-
W. Spencer Smith authoredW. Spencer Smith authored
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
Seq2D.cpp 4.02 KiB
#include "Seq2D.h"
#include "PointADT.h"
#include "LineADT.h"
#include "PathADT.h"
#include "MapTypes.h"
#include "Exceptions.h"
#include <vector>
#include <queue>
#include <unordered_set>
using std::vector;
using std::queue;
using std::unordered_set;
template <class T>
Seq2D<T>::Seq2D(vector<vector<T>> s, double scale)
{
if(scale <= 0) throw invalid_argument();
if(s.empty()) throw invalid_argument();
if(s[0].empty()) throw invalid_argument();
for(auto row : s)
if( row.size() != s[0].size() )
throw invalid_argument();
this->s = s;
this->scale = scale;
this->nRow = s.size();
this->nCol = s[0].size();
}
template <class T>
void Seq2D<T>::set(PointT p, T v)
{
if(!(validPoint(p)))
throw outside_bounds();
s[p.y()][p.x()] = v;
}
template <class T>
T Seq2D<T>::get(PointT p) const
{
if(!(validPoint(p)))
throw outside_bounds();
return s[p.y()][p.x()];
}
template <class T>
nat Seq2D<T>::getNumRow() const
{
return nRow;
}
template <class T>
nat Seq2D<T>::getNumCol() const
{
return nCol;
}
template <class T>
double Seq2D<T>::getScale() const
{
return scale;
}
template <class T>
nat Seq2D<T>::count(T t) const
{
nat cnt = 0;
for(auto row : s)
for(auto element : row)
if(element == t)
++cnt;
return cnt;
}
template <class T>
nat Seq2D<T>::count(LineT l, T t) const
{
if(!validLine(l))
throw invalid_argument();
nat cnt = 0;
for(auto pt : pointsInLine(l))
if(get(pt) == t)
++cnt;
return cnt;
}
template <class T>
nat Seq2D<T>::count(PathT pth, T t) const
{
if(!validPath(pth))
throw invalid_argument();
nat cnt = 0;
for(auto pt : pointsInPath(pth))
if(get(pt) == t)
++cnt;
return cnt;
}
template <class T>
double Seq2D<T>::length(PathT pth) const
{
if(!validPath(pth))
throw invalid_argument();
return pth.len() * scale;
}
template <class T>
bool Seq2D<T>::connected(PointT p1, PointT p2) const
{
if(!validPoint(p1) || !validPoint(p2))
throw invalid_argument();
T t = get(p1);
if(get(p2) != t)
return false;
// use BFS
queue<PointT> q;
unordered_set<PointT> marked;
q.push(p1);
marked.insert(p1);
while(!q.empty()){
PointT p = q.front();
q.pop();
// get adjacent points
unordered_set<PointT> adj =
{ p.translate(0,1),
p.translate(0,-1),
p.translate(1,0),
p.translate(-1,0) };
for(auto pAdj : adj){
if(pAdj == p2) return true;
if(validPoint(pAdj) && marked.find(pAdj) == marked.end())
if(get(pAdj) == t){
q.push(pAdj);
marked.insert(pAdj);
}
}
}
return false;
}
// private methods
template <class T>
bool Seq2D<T>::validRow(nat i) const
{
return i <= (nRow - 1);
}
template <class T>
bool Seq2D<T>::validCol(nat j) const
{
return j <= (nCol - 1);
}
template <class T>
bool Seq2D<T>::validPoint(PointT p) const
{
return validRow(p.x()) && validCol(p.y());
}
template <class T>
bool Seq2D<T>::validLine(LineT l) const
{
return validPoint(l.strt()) && validPoint(l.end());
}
template <class T>
bool Seq2D<T>::validPath(PathT pth) const
{
for(nat i = 0; i < pth.size(); ++i)
if(!validLine(pth.line(i)))
return false;
return true;
}
template <class T>
vector<PointT> Seq2D<T>::pointsInLine(LineT ln) const
{
vector<PointT> pts;
int xFactor = 0;
int yFactor = 0;
switch(ln.orient()){
case N:
yFactor = 1;
break;
case S:
yFactor = -1;
break;
case E:
xFactor = 1;
break;
case W:
xFactor = -1;
break;
}
for(nat i = 0; i < ln.len(); ++i)
pts.push_back(ln.strt().translate(i*xFactor, i*yFactor));
return pts;
}
template <class T>
vector<PointT> Seq2D<T>::pointsInPath(PathT pth) const
{
vector<PointT> pts;
for(nat i = 0; i < pth.size(); ++i)
for(auto pt : pointsInLine(pth.line(i)))
pts.push_back(pt);
return pts;
}
// explicit instantiations of Seq2D
template class Seq2D<LanduseT>;
template class Seq2D<int>;