OGS
QuadTree.h
Go to the documentation of this file.
1// SPDX-FileCopyrightText: Copyright (c) OpenGeoSys Community (opengeosys.org)
2// SPDX-License-Identifier: BSD-3-Clause
3
4#pragma once
5
6#include <algorithm>
7#include <cassert>
8#include <limits>
9#include <list>
10#include <utility>
11
12#include "BaseLib/Logging.h"
13
14namespace GeoLib
15{
27template <typename POINT>
29{
30public:
31 enum class Quadrant
32 {
33 NE = 0,
37 };
38
45 QuadTree(POINT ll, POINT ur, std::size_t max_points_per_leaf)
46 : _father(nullptr),
47 _ll(std::move(ll)),
48 _ur(std::move(ur)),
49 _max_points_per_leaf(max_points_per_leaf)
50 {
51 assert(_max_points_per_leaf > 0);
52
53 if ((_ur[0] - _ll[0]) > (_ur[1] - _ll[1]))
54 {
55 _ur[1] = _ll[1] + _ur[0] - _ll[0];
56 }
57 else
58 {
59 _ur[0] = _ll[0] + _ur[1] - _ll[1];
60 }
61
62 DBUG(
63 "QuadTree(): lower left: ({:f},{:f},{:f}), upper right: "
64 "({:f},{:f},{:f}), depth: {:d}",
65 _ll[0],
66 _ll[1],
67 _ll[2],
68 _ur[0],
69 _ur[1],
70 _ur[2],
71 _depth);
72 }
73
78 {
79 for (auto const& child : _children)
80 {
81 delete child;
82 }
83 }
84
91 bool addPoint(POINT const* pnt)
92 {
93 if ((*pnt)[0] < _ll[0])
94 {
95 return false;
96 }
97 if ((*pnt)[0] >= _ur[0])
98 {
99 return false;
100 }
101 if ((*pnt)[1] < _ll[1])
102 {
103 return false;
104 }
105 if ((*pnt)[1] >= _ur[1])
106 {
107 return false;
108 }
109
110 if (!_is_leaf)
111 {
112 return std::any_of(begin(_children), end(_children),
113 [&pnt](auto* child)
114 { return child->addPoint(pnt); });
115 }
116
117 // check if point is already in quadtree
118 bool pnt_in_quadtree(false);
119 for (std::size_t k(0); k < _pnts.size() && !pnt_in_quadtree; k++)
120 {
121 const double v0((*(_pnts[k]))[0] - (*pnt)[0]);
122 const double v1((*(_pnts[k]))[1] - (*pnt)[1]);
123 const double sqr_dist(v0 * v0 + v1 * v1);
124 if (sqr_dist < std::numeric_limits<double>::epsilon())
125 {
126 pnt_in_quadtree = true;
127 }
128 }
129 if (!pnt_in_quadtree)
130 {
131 _pnts.push_back(pnt);
132 }
133 else
134 {
135 return false;
136 }
137
138 if (_pnts.size() > _max_points_per_leaf)
139 {
140 splitNode();
141 }
142 return true;
143 }
144
152 void balance()
153 {
154 std::list<QuadTree<POINT>*> leaf_list;
155 getLeafs(leaf_list);
156
157 while (!leaf_list.empty())
158 {
159 QuadTree<POINT>* node(leaf_list.front());
160 leaf_list.pop_front();
161
162 if (node->isLeaf())
163 {
164 if (needToRefine(node))
165 {
166 node->splitNode();
167 leaf_list.push_back(node->getChild(Quadrant::NE));
168 leaf_list.push_back(node->getChild(Quadrant::NW));
169 leaf_list.push_back(node->getChild(Quadrant::SW));
170 leaf_list.push_back(node->getChild(Quadrant::SE));
171
172 // check if north neighbor has to be refined
173 QuadTree<POINT>* north_neighbor(node->getNorthNeighbor());
174 if (north_neighbor != nullptr)
175 {
176 if (north_neighbor->getDepth() < node->getDepth())
177 {
178 if (north_neighbor->isLeaf())
179 {
180 leaf_list.push_back(north_neighbor);
181 }
182 }
183 }
184
185 // check if west neighbor has to be refined
186 QuadTree<POINT>* west_neighbor(node->getWestNeighbor());
187 if (west_neighbor != nullptr)
188 {
189 if (west_neighbor->getDepth() < node->getDepth())
190 {
191 if (west_neighbor->isLeaf())
192 {
193 leaf_list.push_back(west_neighbor);
194 }
195 }
196 }
197
198 // check if south neighbor has to be refined
199 QuadTree<POINT>* south_neighbor(node->getSouthNeighbor());
200 if (south_neighbor != nullptr)
201 {
202 if (south_neighbor->getDepth() < node->getDepth())
203 {
204 if (south_neighbor->isLeaf())
205 {
206 leaf_list.push_back(south_neighbor);
207 }
208 }
209 }
210
211 // check if east neighbor has to be refined
212 QuadTree<POINT>* east_neighbor(node->getEastNeighbor());
213 if (east_neighbor != nullptr)
214 {
215 if (east_neighbor->getDepth() < node->getDepth())
216 {
217 if (east_neighbor->isLeaf())
218 {
219 leaf_list.push_back(east_neighbor);
220 }
221 }
222 }
223 }
224 }
225 }
226 }
227
232 void getLeafs(std::list<QuadTree<POINT>*>& leaf_list)
233 {
234 if (_is_leaf)
235 {
236 leaf_list.push_back(this);
237 }
238 else
239 {
240 for (auto& child : _children)
241 {
242 child->getLeafs(leaf_list);
243 }
244 }
245 }
246
247 const std::vector<POINT const*>& getPoints() const { return _pnts; }
248
249 void getSquarePoints(POINT& ll, POINT& ur) const
250 {
251 ll = _ll;
252 ur = _ur;
253 }
254
255 void getLeaf(const POINT& pnt, POINT& ll, POINT& ur)
256 {
257 if (this->isLeaf())
258 {
259 ll = _ll;
260 ur = _ur;
261 }
262 else
263 {
264 if (pnt[0] <= 0.5 * (_ur[0] + _ll[0])) // WEST
265 {
266 if (pnt[1] <= 0.5 * (_ur[1] + _ll[1]))
267 { // SOUTH
268 _children[static_cast<int>(Quadrant::SW)]->getLeaf(pnt, ll,
269 ur);
270 }
271 else
272 { // NORTH
273 _children[static_cast<int>(Quadrant::NW)]->getLeaf(pnt, ll,
274 ur);
275 }
276 }
277 else // EAST
278 {
279 if (pnt[1] <= 0.5 * (_ur[1] + _ll[1]))
280 { // SOUTH
281 _children[static_cast<int>(Quadrant::SE)]->getLeaf(pnt, ll,
282 ur);
283 }
284 else
285 { // NORTH
286 _children[static_cast<int>(Quadrant::NE)]->getLeaf(pnt, ll,
287 ur);
288 }
289 }
290 }
291 }
292
293 QuadTree<POINT> const* getFather() const { return _father; }
294
295 QuadTree<POINT> const* getChild(Quadrant quadrant) const
296 {
297 return _children[quadrant];
298 }
299
306 void getMaxDepth(std::size_t& max_depth) const
307 {
308 if (max_depth < _depth)
309 {
310 max_depth = _depth;
311 }
312
313 for (auto& child : _children)
314 {
315 if (child)
316 {
317 child->getMaxDepth(max_depth);
318 }
319 }
320 }
321
326 std::size_t getDepth() const { return _depth; }
327
328private:
330 {
331 return _children[static_cast<int>(quadrant)];
332 }
333
334 bool isLeaf() const { return _is_leaf; }
335
336 bool isChild(QuadTree<POINT> const* const tree, Quadrant quadrant) const
337 {
338 return _children[static_cast<int>(quadrant)] == tree;
339 }
340
342 {
343 if (this->_father == nullptr)
344 { // root of QuadTree
345 return nullptr;
346 }
347
348 if (this->_father->isChild(this, Quadrant::SW))
349 {
350 return this->_father->getChild(Quadrant::NW);
351 }
352 if (this->_father->isChild(this, Quadrant::SE))
353 {
354 return this->_father->getChild(Quadrant::NE);
355 }
356
357 QuadTree<POINT>* north_neighbor(this->_father->getNorthNeighbor());
358 if (north_neighbor == nullptr)
359 {
360 return nullptr;
361 }
362 if (north_neighbor->isLeaf())
363 {
364 return north_neighbor;
365 }
366
367 if (this->_father->isChild(this, Quadrant::NW))
368 {
369 return north_neighbor->getChild(Quadrant::SW);
370 }
371
372 return north_neighbor->getChild(Quadrant::SE);
373 }
374
376 {
377 if (this->_father == nullptr)
378 { // root of QuadTree
379 return nullptr;
380 }
381
382 if (this->_father->isChild(this, Quadrant::NW))
383 {
384 return this->_father->getChild(Quadrant::SW);
385 }
386 if (this->_father->isChild(this, Quadrant::NE))
387 {
388 return this->_father->getChild(Quadrant::SE);
389 }
390
391 QuadTree<POINT>* south_neighbor(this->_father->getSouthNeighbor());
392 if (south_neighbor == nullptr)
393 {
394 return nullptr;
395 }
396 if (south_neighbor->isLeaf())
397 {
398 return south_neighbor;
399 }
400
401 if (this->_father->isChild(this, Quadrant::SW))
402 {
403 return south_neighbor->getChild(Quadrant::NW);
404 }
405
406 return south_neighbor->getChild(Quadrant::NE);
407 }
408
410 {
411 if (this->_father == nullptr)
412 { // root of QuadTree
413 return nullptr;
414 }
415
416 if (this->_father->isChild(this, Quadrant::NW))
417 {
418 return this->_father->getChild(Quadrant::NE);
419 }
420 if (this->_father->isChild(this, Quadrant::SW))
421 {
422 return this->_father->getChild(Quadrant::SE);
423 }
424
425 QuadTree<POINT>* east_neighbor(this->_father->getEastNeighbor());
426 if (east_neighbor == nullptr)
427 {
428 return nullptr;
429 }
430 if (east_neighbor->isLeaf())
431 {
432 return east_neighbor;
433 }
434
435 if (this->_father->isChild(this, Quadrant::SE))
436 {
437 return east_neighbor->getChild(Quadrant::SW);
438 }
439
440 return east_neighbor->getChild(Quadrant::NW);
441 }
442
444 {
445 if (this->_father == nullptr)
446 { // root of QuadTree
447 return nullptr;
448 }
449
450 if (this->_father->isChild(this, Quadrant::NE))
451 {
452 return this->_father->getChild(Quadrant::NW);
453 }
454 if (this->_father->isChild(this, Quadrant::SE))
455 {
456 return this->_father->getChild(Quadrant::SW);
457 }
458
459 QuadTree<POINT>* west_neighbor(this->_father->getWestNeighbor());
460 if (west_neighbor == nullptr)
461 {
462 return nullptr;
463 }
464 if (west_neighbor->isLeaf())
465 {
466 return west_neighbor;
467 }
468
469 if (this->_father->isChild(this, Quadrant::SW))
470 {
471 return west_neighbor->getChild(Quadrant::SE);
472 }
473
474 return west_neighbor->getChild(Quadrant::NE);
475 }
476
486 POINT ur,
487 QuadTree* father,
488 std::size_t depth,
489 std::size_t max_points_per_leaf)
490 : _father(father),
491 _ll(std::move(ll)),
492 _ur(std::move(ur)),
493 _depth(depth),
494 _max_points_per_leaf(max_points_per_leaf)
495 {
496 }
497
499 {
500 // create children
501 POINT mid_point(_ll);
502 mid_point[0] += (_ur[0] - _ll[0]) / 2.0;
503 mid_point[1] += (_ur[1] - _ll[1]) / 2.0;
504 assert(_children[0] == nullptr);
505 _children[0] = new QuadTree<POINT>(mid_point, _ur, this, _depth + 1,
506 _max_points_per_leaf); // north east
507 POINT h_ll(mid_point), h_ur(mid_point);
508 h_ll[0] = _ll[0];
509 h_ur[1] = _ur[1];
510 assert(_children[1] == nullptr);
511 _children[1] = new QuadTree<POINT>(h_ll, h_ur, this, _depth + 1,
512 _max_points_per_leaf); // north west
513 assert(_children[2] == nullptr);
514 _children[2] = new QuadTree<POINT>(_ll, mid_point, this, _depth + 1,
515 _max_points_per_leaf); // south west
516 h_ll = _ll;
517 h_ll[0] = mid_point[0];
518 h_ur = _ur;
519 h_ur[1] = mid_point[1];
520 assert(_children[3] == nullptr);
521 _children[3] = new QuadTree<POINT>(h_ll, h_ur, this, _depth + 1,
522 _max_points_per_leaf); // south east
523
524 // distribute points to sub quadtrees
525 for (std::size_t j(0); j < _pnts.size(); j++)
526 {
527 bool nfound(true);
528 for (std::size_t k(0); k < 4 && nfound; k++)
529 {
530 if (_children[k]->addPoint(_pnts[j]))
531 {
532 nfound = false;
533 }
534 }
535 }
536 _pnts.clear();
537 _is_leaf = false;
538 }
539
540 static bool needToRefine(QuadTree<POINT> const* const node)
541 {
542 QuadTree<POINT>* north_neighbor(node->getNorthNeighbor());
543 if (north_neighbor != nullptr)
544 {
545 if (north_neighbor->getDepth() == node->getDepth())
546 {
547 if (!north_neighbor->isLeaf())
548 {
549 if (!(north_neighbor->getChild(Quadrant::SW))->isLeaf())
550 {
551 return true;
552 }
553 if (!(north_neighbor->getChild(Quadrant::SE))->isLeaf())
554 {
555 return true;
556 }
557 }
558 }
559 }
560
561 QuadTree<POINT>* west_neighbor(node->getWestNeighbor());
562 if (west_neighbor != nullptr)
563 {
564 if (west_neighbor->getDepth() == node->getDepth())
565 {
566 if (!west_neighbor->isLeaf())
567 {
568 if (!(west_neighbor->getChild(Quadrant::SE))->isLeaf())
569 {
570 return true;
571 }
572 if (!(west_neighbor->getChild(Quadrant::NE))->isLeaf())
573 {
574 return true;
575 }
576 }
577 }
578 }
579
580 QuadTree<POINT>* south_neighbor(node->getSouthNeighbor());
581 if (south_neighbor != nullptr)
582 {
583 if (south_neighbor->getDepth() == node->getDepth())
584 {
585 if (!south_neighbor->isLeaf())
586 {
587 if (!(south_neighbor->getChild(Quadrant::NE))->isLeaf())
588 {
589 return true;
590 }
591 if (!(south_neighbor->getChild(Quadrant::NW))->isLeaf())
592 {
593 return true;
594 }
595 }
596 }
597 }
598
599 QuadTree<POINT>* east_neighbor(node->getEastNeighbor());
600 if (east_neighbor != nullptr)
601 {
602 if (east_neighbor->getDepth() == node->getDepth())
603 {
604 if (!east_neighbor->isLeaf())
605 {
606 if (!(east_neighbor->getChild(Quadrant::NW))->isLeaf())
607 {
608 return true;
609 }
610 if (!(east_neighbor->getChild(Quadrant::SW))->isLeaf())
611 {
612 return true;
613 }
614 }
615 }
616 }
617 return false;
618 }
619
628 std::array<QuadTree<POINT>*, 4> _children = {nullptr, nullptr, nullptr,
629 nullptr};
630
638 std::size_t _depth = 0;
639 std::vector<POINT const*> _pnts;
640 bool _is_leaf = true;
644 const std::size_t _max_points_per_leaf;
645};
646} // namespace GeoLib
void DBUG(fmt::format_string< Args... > fmt, Args &&... args)
Definition Logging.h:22
QuadTree< POINT > * _father
Definition QuadTree.h:620
QuadTree< POINT > * getNorthNeighbor() const
Definition QuadTree.h:341
bool isChild(QuadTree< POINT > const *const tree, Quadrant quadrant) const
Definition QuadTree.h:336
static bool needToRefine(QuadTree< POINT > const *const node)
Definition QuadTree.h:540
QuadTree< POINT > const * getChild(Quadrant quadrant) const
Definition QuadTree.h:295
std::array< QuadTree< POINT > *, 4 > _children
Definition QuadTree.h:628
bool isLeaf() const
Definition QuadTree.h:334
QuadTree< POINT > const * getFather() const
Definition QuadTree.h:293
std::size_t getDepth() const
Definition QuadTree.h:326
void getMaxDepth(std::size_t &max_depth) const
Definition QuadTree.h:306
void getLeafs(std::list< QuadTree< POINT > * > &leaf_list)
Definition QuadTree.h:232
const std::vector< POINT const * > & getPoints() const
Definition QuadTree.h:247
QuadTree< POINT > * getWestNeighbor() const
Definition QuadTree.h:443
const std::size_t _max_points_per_leaf
Definition QuadTree.h:644
std::vector< POINT const * > _pnts
Definition QuadTree.h:639
void getLeaf(const POINT &pnt, POINT &ll, POINT &ur)
Definition QuadTree.h:255
QuadTree< POINT > * getSouthNeighbor() const
Definition QuadTree.h:375
bool addPoint(POINT const *pnt)
Definition QuadTree.h:91
QuadTree< POINT > * getChild(Quadrant quadrant)
Definition QuadTree.h:329
QuadTree< POINT > * getEastNeighbor() const
Definition QuadTree.h:409
std::size_t _depth
Definition QuadTree.h:638
void getSquarePoints(POINT &ll, POINT &ur) const
Definition QuadTree.h:249
QuadTree(POINT ll, POINT ur, QuadTree *father, std::size_t depth, std::size_t max_points_per_leaf)
Definition QuadTree.h:485
QuadTree(POINT ll, POINT ur, std::size_t max_points_per_leaf)
Definition QuadTree.h:45