00001 #ifndef _GRID_HPP
00002 #define _GRID_HPP
00003
00004 #include <assert.h>
00005 #include <list>
00006 #include "geometry.hpp"
00007
00008 namespace Arak {
00009
00017 template <class ItemType>
00018 class Grid {
00019
00020 public:
00021
00030 class Cell : public Geometry::Rectangle {
00031
00032 friend class Grid;
00033 friend class Grid::LineCellIterator;
00034 friend class Grid::ConstLineCellIterator;
00035 friend class Grid::RectangleCellIterator;
00036 friend class Grid::ConstRectangleCellIterator;
00037 friend class Grid::TriangleCellIterator;
00038 friend class Grid::ConstTriangleCellIterator;
00039 friend class Grid::ConvexPolygonCellIterator;
00040 friend class Grid::ConstConvexPolygonCellIterator;
00041
00042 public:
00043
00047 typedef std::list<ItemType> ItemList;
00048
00049 protected:
00050
00054 typedef typename ItemList::iterator ItemIterator;
00055
00059 int r;
00060
00064 int c;
00065
00069 ItemList items;
00070
00075 ItemList unused;
00076
00081 Cell* up;
00082
00087 Cell* down;
00088
00093 Cell* right;
00094
00099 Cell* left;
00100
00101 public:
00102
00107 class Entry {
00108
00109 private:
00110
00114 Cell* cell;
00115
00119 ItemIterator it;
00120
00121 public:
00122
00126 Entry() : cell(NULL), it() { }
00127
00131 Entry(Cell* cell, ItemIterator it) : cell(cell), it(it) { }
00132
00136 bool valid() const { return (cell != NULL); }
00137
00143 void remove() {
00144 assert(valid());
00145
00146 cell->unused.splice(cell->unused.begin(), cell->items, it);
00147 cell = NULL;
00148 }
00149
00153 const Cell& getCell() const { return *cell; }
00154
00155 };
00156
00164 Cell(const Geometry::Rectangle& r, int row, int col) :
00165 Geometry::Rectangle(r), r(row), c(col), items(),
00166 up(NULL), down(NULL), right(NULL), left(NULL) { }
00167
00175 inline Entry add(const ItemType& e) {
00176 if (unused.empty()) {
00177
00178 return Entry(this, items.insert(items.begin(), e));
00179 } else {
00180
00181 ItemIterator it = unused.begin();
00182 *it = e;
00183 items.splice(items.begin(), unused, it);
00184 return Entry(this, items.begin());
00185 }
00186 }
00187
00191 inline const ItemList& getItemList() const {
00192 return items;
00193 }
00194
00198 inline ItemList& getItemList() {
00199 return items;
00200 }
00201
00205 int row() const { return r; }
00206
00210 int col() const { return c; }
00211
00215 bool operator==(const Cell& other) const { return (this == &other); }
00216 bool operator!=(const Cell& other) const { return (this != &other); }
00217
00221 Geometry::Point center() const {
00222 return CGAL::midpoint((*this)[0], (*this)[2]);
00223 }
00224
00225 };
00226
00234 template <class GridType, class CellType>
00235 class LineCellIteratorBase {
00236
00237 protected:
00238
00242 Geometry::Line line;
00243
00247 enum CompassDirection {
00248 NORTH,
00249 NORTH_EAST,
00250 EAST,
00251 SOUTH_EAST,
00252 SOUTH,
00253 SOUTH_WEST,
00254 WEST,
00255 NORTH_WEST
00256 };
00257
00261 CompassDirection dir;
00262
00266 CellType* curCell;
00267
00272 CellType* lastCell;
00273
00281 inline CompassDirection direction(const Geometry::Point& p,
00282 const Geometry::Point& q) {
00283 CGAL::Comparison_result xc = CGAL::compare_x(p, q);
00284 CGAL::Comparison_result yc = CGAL::compare_y(p, q);
00285 switch (xc) {
00286 case CGAL::SMALLER:
00287 switch (yc) {
00288 case CGAL::SMALLER:
00289 return NORTH_EAST;
00290 case CGAL::LARGER:
00291 return SOUTH_EAST;
00292 case CGAL::EQUAL:
00293 default:
00294 return EAST;
00295 }
00296 case CGAL::LARGER:
00297 switch (yc) {
00298 case CGAL::SMALLER:
00299 return NORTH_WEST;
00300 case CGAL::LARGER:
00301 return SOUTH_WEST;
00302 case CGAL::EQUAL:
00303 default:
00304 return WEST;
00305 }
00306 case CGAL::EQUAL:
00307 default:
00308 switch (yc) {
00309 case CGAL::SMALLER:
00310 return NORTH;
00311 case CGAL::LARGER:
00312 return SOUTH;
00313 case CGAL::EQUAL:
00314 default:
00315 assert(false);
00316 }
00317 }
00318 }
00319
00320 public:
00321
00326 struct SEGMENT { };
00327
00332 struct RAY { };
00333
00343 LineCellIteratorBase(GridType& g,
00344 const Geometry::Point &p,
00345 const Geometry::Point &q,
00346 SEGMENT) : line(p, q) {
00347 dir = direction(p, q);
00348 if (g.boundary().has_on_unbounded_side(p) ||
00349 g.boundary().has_on_unbounded_side(q)) {
00350 Geometry::Segment s(p, q);
00351 Geometry::Point r;
00352 CGAL::Object intersection = CGAL::intersection(s, g.boundary());
00353 if (CGAL::assign(s, intersection)) {
00354 curCell = &g.getCell(Geometry::project(s.source(), g.boundary()));
00355 lastCell = &g.getCell(Geometry::project(s.target(), g.boundary()));
00356 } else if (CGAL::assign(r, intersection)) {
00357 curCell = lastCell = &g.getCell(Geometry::project(r, g.boundary()));
00358 } else {
00359 curCell = lastCell = NULL;
00360 }
00361 } else {
00362 curCell = &g.getCell(p);
00363 lastCell = &g.getCell(q);
00364 }
00365 }
00366
00375 LineCellIteratorBase(GridType& g,
00376 const Geometry::Point &p,
00377 const Geometry::Point &q,
00378 RAY) : line(p, q) {
00379 dir = direction(p, q);
00380 if (g.boundary().has_on_unbounded_side(p) ||
00381 g.boundary().has_on_unbounded_side(q)) {
00382 Geometry::Segment s(p, q);
00383 Geometry::Point r;
00384 CGAL::Object intersection = CGAL::intersection(s, g.boundary());
00385 if (CGAL::assign(s, intersection)) {
00386 curCell = &g.getCell(Geometry::project(s.source(), g.boundary()));
00387 lastCell = &g.getCell(Geometry::project(s.target(), g.boundary()));
00388 } else if (CGAL::assign(r, intersection)) {
00389 curCell = lastCell = &g.getCell(Geometry::project(r, g.boundary()));
00390 } else {
00391 curCell = lastCell = NULL;
00392 }
00393 } else {
00394 curCell = &g.getCell(p);
00395 lastCell = NULL;
00396 }
00397 }
00398
00402 LineCellIteratorBase()
00403 : line(1, 0, 0),
00404 curCell(NULL),
00405 lastCell(NULL) { }
00406
00410 inline bool
00411 operator==(const LineCellIteratorBase<GridType,CellType>& other) const
00412 { return (curCell == other.curCell); }
00413 inline bool
00414 operator!=(const LineCellIteratorBase<GridType,CellType>& other) const
00415 { return !(*this == other); }
00416
00420 inline LineCellIteratorBase<GridType,CellType>& operator++(int) {
00421 LineCellIteratorBase<GridType,CellType> tmp(*this);
00422 ++(*this);
00423 return tmp;
00424 }
00425 inline LineCellIteratorBase<GridType,CellType>& operator++() {
00426 using namespace Arak::Geometry;
00427 assert(curCell != NULL);
00428 if (curCell == lastCell) {
00429 curCell = NULL;
00430 return *this;
00431 }
00432 switch (dir) {
00433 case NORTH_EAST:
00434 switch (CGAL::compare_y_at_x(curCell->vertex(2), line)) {
00435 case CGAL::SMALLER:
00436 curCell = curCell->up; break;
00437 case CGAL::LARGER:
00438 curCell = curCell->right; break;
00439 case CGAL::EQUAL:
00440 curCell = curCell->right;
00441 if (curCell != NULL)
00442 curCell = curCell->up;
00443 break;
00444 }
00445 break;
00446 case SOUTH_EAST:
00447 switch (CGAL::compare_y_at_x(curCell->vertex(1), line)) {
00448 case CGAL::LARGER:
00449 curCell = curCell->down; break;
00450 case CGAL::SMALLER:
00451 curCell = curCell->right; break;
00452 case CGAL::EQUAL:
00453 curCell = curCell->right;
00454 if (curCell != NULL)
00455 curCell = curCell->down;
00456 break;
00457 }
00458 break;
00459 case SOUTH_WEST:
00460 switch (CGAL::compare_y_at_x(curCell->vertex(0), line)) {
00461 case CGAL::LARGER:
00462 curCell = curCell->down; break;
00463 case CGAL::SMALLER:
00464 curCell = curCell->left; break;
00465 case CGAL::EQUAL:
00466 curCell = curCell->left;
00467 if (curCell != NULL)
00468 curCell = curCell->down;
00469 break;
00470 }
00471 break;
00472 case NORTH_WEST:
00473 switch (CGAL::compare_y_at_x(curCell->vertex(3), line)) {
00474 case CGAL::SMALLER:
00475 curCell = curCell->up; break;
00476 case CGAL::LARGER:
00477 curCell = curCell->left; break;
00478 case CGAL::EQUAL:
00479 curCell = curCell->left;
00480 if (curCell != NULL)
00481 curCell = curCell->up;
00482 break;
00483 }
00484 break;
00485 case NORTH:
00486 curCell = curCell->up;
00487 break;
00488 case SOUTH:
00489 curCell = curCell->down;
00490 break;
00491 case EAST:
00492 curCell = curCell->right;
00493 break;
00494 case WEST:
00495 curCell = curCell->left;
00496 break;
00497 }
00498 return *this;
00499 }
00500
00504 inline CellType* operator->() const {return curCell;}
00505 inline CellType& operator*() const { return *curCell;}
00506
00507 };
00508
00513 typedef LineCellIteratorBase<Grid, Cell> LineCellIterator;
00514
00519 typedef LineCellIteratorBase<const Grid, const Cell> ConstLineCellIterator;
00520
00525 template <class GridType, class CellType>
00526 class RectangleCellIteratorBase {
00527
00528 protected:
00529
00533 int i;
00534
00538 int imax;
00539
00543 int j;
00544
00548 int jmin;
00549
00553 int jmax;
00554
00558 CellType* curCell;
00559
00563 GridType* grid;
00564
00565 public:
00566
00574 RectangleCellIteratorBase(GridType& g, Geometry::Rectangle r)
00575 : curCell(NULL), grid(&g) {
00576 if (CGAL::assign(r, CGAL::intersection(g.boundary(), r))) {
00577 assert(g.getCellCoords(r.min(), i, jmin));
00578 j = jmin;
00579 assert(g.getCellCoords(r.max(), imax, jmax));
00580 curCell = &g.getCell(i, j);
00581 } else {
00582 curCell = NULL;
00583 }
00584 }
00585
00589 RectangleCellIteratorBase() : curCell(NULL), grid(NULL) { }
00590
00594 inline bool operator==(const RectangleCellIteratorBase<GridType,CellType>& other) const
00595 { return (curCell == other.curCell); }
00596 inline bool operator!=(const RectangleCellIteratorBase<GridType,CellType>& other) const
00597 { return !(*this == other); }
00598
00602 inline RectangleCellIteratorBase<GridType,CellType>& operator++(int) {
00603 RectangleCellIteratorBase<GridType,CellType> tmp(*this);
00604 ++(*this);
00605 return tmp;
00606 }
00607 inline RectangleCellIteratorBase<GridType,CellType>& operator++() {
00608 using namespace Arak::Geometry;
00609 assert(curCell != NULL);
00610 if ((i == imax) && (j == jmax)) {
00611 curCell = NULL;
00612 return *this;
00613 } else if (j == jmax) {
00614 i++;
00615 j = jmin;
00616 curCell = &(grid->getCell(i, j));
00617 } else {
00618 j++;
00619 curCell = curCell->right;
00620 }
00621 return *this;
00622 }
00623
00627 inline CellType* operator->() const { return curCell; }
00628 inline CellType& operator*() const { return *curCell; }
00629
00630 };
00631
00636 typedef RectangleCellIteratorBase<Grid, Cell>
00637 RectangleCellIterator;
00638
00643 typedef RectangleCellIteratorBase<const Grid, const Cell>
00644 ConstRectangleCellIterator;
00645
00650 template <class GridType, class CellType>
00651 class TriangleCellIteratorBase {
00652
00653 protected:
00654
00658 CellType* curCell;
00659
00663 GridType* grid;
00664
00668 int imin;
00669
00673 int imax;
00674
00680 std::vector<int> jmins;
00681
00687 std::vector<int> jmaxs;
00688
00689 public:
00690
00698 TriangleCellIteratorBase(GridType& g, Geometry::Triangle t)
00699 : curCell(NULL), grid(&g) {
00700
00701
00702 Geometry::Rectangle r = Geometry::boundingRectangle(t[0], t[1], t[2]);
00703 if (!CGAL::assign(r, CGAL::intersection(g.boundary(), r))) {
00704
00705 curCell = NULL;
00706 return;
00707 }
00708
00709 int jmin, jmax;
00710 assert(g.getCellCoords(r.min(), imin, jmin));
00711 assert(g.getCellCoords(r.max(), imax, jmax));
00712 assert(imin <= imax);
00713 assert(jmin <= jmax);
00714
00715
00716 jmins.insert(jmins.end(), imax - imin + 1,
00717 std::numeric_limits<int>::max());
00718 jmaxs.insert(jmaxs.end(), imax - imin + 1,
00719 std::numeric_limits<int>::min());
00720 for (int v = 0; v < 3; v++) {
00721 ConstLineCellIterator it(g, t[v], t[v + 1],
00722 ConstLineCellIterator::SEGMENT()), end;
00723 while (it != end) {
00724 const Cell& cell = *it;
00725 int i = cell.row();
00726 int j = cell.col();
00727 int k = i - imin;
00728 jmins[k] = std::min<int>(jmins[k], j);
00729 jmaxs[k] = std::max<int>(jmaxs[k], j);
00730 ++it;
00731 }
00732 }
00733
00734 std::replace(jmins.begin(), jmins.end(),
00735 std::numeric_limits<int>::max(), jmin);
00736 std::replace(jmaxs.begin(), jmaxs.end(),
00737 std::numeric_limits<int>::min(), jmax);
00738
00739 curCell = &g.getCell(imin, jmins[0]);
00740 }
00741
00745 TriangleCellIteratorBase() : curCell(NULL), grid(NULL) { }
00746
00750 inline bool operator==(const TriangleCellIteratorBase<GridType,CellType>& other) const
00751 { return (curCell == other.curCell); }
00752 inline bool operator!=(const TriangleCellIteratorBase<GridType,CellType>& other) const
00753 { return !(*this == other); }
00754
00758 inline TriangleCellIteratorBase<GridType,CellType>& operator++(int) {
00759 TriangleCellIterator tmp(*this);
00760 ++(*this);
00761 return tmp;
00762 }
00763 inline TriangleCellIteratorBase<GridType,CellType>& operator++() {
00764 using namespace Arak::Geometry;
00765 assert(curCell != NULL);
00766 int i = curCell->row();
00767 int j = curCell->col();
00768 int k = i - imin;
00769 if ((i == imax) && (j == jmaxs[k])) {
00770
00771 curCell = NULL;
00772 return *this;
00773 } else if (j == jmaxs[k])
00774
00775
00776 curCell = &(grid->getCell(i + 1, jmins[k + 1]));
00777 else
00778
00779
00780 curCell = curCell->right;
00781 return *this;
00782 }
00783
00787 inline CellType* operator->() const { return curCell; }
00788 inline CellType& operator*() const { return *curCell; }
00789
00790 };
00791
00796 typedef TriangleCellIteratorBase<Grid, Cell>
00797 TriangleCellIterator;
00798
00803 typedef TriangleCellIteratorBase<const Grid, const Cell>
00804 ConstTriangleCellIterator;
00805
00810 template <class GridType, class CellType>
00811 class ConvexPolygonCellIteratorBase {
00812
00813 protected:
00814
00818 CellType* curCell;
00819
00823 GridType* grid;
00824
00829 int imin;
00830
00835 int imax;
00836
00842 std::vector<int> jmins;
00843
00849 std::vector<int> jmaxs;
00850
00851 public:
00852
00860 ConvexPolygonCellIteratorBase(GridType& g, const Geometry::Polygon& p)
00861 : curCell(NULL), grid(&g) {
00862
00863
00864 Geometry::Rectangle r(*(p.left_vertex()),
00865 *(p.right_vertex()),
00866 *(p.bottom_vertex()),
00867 *(p.top_vertex()));
00868 if (!CGAL::assign(r, CGAL::intersection(g.boundary(), r))) {
00869
00870 curCell = NULL;
00871 return;
00872 }
00873
00874 int jmin, jmax;
00875 assert(g.getCellCoords(r.min(), imin, jmin));
00876 assert(g.getCellCoords(r.max(), imax, jmax));
00877 assert(imin <= imax);
00878 assert(jmin <= jmax);
00879
00880
00881 jmins.insert(jmins.end(), imax - imin + 1,
00882 std::numeric_limits<int>::max());
00883 jmaxs.insert(jmaxs.end(), imax - imin + 1,
00884 std::numeric_limits<int>::min());
00885 const int size = p.size();
00886 for (int v = 0; v < size; v++) {
00887 ConstLineCellIterator it(g, p[v], p[(v + 1) % size],
00888 ConstLineCellIterator::SEGMENT()), end;
00889 while (it != end) {
00890 const Cell& cell = *it;
00891 int i = cell.row();
00892 int j = cell.col();
00893 int k = i - imin;
00894 jmins[k] = std::min<int>(jmins[k], j);
00895 jmaxs[k] = std::max<int>(jmaxs[k], j);
00896 ++it;
00897 }
00898 }
00899
00900 std::replace(jmins.begin(), jmins.end(),
00901 std::numeric_limits<int>::max(), jmin);
00902 std::replace(jmaxs.begin(), jmaxs.end(),
00903 std::numeric_limits<int>::min(), jmax);
00904
00905 curCell = &g.getCell(imin, jmins[0]);
00906 }
00907
00911 ConvexPolygonCellIteratorBase() : curCell(NULL), grid(NULL) { }
00912
00916 inline bool operator==(const ConvexPolygonCellIteratorBase<GridType,CellType>& other) const
00917 { return (curCell == other.curCell); }
00918 inline bool operator!=(const ConvexPolygonCellIteratorBase<GridType,CellType>& other) const
00919 { return !(*this == other); }
00920
00924 inline ConvexPolygonCellIteratorBase<GridType,CellType>& operator++(int) {
00925 ConvexPolygonCellIterator tmp(*this);
00926 ++(*this);
00927 return tmp;
00928 }
00929 inline ConvexPolygonCellIteratorBase<GridType,CellType>& operator++() {
00930 using namespace Arak::Geometry;
00931 assert(curCell != NULL);
00932 int i = curCell->row();
00933 int j = curCell->col();
00934 int k = i - imin;
00935 if ((i == imax) && (j == jmaxs[k])) {
00936
00937 curCell = NULL;
00938 return *this;
00939 } else if (j == jmaxs[k])
00940
00941
00942 curCell = &(grid->getCell(i + 1, jmins[k + 1]));
00943 else
00944
00945
00946 curCell = curCell->right;
00947 return *this;
00948 }
00949
00953 inline CellType* operator->() const { return curCell; }
00954 inline CellType& operator*() const { return *curCell; }
00955
00956 };
00957
00962 typedef ConvexPolygonCellIteratorBase<Grid, Cell>
00963 ConvexPolygonCellIterator;
00964
00969 typedef ConvexPolygonCellIteratorBase<const Grid, const Cell>
00970 ConstConvexPolygonCellIterator;
00971
00972 protected:
00973
00977 const Geometry::Rectangle bd;
00978
00982 std::vector< std::vector<Cell*> > cells;
00983
00987 const int rows;
00988
00992 const int cols;
00993
00997 Geometry::Kernel::FT cellWidth;
00998
01002 Geometry::Kernel::FT cellHeight;
01003
01012 std::vector<Geometry::Kernel::FT> xvals;
01013
01022 std::vector<Geometry::Kernel::FT> yvals;
01023
01024 public:
01025
01034 Grid(const Geometry::Rectangle& boundary, int rows, int cols)
01035 : bd(boundary), rows(rows), cols(cols) {
01036 using namespace Arak::Geometry;
01037
01038 Kernel::FT xmin = bd.xmin();
01039 Kernel::FT xmax = bd.xmax();
01040 Kernel::FT ymin = bd.ymin();
01041 Kernel::FT ymax = bd.ymax();
01042 this->cellWidth = (xmax - xmin) / Kernel::FT(cols);
01043 this->cellHeight = (ymax - ymin) / Kernel::FT(rows);
01044
01045 xvals.reserve(cols + 1);
01046 Kernel::FT x = xmin;
01047 for (int i = 0; i < cols; i++) {
01048 xvals.push_back(x);
01049 x += cellWidth;
01050 }
01051 xvals.push_back(xmax);
01052 yvals.reserve(rows + 1);
01053 Kernel::FT y = ymin;
01054 for (int i = 0; i < rows; i++) {
01055 yvals.push_back(y);
01056 y += cellHeight;
01057 }
01058 yvals.push_back(ymax);
01059
01060 cells.reserve(rows);
01061 for (int i = 0; i < rows; i++) {
01062 cells.push_back(std::vector<Cell*>());
01063 cells[i].reserve(cols);
01064 for (int j = 0; j < cols; j++) {
01065 Geometry::Rectangle r(xvals[j], yvals[i],
01066 xvals[j + 1], yvals[i + 1]);
01067 cells[i][j] = new Cell(r, i, j);
01068 if (i > 0) {
01069 cells[i][j]->down = cells[i - 1][j];
01070 cells[i - 1][j]->up = cells[i][j];
01071 }
01072 if (j > 0) {
01073 cells[i][j]->left = cells[i][j - 1];
01074 cells[i][j - 1]->right = cells[i][j];
01075 }
01076 }
01077 }
01078 }
01079
01083 ~Grid() {
01084
01085 }
01086
01092 inline int numRows() const { return rows; }
01093
01099 inline int numCols() const { return cols; }
01100
01108 const Geometry::Rectangle& boundary() const { return bd; }
01109
01119 bool getCellCoords(const Geometry::Point& p, int& i, int& j) const {
01120 if (bd.has_on_unbounded_side(p)) return false;
01121
01122
01123
01124
01125 if (p.y() == bd.ymax())
01126 i = rows - 1;
01127 else {
01128 i = int(floor(CGAL::to_double((p.y() - bd.ymin()) / cellHeight)));
01129 while (p.y() < yvals[i]) i--;
01130 while (p.y() >= yvals[i + 1]) i++;
01131 }
01132 if (p.x() == bd.xmax())
01133 j = cols - 1;
01134 else {
01135 j = int(floor(CGAL::to_double((p.x() - bd.xmin()) / cellWidth)));
01136 while (p.x() < xvals[j]) j--;
01137 while (p.x() >= xvals[j + 1]) j++;
01138 }
01139 return true;
01140 }
01141
01149 inline const Cell& getCell(const int i, const int j) const {
01150 return *(cells[i][j]);
01151 }
01152
01160 inline Cell& getCell(const int i, const int j) {
01161 return *(cells[i][j]);
01162 }
01163
01168 const Cell& getCell(const Geometry::Point& p) const {
01169 int i = -1, j = -1;
01170 assert(getCellCoords(p, i, j));
01171 return getCell(i, j);
01172 }
01173
01178 Cell& getCell(const Geometry::Point& p) {
01179 int i = -1, j = -1;
01180 assert(getCellCoords(p, i, j));
01181 return *(cells[i][j]);
01182 }
01183
01184 };
01185
01186 }
01187
01188 #endif