Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
tpl_2dtree.H
Go to the documentation of this file.
1
2/*
3 Aleph_w
4
5 Data structures & Algorithms
6 version 2.0.0b
7 https://github.com/lrleon/Aleph-w
8
9 This file is part of Aleph-w library
10
11 Copyright (c) 2002-2026 Leandro Rabindranath Leon
12
13 Permission is hereby granted, free of charge, to any person obtaining a copy
14 of this software and associated documentation files (the "Software"), to deal
15 in the Software without restriction, including without limitation the rights
16 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17 copies of the Software, and to permit persons to whom the Software is
18 furnished to do so, subject to the following conditions:
19
20 The above copyright notice and this permission notice shall be included in all
21 copies or substantial portions of the Software.
22
23 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
29 SOFTWARE.
30*/
31
32
44# ifndef TPL_2DTREE_H
45# define TPL_2DTREE_H
46
47# include <point.H>
48# include <htlist.H>
49# include <ahDefs.H> // For Empty_Class
50
51using namespace Aleph;
52
130template <typename T = Empty_Class>
132{
134 struct Node
135 {
136 Point point;
140
142 Node(const Point & __point) noexcept
143 : point(__point), lb(nullptr), rt(nullptr)
144 {
145 // empty
146 }
147
149 void set_rect(const Geom_Number & xmin, const Geom_Number & ymin,
150 const Geom_Number & xmax, const Geom_Number & ymax) noexcept
151 {
153 }
154
156 void set_rect(const Point & pmin, const Point & pmax) noexcept
157 {
158 rect.set_rect(pmin.get_x(), pmin.get_y(), pmax.get_x(), pmax.get_y());
159 }
160
165 [[nodiscard]] const Geom_Number &x() const noexcept { return point.get_x(); }
166 [[nodiscard]] const Geom_Number &y() const noexcept { return point.get_y(); }
167 };
168
169 Point pmin;
170 Point pmax;
171 size_t N;
173
174public:
176 K2Tree() : pmin(0, 0), pmax(0, 0), N(0), root(nullptr)
177 {
178 // empty
179 }
180
186 K2Tree(const Point & __pmin, const Point & __pmax)
187 : pmin(__pmin), pmax(__pmax), N(0), root(nullptr)
188 {
189 // empty
190 }
191
199 K2Tree(const Geom_Number & xmin, const Geom_Number & ymin,
200 const Geom_Number & xmax, const Geom_Number & ymax)
201 : pmin(xmin, ymin), pmax(xmax, ymax), N(0), root(nullptr)
202 {
203 // empty
204 }
205
206 K2Tree(const K2Tree &) = delete;
207
208 K2Tree &operator =(const K2Tree &) = delete;
209
211 [[nodiscard]] constexpr bool is_empty() const noexcept { return N == 0; }
212
214 [[nodiscard]] constexpr size_t size() const noexcept { return N; }
215
216private:
225 Node * lr_insert(Node *root, const Point & p)
226 {
227 if (root == nullptr)
228 return new Node(p);
229
230 Node *ret_val = nullptr;
231 if (p.get_x() == root->x())
232 {
233 if (p.get_y() == root->y())
234 return nullptr; // Duplicate point
235
236 ret_val = bu_insert(root->rt, p);
237 if (ret_val != nullptr)
238 {
239 root->rt = ret_val; // Node was inserted
240 root->rt->set_rect(root->x(), root->ymin(),
241 root->xmax(), root->ymax());
242
243 return root;
244 }
245
246 return nullptr;
247 }
248
249 if (p.get_x() < root->x())
250 {
251 ret_val = bu_insert(root->lb, p);
252 if (ret_val != nullptr)
253 {
254 root->lb = ret_val;
255 root->lb->set_rect(root->xmin(), root->ymin(),
256 root->x(), root->ymax());
257
258 return root;
259 }
260 else
261 return nullptr;
262 }
263
264 ret_val = bu_insert(root->rt, p);
265 if (ret_val != nullptr)
266 {
267 root->rt = ret_val;
268 root->rt->set_rect(root->x(), root->ymin(),
269 root->xmax(), root->ymax());
270
271 return root;
272 }
273
274 return nullptr;
275 }
276
285 Node * bu_insert(Node *root, const Point & p)
286 {
287 if (root == nullptr)
288 return new Node(p);
289
290 Node *ret_val = nullptr;
291 if (p.get_y() == root->y())
292 {
293 if (p.get_x() == root->x())
294 return nullptr; // Duplicate point
295
296 ret_val = lr_insert(root->rt, p);
297 if (ret_val != nullptr)
298 {
299 root->rt = ret_val; // Node was inserted
300 root->rt->set_rect(root->xmin(), root->y(),
301 root->xmax(), root->ymax());
302
303 return root;
304 }
305
306 return nullptr;
307 }
308
309 if (p.get_y() < root->y())
310 {
311 ret_val = lr_insert(root->lb, p);
312 if (ret_val != nullptr)
313 {
314 root->lb = ret_val;
315 root->lb->set_rect(root->xmin(), root->ymin(),
316 root->xmax(), root->y());
317 return root;
318 }
319 return nullptr;
320 }
321
322 ret_val = lr_insert(root->rt, p);
323 if (ret_val != nullptr)
324 {
325 root->rt = ret_val;
326 root->rt->set_rect(root->xmin(), root->y(),
327 root->xmax(), root->ymax());
328
329 return root;
330 }
331
332 return nullptr;
333 }
334
335public:
343 Point * insert(const Point & p)
344 {
345 if (root == nullptr)
346 {
347 root = new Node(p);
349 ++N;
350
351 return &root->point;
352 }
353
354 Node *ret = lr_insert(root, p);
355 if (ret == nullptr)
356 return nullptr;
357
358 ++N;
359
360 return &root->point; // FIX: Was returning nullptr
361 }
362
363private:
365 static Node * bu_search(Node *root, const Point & p) noexcept
366 {
367 if (root == nullptr)
368 return nullptr;
369
370 if (root->y() == p.get_y())
371 {
372 if (root->x() == p.get_x())
373 return root;
374
375 return lr_search(root->rt, p);
376 }
377
378 if (p.get_y() < root->y())
379 return lr_search(root->lb, p);
380 return lr_search(root->rt, p);
381 }
382
384 static Node * lr_search(Node *root, const Point & p) noexcept
385 {
386 if (root == nullptr)
387 return nullptr;
388
389 if (root->x() == p.get_x())
390 {
391 if (root->y() == p.get_y())
392 return root;
393
394 return bu_search(root->rt, p);
395 }
396
397 if (p.get_x() < root->x())
398 return bu_search(root->lb, p);
399 return bu_search(root->rt, p);
400 }
401
402public:
404 [[nodiscard]] bool contains(const Point & p) const noexcept
405 {
406 return lr_search(root, p) != nullptr;
407 }
408
409private:
416 static void range(Node *root, const Rectangle & rect, DynList<Point> *q)
417 {
418 if (root == nullptr)
419 return;
420
421 if (not root->rect.intersects(rect))
422 return;
423
424 const Point & point = root->point;
425 if (rect.contains(point))
426 q->append(point);
427
428 range(root->lb, rect, q);
429 range(root->rt, rect, q);
430 }
431
432public:
441 void range(const Rectangle & rect, DynList<Point> *l)
442 {
443 if (N == 0)
444 return;
445
446 range(root, rect, l);
447 }
448
449private:
452
458 void lr_nearest(Node *root, const Point & p) noexcept
459 {
460 if (root == nullptr)
461 return;
462
464 return;
465
466 if (const Geom_Number d2 = root->point.distance_squared_to(p); d2 < min_dist2)
467 {
468 min_dist2 = d2;
469 min_node = root;
470 }
471
472 if (p.get_x() < root->x()) // Is p to left of this?
473 {
474 bu_nearest(root->lb, p);
475 bu_nearest(root->rt, p);
476 }
477 else
478 {
479 bu_nearest(root->rt, p);
480 bu_nearest(root->lb, p);
481 }
482 }
483
489 void bu_nearest(Node *root, const Point & p) noexcept
490 {
491 if (root == nullptr)
492 return;
493
495 return;
496
497 if (const Geom_Number d2 = root->point.distance_squared_to(p); d2 < min_dist2)
498 {
499 min_dist2 = d2;
500 min_node = root;
501 }
502
503 if (p.get_y() < root->y()) // Is p below this?
504 {
505 lr_nearest(root->lb, p);
506 lr_nearest(root->rt, p);
507 }
508 else
509 {
510 lr_nearest(root->rt, p);
511 lr_nearest(root->lb, p);
512 }
513 }
514
515public:
523 [[nodiscard]] Point nearest(const Point & p) noexcept
524 {
525 if (N == 0)
526 return NullPoint;
527
528 // Initialize with distance to root (mpq_class doesn't have max())
529 min_node = root;
530 min_dist2 = root->point.distance_squared_to(p);
531
532 lr_nearest(root, p);
533
534 return min_node != nullptr ? min_node->point : NullPoint;
535 }
536
537private:
539 void destroy_tree(Node *node) noexcept
540 {
541 if (node == nullptr)
542 return;
543
544 destroy_tree(node->lb);
545 destroy_tree(node->rt);
546 delete node;
547 }
548
549public:
552 {
554 }
555};
556
557# endif // TPL_2DTREE_H
Core definitions, constants, and utility macros for Aleph-w.
Dynamic singly linked list with functional programming support.
Definition htlist.H:1423
T & append(const T &item)
Append a new item by copy.
Definition htlist.H:1562
2D k-d tree for efficient spatial point operations.
Definition tpl_2dtree.H:132
static Node * lr_search(Node *root, const Point &p) noexcept
Search with left-right (X) split pattern.
Definition tpl_2dtree.H:384
K2Tree()
Default constructor - creates an empty tree with zero-sized region.
Definition tpl_2dtree.H:176
constexpr size_t size() const noexcept
Get the number of points in the tree.
Definition tpl_2dtree.H:214
Node * root
Root of the tree.
Definition tpl_2dtree.H:172
static void range(Node *root, const Rectangle &rect, DynList< Point > *q)
Recursively find points within a rectangle.
Definition tpl_2dtree.H:416
K2Tree(const K2Tree &)=delete
size_t N
Number of points in the tree.
Definition tpl_2dtree.H:171
Point pmin
Lower-left corner of reference rectangle.
Definition tpl_2dtree.H:169
Point pmax
Upper-right corner of reference rectangle.
Definition tpl_2dtree.H:170
Node * min_node
Current nearest node (for nearest())
Definition tpl_2dtree.H:450
Point nearest(const Point &p) noexcept
Find the nearest point to a query point.
Definition tpl_2dtree.H:523
void lr_nearest(Node *root, const Point &p) noexcept
Recursively find nearest neighbor (X-split level).
Definition tpl_2dtree.H:458
K2Tree(const Point &__pmin, const Point &__pmax)
Construct a k-d tree with specified bounding region.
Definition tpl_2dtree.H:186
K2Tree & operator=(const K2Tree &)=delete
Node * bu_insert(Node *root, const Point &p)
Insert into tree with bottom-up (Y) split.
Definition tpl_2dtree.H:285
bool contains(const Point &p) const noexcept
Check if the tree contains a point.
Definition tpl_2dtree.H:404
void range(const Rectangle &rect, DynList< Point > *l)
Find all points within a rectangle.
Definition tpl_2dtree.H:441
Node * lr_insert(Node *root, const Point &p)
Insert into tree with left-right (X) split.
Definition tpl_2dtree.H:225
constexpr bool is_empty() const noexcept
Check if the tree is empty.
Definition tpl_2dtree.H:211
K2Tree(const Geom_Number &xmin, const Geom_Number &ymin, const Geom_Number &xmax, const Geom_Number &ymax)
Construct a k-d tree with specified coordinate bounds.
Definition tpl_2dtree.H:199
~K2Tree()
Destructor - frees all nodes.
Definition tpl_2dtree.H:551
Point * insert(const Point &p)
Insert a point into the tree.
Definition tpl_2dtree.H:343
Geom_Number min_dist2
Current minimum squared distance.
Definition tpl_2dtree.H:451
void bu_nearest(Node *root, const Point &p) noexcept
Recursively find nearest neighbor (Y-split level).
Definition tpl_2dtree.H:489
void destroy_tree(Node *node) noexcept
Recursively delete all nodes.
Definition tpl_2dtree.H:539
static Node * bu_search(Node *root, const Point &p) noexcept
Search with bottom-up (Y) split pattern.
Definition tpl_2dtree.H:365
bool contains(const Point &p) const
Definition point.H:1069
void set_rect(const Geom_Number &__xmin, const Geom_Number &__ymin, const Geom_Number &__xmax, const Geom_Number &__ymax)
Definition point.H:1023
const Geom_Number & get_xmin() const
Definition point.H:1003
const Geom_Number & get_ymin() const
Definition point.H:1005
const Geom_Number & get_xmax() const
Definition point.H:1007
Geom_Number distance_squared_to(const Point &p) const
Definition point.H:1046
bool intersects(const Rectangle &that) const
Definition point.H:1040
const Geom_Number & get_ymax() const
Definition point.H:1009
Singly linked list implementations with head-tail access.
Main namespace for Aleph-w library functions.
Definition ah-arena.H:89
DynList< T > maps(const C &c, Op op)
Classic map operation.
const Point NullPoint
Definition point.C:41
2D point and geometric utilities.
Internal node structure for the k-d tree.
Definition tpl_2dtree.H:135
const Geom_Number & ymin() const noexcept
Definition tpl_2dtree.H:162
Node * rt
Right/top subtree.
Definition tpl_2dtree.H:139
const Geom_Number & xmin() const noexcept
Definition tpl_2dtree.H:161
const Geom_Number & x() const noexcept
Definition tpl_2dtree.H:165
Node * lb
Left/bottom subtree.
Definition tpl_2dtree.H:138
void set_rect(const Geom_Number &xmin, const Geom_Number &ymin, const Geom_Number &xmax, const Geom_Number &ymax) noexcept
Set the rectangular region for this node.
Definition tpl_2dtree.H:149
Point point
The point stored at this node.
Definition tpl_2dtree.H:136
const Geom_Number & y() const noexcept
Definition tpl_2dtree.H:166
const Geom_Number & ymax() const noexcept
Definition tpl_2dtree.H:164
void set_rect(const Point &pmin, const Point &pmax) noexcept
Set the rectangular region using corner points.
Definition tpl_2dtree.H:156
const Geom_Number & xmax() const noexcept
Definition tpl_2dtree.H:163
Node(const Point &__point) noexcept
Construct a node with a given point.
Definition tpl_2dtree.H:142
Rectangle rect
The axis-aligned rectangle for this node's region.
Definition tpl_2dtree.H:137
DynList< int > l