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