generate-shapes/src/util/geo/Grid.tpp
2023-10-06 12:14:03 +02:00

246 lines
8.9 KiB
C++

// Copyright 2017, University of Freiburg,
// Chair of Algorithms and Data Structures.
// Author: Patrick Brosi <brosip@informatik.uni-freiburg.de>
// _____________________________________________________________________________
template <typename V, template <typename> class G, typename T>
Grid<V, G, T>::Grid(bool bldIdx)
: _width(0),
_height(0),
_cellWidth(0),
_cellHeight(0),
_xWidth(0),
_yHeight(0),
_hasValIdx(bldIdx),
_grid(0) {}
// _____________________________________________________________________________
template <typename V, template <typename> class G, typename T>
Grid<V, G, T>::Grid() : Grid<V, G, T>(true) {}
// _____________________________________________________________________________
template <typename V, template <typename> class G, typename T>
Grid<V, G, T>::Grid(double w, double h, const Box<T>& bbox)
: Grid<V, G, T>(w, h, bbox, true) {}
// _____________________________________________________________________________
template <typename V, template <typename> class G, typename T>
Grid<V, G, T>::Grid(double w, double h, const Box<T>& bbox, bool bValIdx)
: _cellWidth(fabs(w)),
_cellHeight(fabs(h)),
_bb(bbox),
_hasValIdx(bValIdx),
_grid(0) {
_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 = new std::set<V>*[_xWidth];
// resize columns
for (size_t x = 0; x < _xWidth; x++) {
_grid[x] = new std::set<V>[_yHeight];
}
}
// _____________________________________________________________________________
template <typename V, template <typename> class G, typename T>
void Grid<V, G, T>::add(G<T> geom, V val) {
Box<T> 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 < _xWidth; x++) {
for (size_t y = swY; y <= neY && y < _yHeight; y++) {
if (intersects(geom, getBox(x, y))) {
add(x, y, val);
}
}
}
}
// _____________________________________________________________________________
template <typename V, template <typename> class G, typename T>
void Grid<V, G, T>::add(size_t x, size_t y, V val) {
_grid[x][y].insert(val);
if (_hasValIdx) _index[val].insert(std::pair<size_t, size_t>(x, y));
}
// _____________________________________________________________________________
template <typename V, template <typename> class G, typename T>
void Grid<V, G, T>::get(const Box<T>& box, std::set<V>* 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 < _xWidth; x++)
for (size_t y = swY; y <= neY && y < _yHeight; y++) get(x, y, s);
}
// _____________________________________________________________________________
template <typename V, template <typename> class G, typename T>
template <template <typename> class GG>
void Grid<V, G, T>::get(const GG<T>& geom, double d, std::set<V>* s) const {
Box<T> a = getBoundingBox(geom);
Box<T> b(
Point<T>(a.getLowerLeft().getX() - d, a.getLowerLeft().getY() - d),
Point<T>(a.getUpperRight().getX() + d, a.getUpperRight().getY() + d));
return get(b, s);
}
// _____________________________________________________________________________
template <typename V, template <typename> class G, typename T>
template <template <typename> class GG>
void Grid<V, G, T>::get(const std::vector<GG<T>>& geom, double d,
std::set<V>* s) const {
Box<T> a = getBoundingBox(geom);
Box<T> b(
Point<T>(a.getLowerLeft().getX() - d, a.getLowerLeft().getY() - d),
Point<T>(a.getUpperRight().getX() + d, a.getUpperRight().getY() + d));
return get(b, s);
}
// _____________________________________________________________________________
template <typename V, template <typename> class G, typename T>
void Grid<V, G, T>::get(size_t x, size_t y, std::set<V>* s) const {
if (_hasValIdx || _removed.size() == 0) {
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<V, G, T>::_removed.count(v) == 0; });
}
}
// _____________________________________________________________________________
template <typename V, template <typename> class G, typename T>
const std::set<V>& Grid<V, G, T>::getCell(size_t x, size_t y) const {
return _grid[x][y];
}
// _____________________________________________________________________________
template <typename V, template <typename> class G, typename T>
void Grid<V, G, T>::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 <typename V, template <typename> class G, typename T>
void Grid<V, G, T>::getNeighbors(const V& val, double d, std::set<V>* 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 <typename V, template <typename> class G, typename T>
void Grid<V, G, T>::getCellNeighbors(const V& val, size_t d,
std::set<V>* 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 <typename V, template <typename> class G, typename T>
void Grid<V, G, T>::getCellNeighbors(size_t cx, size_t cy, size_t xPerm,
size_t yPerm, std::set<V>* 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 <typename V, template <typename> class G, typename T>
std::set<std::pair<size_t, size_t>> Grid<V, G, T>::getCells(
const V& val) const {
if (!_hasValIdx) throw GridException("No value index build!");
return _index.find(val)->second;
}
// _____________________________________________________________________________
template <typename V, template <typename> class G, typename T>
Box<T> Grid<V, G, T>::getBox(size_t x, size_t y) const {
Point<T> sw(_bb.getLowerLeft().getX() + x * _cellWidth,
_bb.getLowerLeft().getY() + y * _cellHeight);
Point<T> ne(_bb.getLowerLeft().getX() + (x + 1) * _cellWidth,
_bb.getLowerLeft().getY() + (y + 1) * _cellHeight);
return Box<T>(sw, ne);
}
// _____________________________________________________________________________
template <typename V, template <typename> class G, typename T>
size_t Grid<V, G, T>::getCellXFromX(double x) const {
float dist = x - _bb.getLowerLeft().getX();
if (dist < 0) dist = 0;
return floor(dist / _cellWidth);
}
// _____________________________________________________________________________
template <typename V, template <typename> class G, typename T>
size_t Grid<V, G, T>::getCellYFromY(double y) const {
float dist = y - _bb.getLowerLeft().getY();
if (dist < 0) dist = 0;
return floor(dist / _cellHeight);
}
// _____________________________________________________________________________
template <typename V, template <typename> class G, typename T>
size_t Grid<V, G, T>::getXWidth() const {
return _xWidth;
}
// _____________________________________________________________________________
template <typename V, template <typename> class G, typename T>
size_t Grid<V, G, T>::getYHeight() const {
return _yHeight;
}