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 Aleph_w
3
4 Data structures & Algorithms
5 version 2.0.0b
6 https://github.com/lrleon/Aleph-w
7
8 This file is part of Aleph-w library
9
10 Copyright (c) 2002-2026 Leandro Rabindranath Leon
11
12 Permission is hereby granted, free of charge, to any person obtaining a copy
13 of this software and associated documentation files (the "Software"), to deal
14 in the Software without restriction, including without limitation the rights
15 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16 copies of the Software, and to permit persons to whom the Software is
17 furnished to do so, subject to the following conditions:
18
19 The above copyright notice and this permission notice shall be included in all
20 copies or substantial portions of the Software.
21
22 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28 SOFTWARE.
29*/
30
31
43# ifndef TPL_2DTREE_H
44# define TPL_2DTREE_H
45
46# include <point.H>
47# include <optional>
48# include <algorithm>
49# include <htlist.H>
50# include <ahSort.H>
51# include <tpl_array.H>
52# include <ahDefs.H> // For Empty_Class
53# include <utility>
54
56
134template <typename T = Empty_Class>
136{
138 struct Node
139 {
144
147 : point_(std::move(p)), lb_(nullptr), rt_(nullptr)
148 {
149 // empty
150 }
151
153 void set_rect(const Geom_Number & xmin, const Geom_Number & ymin,
154 const Geom_Number & xmax, const Geom_Number & ymax) noexcept
155 {
157 }
158
160 void set_rect(const Point & pmin, const Point & pmax) noexcept
161 {
162 rect_.set_rect(pmin.get_x(), pmin.get_y(), pmax.get_x(), pmax.get_y());
163 }
164
169 [[nodiscard]] const Geom_Number &x() const noexcept { return point_.get_x(); }
170 [[nodiscard]] const Geom_Number &y() const noexcept { return point_.get_y(); }
171 };
172
175 size_t N_;
177
178public:
180 K2Tree() : pmin_(0, 0), pmax_(0, 0), N_(0), root_(nullptr)
181 {
182 // empty
183 }
184
191 : pmin_(std::move(pmin)), pmax_(std::move(pmax)), N_(0), root_(nullptr)
192 {
193 // empty
194 }
195
203 K2Tree(const Geom_Number & xmin, const Geom_Number & ymin,
204 const Geom_Number & xmax, const Geom_Number & ymax)
205 : pmin_(xmin, ymin), pmax_(xmax, ymax), N_(0), root_(nullptr)
206 {
207 // empty
208 }
209
210 K2Tree(const K2Tree &) = delete;
211
212 K2Tree &operator =(const K2Tree &) = delete;
213
216 : pmin_(std::move(other.pmin_)), pmax_(std::move(other.pmax_)),
217 N_(other.N_), root_(other.root_)
218 {
219 other.N_ = 0;
220 other.root_ = nullptr;
221 }
222
225 {
226 if (this != &other)
227 {
229 pmin_ = other.pmin_;
230 pmax_ = other.pmax_;
231 N_ = other.N_;
232 root_ = other.root_;
233 other.N_ = 0;
234 other.root_ = nullptr;
235 }
236 return *this;
237 }
238
240 [[nodiscard]] constexpr bool is_empty() const noexcept { return N_ == 0; }
241
243 [[nodiscard]] constexpr size_t size() const noexcept { return N_; }
244
245private:
254 Node * lr_insert(Node *root, const Point & p)
255 {
256 if (root == nullptr)
257 return new Node(p);
258
259 Node *ret_val = nullptr;
260 if (p.get_x() == root->x())
261 {
262 if (p.get_y() == root->y())
263 return nullptr; // Duplicate point
264
265 ret_val = bu_insert(root->rt_, p);
266 if (ret_val != nullptr)
267 {
268 root->rt_ = ret_val; // Node was inserted
269 root->rt_->set_rect(root->x(), root->ymin(),
270 root->xmax(), root->ymax());
271
272 return root;
273 }
274
275 return nullptr;
276 }
277
278 if (p.get_x() < root->x())
279 {
280 ret_val = bu_insert(root->lb_, p);
281 if (ret_val != nullptr)
282 {
283 root->lb_ = ret_val;
284 root->lb_->set_rect(root->xmin(), root->ymin(),
285 root->x(), root->ymax());
286
287 return root;
288 }
289 return nullptr;
290 }
291
292 ret_val = bu_insert(root->rt_, p);
293 if (ret_val != nullptr)
294 {
295 root->rt_ = ret_val;
296 root->rt_->set_rect(root->x(), root->ymin(),
297 root->xmax(), root->ymax());
298
299 return root;
300 }
301
302 return nullptr;
303 }
304
313 Node * bu_insert(Node *root, const Point & p)
314 {
315 if (root == nullptr)
316 return new Node(p);
317
318 Node *ret_val = nullptr;
319 if (p.get_y() == root->y())
320 {
321 if (p.get_x() == root->x())
322 return nullptr; // Duplicate point
323
324 ret_val = lr_insert(root->rt_, p);
325 if (ret_val != nullptr)
326 {
327 root->rt_ = ret_val; // Node was inserted
328 root->rt_->set_rect(root->xmin(), root->y(),
329 root->xmax(), root->ymax());
330
331 return root;
332 }
333
334 return nullptr;
335 }
336
337 if (p.get_y() < root->y())
338 {
339 ret_val = lr_insert(root->lb_, p);
340 if (ret_val != nullptr)
341 {
342 root->lb_ = ret_val;
343 root->lb_->set_rect(root->xmin(), root->ymin(),
344 root->xmax(), root->y());
345 return root;
346 }
347 return nullptr;
348 }
349
350 ret_val = lr_insert(root->rt_, p);
351 if (ret_val != nullptr)
352 {
353 root->rt_ = ret_val;
354 root->rt_->set_rect(root->xmin(), root->y(),
355 root->xmax(), root->ymax());
356
357 return root;
358 }
359
360 return nullptr;
361 }
362
363public:
371 bool insert(const Point & p)
372 {
373 if (root_ == nullptr)
374 {
375 root_ = new Node(p);
377 ++N_;
378 return true;
379 }
380
381 Node *ret = lr_insert(root_, p);
382 if (ret == nullptr)
383 return false;
384
385 ++N_;
386 return true;
387 }
388
389private:
391 static Node * bu_search(Node *root, const Point & p) noexcept
392 {
393 if (root == nullptr)
394 return nullptr;
395
396 if (root->y() == p.get_y())
397 {
398 if (root->x() == p.get_x())
399 return root;
400
401 return lr_search(root->rt_, p);
402 }
403
404 if (p.get_y() < root->y())
405 return lr_search(root->lb_, p);
406 return lr_search(root->rt_, p);
407 }
408
410 static Node * lr_search(Node *root, const Point & p) noexcept
411 {
412 if (root == nullptr)
413 return nullptr;
414
415 if (root->x() == p.get_x())
416 {
417 if (root->y() == p.get_y())
418 return root;
419
420 return bu_search(root->rt_, p);
421 }
422
423 if (p.get_x() < root->x())
424 return bu_search(root->lb_, p);
425 return bu_search(root->rt_, p);
426 }
427
428public:
430 [[nodiscard]] bool contains(const Point & p) const noexcept
431 {
432 return lr_search(root_, p) != nullptr;
433 }
434
435private:
442 static void range(Node *root, const Rectangle & rect, DynList<Point> *q)
443 {
444 if (root == nullptr)
445 return;
446
447 if (not root->rect_.intersects(rect))
448 return;
449
450 if (const Point & point = root->point_; rect.contains(point))
451 q->append(point);
452
453 range(root->lb_, rect, q);
454 range(root->rt_, rect, q);
455 }
456
457public:
466 void range(const Rectangle & rect, DynList<Point> *l) const
467 {
468 if (N_ == 0)
469 return;
470
471 range(root_, rect, l);
472 }
473
474private:
477 {
478 Node *node = nullptr;
480 };
481
488 static void lr_nearest(Node *root, const Point & p,
489 NearestState & st) noexcept
490 {
491 if (root == nullptr)
492 return;
493
494 if (root->rect_.distance_squared_to(p) > st.dist2)
495 return;
496
497 if (const Geom_Number d2 = root->point_.distance_squared_to(p); d2 < st.dist2)
498 {
499 st.dist2 = d2;
500 st.node = root;
501 }
502
503 if (p.get_x() < root->x()) // Is p to left of this?
504 {
505 bu_nearest(root->lb_, p, st);
506 bu_nearest(root->rt_, p, st);
507 }
508 else
509 {
510 bu_nearest(root->rt_, p, st);
511 bu_nearest(root->lb_, p, st);
512 }
513 }
514
521 static void bu_nearest(Node *root, const Point & p,
522 NearestState & st) noexcept
523 {
524 if (root == nullptr)
525 return;
526
527 if (root->rect_.distance_squared_to(p) > st.dist2)
528 return;
529
530 if (const Geom_Number d2 = root->point_.distance_squared_to(p); d2 < st.dist2)
531 {
532 st.dist2 = d2;
533 st.node = root;
534 }
535
536 if (p.get_y() < root->y()) // Is p below this?
537 {
538 lr_nearest(root->lb_, p, st);
539 lr_nearest(root->rt_, p, st);
540 }
541 else
542 {
543 lr_nearest(root->rt_, p, st);
544 lr_nearest(root->lb_, p, st);
545 }
546 }
547
548public:
557 [[nodiscard]] std::optional<Point> nearest(const Point & p) const noexcept
558 {
559 if (N_ == 0)
560 return std::nullopt;
561
562 NearestState st;
563 st.node = root_;
565
566 lr_nearest(root_, p, st);
567
568 return st.node != nullptr ? std::optional<Point>(st.node->point_) : std::nullopt;
569 }
570
576 template <typename Op>
577 void for_each(Op && op) const
578 {
579 for_each_node(root_, std::forward<Op>(op));
580 }
581
600 const Point & pmin,
601 const Point & pmax)
602 {
603 // Sort lexicographically and remove duplicates
604 if (points.size() > 1)
605 {
606 Aleph::in_place_sort(points, [](const Point & a, const Point & b)
607 {
608 if (a.get_x() < b.get_x()) return true;
609 if (b.get_x() < a.get_x()) return false;
610 return a.get_y() < b.get_y();
611 });
612
613 size_t w = 1;
614 for (size_t r = 1; r < points.size(); ++r)
615 if (points(r) != points(w - 1))
616 points(w++) = points(r);
617
618 while (points.size() > w)
619 static_cast<void>(points.remove_last());
620 }
621
622 K2Tree tree(pmin, pmax);
623 if (points.is_empty())
624 return tree;
625
626 tree.root_ = build_balanced(points, 0, points.size(), true,
627 pmin, pmax);
628 tree.N_ = points.size();
629 return tree;
630 }
631
632private:
640 const size_t lo, const size_t hi,
641 const bool split_x,
642 const Point & rmin, const Point & rmax)
643 {
644 if (lo >= hi)
645 return nullptr;
646
647 const size_t mid = lo + (hi - lo) / 2;
648
649 if (split_x)
650 std::nth_element(&pts(lo), &pts(mid), &pts(hi),
651 [](const Point & a, const Point & b)
652 {
653 return a.get_x() < b.get_x();
654 });
655 else
656 std::nth_element(&pts(lo), &pts(mid), &pts(hi),
657 [](const Point & a, const Point & b)
658 {
659 return a.get_y() < b.get_y();
660 });
661
662 // Ensure the left partition [lo, root_pos) has only elements with
663 // split-coord strictly less than the median, matching the search
664 // invariant (equal goes right).
665 const Geom_Number mv = split_x ? pts(mid).get_x() : pts(mid).get_y();
666
667 size_t strict_end = lo;
668 for (size_t i = lo; i < mid; ++i)
669 if (const Geom_Number v = split_x ? pts(i).get_x() : pts(i).get_y(); v < mv)
670 {
671 if (i != strict_end)
672 {
673 const Point tmp = pts(i);
674 pts(i) = pts(strict_end);
675 pts(strict_end) = tmp;
676 }
677 ++strict_end;
678 }
679
680 // If equal-valued elements were found in [strict_end, mid), move
681 // the median to strict_end so that those elements fall into the
682 // right subtree.
683 size_t root_pos = mid;
684 if (strict_end < mid)
685 {
686 const Point median_pt = pts(mid);
687 pts(mid) = pts(strict_end);
690 }
691
692 Node *node = new Node(pts(root_pos));
693 node->set_rect(rmin, rmax);
694
695 if (split_x)
696 {
697 node->lb_ = build_balanced(pts, lo, root_pos, false,
698 rmin, Point(node->x(), rmax.get_y()));
699 node->rt_ = build_balanced(pts, root_pos + 1, hi, false,
700 Point(node->x(), rmin.get_y()), rmax);
701 }
702 else
703 {
704 node->lb_ = build_balanced(pts, lo, root_pos, true,
705 rmin, Point(rmax.get_x(), node->y()));
706 node->rt_ = build_balanced(pts, root_pos + 1, hi, true,
707 Point(rmin.get_x(), node->y()), rmax);
708 }
709
710 return node;
711 }
712
714 template <typename Op>
715 static void for_each_node(const Node *node, Op && op)
716 {
717 if (node == nullptr)
718 return;
719
720 for_each_node(node->lb_, op);
721 op(node->point_);
722 for_each_node(node->rt_, op);
723 }
724
726 void destroy_tree(Node *node) noexcept
727 {
728 if (node == nullptr)
729 return;
730
731 destroy_tree(node->lb_);
732 destroy_tree(node->rt_);
733 delete node;
734 }
735
736public:
739 {
741 }
742};
743
744# endif // TPL_2DTREE_H
Core definitions, constants, and utility macros for Aleph-w.
High-level sorting functions for Aleph containers.
long double w
Definition btreepic.C:153
Simple dynamic array with automatic resizing and functional operations.
Definition tpl_array.H:139
constexpr size_t size() const noexcept
Return the number of elements stored in the stack.
Definition tpl_array.H:351
constexpr bool is_empty() const noexcept
Checks if the container is empty.
Definition tpl_array.H:348
Dynamic singly linked list with functional programming support.
Definition htlist.H:1155
T & append(const T &item)
Definition htlist.H:1271
Represents a point with rectangular coordinates in a 2D plane.
Definition point.H:229
const Geom_Number & get_x() const noexcept
Gets the x-coordinate value.
Definition point.H:457
const Geom_Number & get_y() const noexcept
Gets the y-coordinate value.
Definition point.H:466
Geom_Number distance_squared_to(const Point &that) const
Calculates the squared Euclidean distance to another point.
Definition point.H:1454
An axis-aligned rectangle.
Definition point.H:1737
const Geom_Number & get_xmin() const
Gets the minimum x-coordinate.
Definition point.H:1764
void set_rect(const Geom_Number &xmin, const Geom_Number &ymin, const Geom_Number &xmax, const Geom_Number &ymax)
Sets the coordinates of the rectangle.
Definition point.H:1803
const Geom_Number & get_ymax() const
Gets the maximum y-coordinate.
Definition point.H:1770
const Geom_Number & get_ymin() const
Gets the minimum y-coordinate.
Definition point.H:1766
const Geom_Number & get_xmax() const
Gets the maximum x-coordinate.
Definition point.H:1768
2D k-d tree for efficient spatial point operations.
Definition tpl_2dtree.H:136
bool insert(const Point &p)
Insert a point into the tree.
Definition tpl_2dtree.H:371
static Node * lr_search(Node *root, const Point &p) noexcept
Search with left-right (X) split pattern.
Definition tpl_2dtree.H:410
Point pmax_
Upper-right corner of reference rectangle.
Definition tpl_2dtree.H:174
K2Tree()
Default constructor - creates an empty tree with zero-sized region.
Definition tpl_2dtree.H:180
constexpr size_t size() const noexcept
Get the number of points in the tree.
Definition tpl_2dtree.H:243
K2Tree(Point pmin, Point pmax)
Construct a k-d tree with specified bounding region.
Definition tpl_2dtree.H:190
Node * root_
Root of the tree.
Definition tpl_2dtree.H:176
static void lr_nearest(Node *root, const Point &p, NearestState &st) noexcept
Recursively find the nearest neighbor (X-split level).
Definition tpl_2dtree.H:488
void range(const Rectangle &rect, DynList< Point > *l) const
Find all points within a rectangle.
Definition tpl_2dtree.H:466
static void range(Node *root, const Rectangle &rect, DynList< Point > *q)
Recursively find points within a rectangle.
Definition tpl_2dtree.H:442
K2Tree(const K2Tree &)=delete
Point pmin_
Lower-left corner of reference rectangle.
Definition tpl_2dtree.H:173
K2Tree(K2Tree &&other) noexcept
Move constructor — transfers ownership of all nodes.
Definition tpl_2dtree.H:215
void for_each(Op &&op) const
Apply an operation to every point in the tree (inorder).
Definition tpl_2dtree.H:577
static K2Tree build(Array< Point > points, const Point &pmin, const Point &pmax)
Build a balanced k-d tree from an array of points.
Definition tpl_2dtree.H:599
static Node * build_balanced(Array< Point > &pts, const size_t lo, const size_t hi, const bool split_x, const Point &rmin, const Point &rmax)
Recursively build a balanced subtree selecting medians.
Definition tpl_2dtree.H:639
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:313
bool contains(const Point &p) const noexcept
Check if the tree contains a point.
Definition tpl_2dtree.H:430
static void bu_nearest(Node *root, const Point &p, NearestState &st) noexcept
Recursively find the nearest neighbor (Y-split level).
Definition tpl_2dtree.H:521
std::optional< Point > nearest(const Point &p) const noexcept
Find the nearest point to a query point.
Definition tpl_2dtree.H:557
Node * lr_insert(Node *root, const Point &p)
Insert into tree with left-right (X) split.
Definition tpl_2dtree.H:254
static void for_each_node(const Node *node, Op &&op)
Recursive inorder traversal helper for for_each.
Definition tpl_2dtree.H:715
constexpr bool is_empty() const noexcept
Check if the tree is empty.
Definition tpl_2dtree.H:240
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:203
~K2Tree()
Destructor - frees all nodes.
Definition tpl_2dtree.H:738
void destroy_tree(Node *node) noexcept
Recursively delete all nodes.
Definition tpl_2dtree.H:726
static Node * bu_search(Node *root, const Point &p) noexcept
Search with bottom-up (Y) split pattern.
Definition tpl_2dtree.H:391
size_t N_
Number of points in the tree.
Definition tpl_2dtree.H:175
__gmp_expr< T, __gmp_binary_expr< __gmp_expr< T, U >, unsigned long int, __gmp_root_function > > root(const __gmp_expr< T, U > &expr, unsigned long int l)
Definition gmpfrxx.h:4060
Singly linked list implementations with head-tail access.
auto pmin(ThreadPool &pool, const Container &c, size_t chunk_size=0)
Parallel minimum element.
Divide_Conquer_DP_Result< Cost > divide_and_conquer_partition_dp(const size_t groups, const size_t n, Transition_Cost_Fn transition_cost, const Cost inf=dp_optimization_detail::default_inf< Cost >())
Optimize partition DP using divide-and-conquer optimization.
DynArray< T > & in_place_sort(DynArray< T > &c, Cmp cmp=Cmp())
Sorts a DynArray in place.
Definition ahSort.H:321
auto pmax(ThreadPool &pool, const Container &c, size_t chunk_size=0)
Parallel maximum element.
STL namespace.
2D point and geometric utilities.
Empty placeholder class with no data members.
Definition ahDefs.H:105
Thread-local state for nearest-neighbor recursion.
Definition tpl_2dtree.H:477
Internal node structure for the k-d tree.
Definition tpl_2dtree.H:139
Point point_
The point stored at this node.
Definition tpl_2dtree.H:140
const Geom_Number & ymin() const noexcept
Definition tpl_2dtree.H:166
const Geom_Number & xmin() const noexcept
Definition tpl_2dtree.H:165
const Geom_Number & x() const noexcept
Definition tpl_2dtree.H:169
Node * rt_
Right/top subtree.
Definition tpl_2dtree.H:143
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:153
const Geom_Number & y() const noexcept
Definition tpl_2dtree.H:170
Node(Point p) noexcept
Construct a node with a given point.
Definition tpl_2dtree.H:146
const Geom_Number & ymax() const noexcept
Definition tpl_2dtree.H:168
void set_rect(const Point &pmin, const Point &pmax) noexcept
Set the rectangular region using corner points.
Definition tpl_2dtree.H:160
const Geom_Number & xmax() const noexcept
Definition tpl_2dtree.H:167
Node * lb_
Left/bottom subtree.
Definition tpl_2dtree.H:142
Rectangle rect_
The axis-aligned rectangle for this node's region.
Definition tpl_2dtree.H:141
gsl_rng * r
Dynamic array container with automatic resizing.
DynList< int > l