// Copyright 2017, University of Freiburg, // Chair of Algorithms and Data Structures. // Author: Patrick Brosi // _____________________________________________________________________________ template class G, typename T> Grid::Grid(bool bldIdx) : _width(0), _height(0), _cellWidth(0), _cellHeight(0), _xWidth(0), _yHeight(0), _hasValIdx(bldIdx) {} // _____________________________________________________________________________ template class G, typename T> Grid::Grid() : Grid(true) {} // _____________________________________________________________________________ template class G, typename T> Grid::Grid(double w, double h, const Box& bbox) : Grid(w, h, bbox, true) {} // _____________________________________________________________________________ template class G, typename T> Grid::Grid(double w, double h, const Box& bbox, bool bValIdx) : _cellWidth(fabs(w)), _cellHeight(fabs(h)), _bb(bbox), _hasValIdx(bValIdx) { _width = bbox.getUpperRight().getX() - bbox.getLowerLeft().getX(); _height = bbox.getUpperRight().getY() - bbox.getLowerLeft().getY(); if (_width < 0 || _height < 0) { _width = 0; _height = 0; _xWidth = 0; _yHeight = 0; return; } _xWidth = ceil(_width / _cellWidth); _yHeight = ceil(_height / _cellHeight); // resize rows _grid.resize(_xWidth); // resize columns for (size_t i = 0; i < _xWidth; i++) { _grid[i].resize(_yHeight); } } // _____________________________________________________________________________ template class G, typename T> void Grid::add(G geom, V val) { Box box = getBoundingBox(geom); size_t swX = getCellXFromX(box.getLowerLeft().getX()); size_t swY = getCellYFromY(box.getLowerLeft().getY()); size_t neX = getCellXFromX(box.getUpperRight().getX()); size_t neY = getCellYFromY(box.getUpperRight().getY()); for (size_t x = swX; x <= neX && x < _grid.size(); x++) { for (size_t y = swY; y <= neY && y < _grid[x].size(); y++) { if (intersects(geom, getBox(x, y))) { add(x, y, val); } } } } // _____________________________________________________________________________ template class G, typename T> void Grid::add(size_t x, size_t y, V val) { _grid[x][y].insert(val); if (_hasValIdx) _index[val].insert(std::pair(x, y)); } // _____________________________________________________________________________ template class G, typename T> void Grid::get(const Box& box, std::set* s) const { size_t swX = getCellXFromX(box.getLowerLeft().getX()); size_t swY = getCellYFromY(box.getLowerLeft().getY()); size_t neX = getCellXFromX(box.getUpperRight().getX()); size_t neY = getCellYFromY(box.getUpperRight().getY()); for (size_t x = swX; x <= neX && x >= 0 && x < _xWidth; x++) for (size_t y = swY; y <= neY && y >= 0 && y < _yHeight; y++) get(x, y, s); } // _____________________________________________________________________________ template class G, typename T> void Grid::get(const G& geom, double d, std::set* s) const { Box a = getBoundingBox(geom); Box b(Point(a.getLowerLeft().getX() - d, a.getLowerLeft().getY() - d), Point(a.getUpperRight().getX() + d, a.getUpperRight().getY() + d)); return get(b, s); } // _____________________________________________________________________________ template class G, typename T> void Grid::get(size_t x, size_t y, std::set* s) const { if (_hasValIdx) { s->insert(_grid[x][y].begin(), _grid[x][y].end()); } else { // if we dont have a value index, we have a set of deleted nodes. // in this case, only insert if not deleted std::copy_if(_grid[x][y].begin(), _grid[x][y].end(), std::inserter(*s, s->end()), [&](const V& v) { return Grid::_removed.count(v) == 0; }); } } // _____________________________________________________________________________ template class G, typename T> void Grid::remove(V val) { if (_hasValIdx) { auto i = _index.find(val); if (i == _index.end()) return; for (auto pair : i->second) { _grid[pair.first][pair.second].erase( _grid[pair.first][pair.second].find(val)); } _index.erase(i); } else { _removed.insert(val); } } // _____________________________________________________________________________ template class G, typename T> void Grid::getNeighbors(const V& val, double d, std::set* s) const { if (!_hasValIdx) throw GridException("No value index build!"); auto it = _index.find(val); if (it == _index.end()) return; size_t xPerm = ceil(d / _cellWidth); size_t yPerm = ceil(d / _cellHeight); for (auto pair : it->second) { getCellNeighbors(pair.first, pair.second, xPerm, yPerm, s); } } // _____________________________________________________________________________ template class G, typename T> void Grid::getCellNeighbors(const V& val, size_t d, std::set* s) const { if (!_hasValIdx) throw GridException("No value index build!"); auto it = _index.find(val); if (it == _index.end()) return; for (auto pair : it->second) { getCellNeighbors(pair.first, pair.second, d, d, s); } } // _____________________________________________________________________________ template class G, typename T> void Grid::getCellNeighbors(size_t cx, size_t cy, size_t xPerm, size_t yPerm, std::set* s) const { size_t swX = xPerm > cx ? 0 : cx - xPerm; size_t swY = yPerm > cy ? 0 : cy - yPerm; size_t neX = xPerm + cx + 1 > _xWidth ? _xWidth : cx + xPerm + 1; size_t neY = yPerm + cy + 1 > _yHeight ? _yHeight : cy + yPerm + 1; for (size_t x = swX; x < neX; x++) { for (size_t y = swY; y < neY; y++) { s->insert(_grid[x][y].begin(), _grid[x][y].end()); } } } // _____________________________________________________________________________ template class G, typename T> std::set > Grid::getCells( const V& val) const { if (!_hasValIdx) throw GridException("No value index build!"); return _index.find(val)->second; } // _____________________________________________________________________________ template class G, typename T> Box Grid::getBox(size_t x, size_t y) const { Point sw(_bb.getLowerLeft().getX() + x * _cellWidth, _bb.getLowerLeft().getY() + y * _cellHeight); Point ne(_bb.getLowerLeft().getX() + (x + 1) * _cellWidth, _bb.getLowerLeft().getY() + (y + 1) * _cellHeight); return Box(sw, ne); } // _____________________________________________________________________________ template class G, typename T> size_t Grid::getCellXFromX(double x) const { float dist = x - _bb.getLowerLeft().getX(); if (dist < 0) dist = 0; return floor(dist / _cellWidth); } // _____________________________________________________________________________ template class G, typename T> size_t Grid::getCellYFromY(double y) const { float dist = y - _bb.getLowerLeft().getY(); if (dist < 0) dist = 0; return floor(dist / _cellHeight); } // _____________________________________________________________________________ template class G, typename T> size_t Grid::getXWidth() const { return _xWidth; } // _____________________________________________________________________________ template class G, typename T> size_t Grid::getYHeight() const { return _yHeight; }