Skip to content
Snippets Groups Projects
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>;