Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
k2tree_test.cc
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
39#include <gtest/gtest.h>
40#include <tpl_2dtree.H>
41#include <tpl_array.H>
42#include <random>
43#include <algorithm>
44#include <vector>
45#include <set>
46#include <cmath>
47
49
50// ============================================================================
51// Basic Functionality Tests
52// ============================================================================
53
55{
56 K2TreeInt tree(0, 0, 100, 100);
57
58 EXPECT_TRUE(tree.is_empty());
59 EXPECT_EQ(tree.size(), 0);
60}
61
63{
64 K2TreeInt tree(0, 0, 100, 100);
65
66 bool inserted = tree.insert(Point(50, 50));
67
68 EXPECT_TRUE(inserted);
69 EXPECT_EQ(tree.size(), 1);
70 EXPECT_FALSE(tree.is_empty());
71}
72
74{
75 K2TreeInt tree(0, 0, 100, 100);
76
77 tree.insert(Point(25, 25));
78 tree.insert(Point(75, 75));
79 tree.insert(Point(50, 50));
80
81 EXPECT_EQ(tree.size(), 3);
82}
83
85{
86 K2TreeInt tree(0, 0, 100, 100);
87
88 bool first = tree.insert(Point(50, 50));
89 bool second = tree.insert(Point(50, 50));
90
91 EXPECT_TRUE(first);
92 EXPECT_FALSE(second); // Duplicates not allowed
93 EXPECT_EQ(tree.size(), 1);
94}
95
97{
98 K2TreeInt tree(0, 0, 100, 100);
99
100 tree.insert(Point(30, 40));
101 tree.insert(Point(70, 60));
102
103 EXPECT_TRUE(tree.contains(Point(30, 40)));
104 EXPECT_TRUE(tree.contains(Point(70, 60)));
105}
106
108{
109 K2TreeInt tree(0, 0, 100, 100);
110
111 tree.insert(Point(30, 40));
112
113 EXPECT_FALSE(tree.contains(Point(50, 50)));
114 EXPECT_FALSE(tree.contains(Point(70, 60)));
115}
116
118{
119 K2TreeInt tree(0, 0, 100, 100);
120
121 EXPECT_FALSE(tree.contains(Point(50, 50)));
122}
123
124// ============================================================================
125// Insertion Patterns Tests
126// ============================================================================
127
129{
130 K2TreeInt tree(0, 0, 100, 100);
131
132 for (int i = 0; i < 10; ++i)
133 {
134 for (int j = 0; j < 10; ++j)
135 {
136 tree.insert(Point(i * 10, j * 10));
137 }
138 }
139
140 EXPECT_EQ(tree.size(), 100);
141
142 // Verify all points
143 for (int i = 0; i < 10; ++i)
144 {
145 for (int j = 0; j < 10; ++j)
146 {
147 EXPECT_TRUE(tree.contains(Point(i * 10, j * 10)));
148 }
149 }
150}
151
153{
154 K2TreeInt tree(0, 0, 100, 100);
155
156 for (int i = 9; i >= 0; --i)
157 {
158 for (int j = 9; j >= 0; --j)
159 {
160 tree.insert(Point(i * 10, j * 10));
161 }
162 }
163
164 EXPECT_EQ(tree.size(), 100);
165}
166
168{
169 K2TreeInt tree(0, 0, 1000, 1000);
170
171 std::mt19937 gen(12345);
172 std::uniform_real_distribution<> dis(0, 1000);
173
174 std::vector<Point> points;
175 for (int i = 0; i < 100; ++i)
176 {
177 Point p(dis(gen), dis(gen));
178 points.push_back(p);
179 tree.insert(p);
180 }
181
182 EXPECT_EQ(tree.size(), points.size());
183
184 for (const auto & p : points)
185 {
186 EXPECT_TRUE(tree.contains(p));
187 }
188}
189
191{
192 K2TreeInt tree(0, 0, 1000, 1000);
193
194 // Insert cluster in one region
195 for (int i = 0; i < 20; ++i)
196 {
197 tree.insert(Point(10 + i, 10 + i));
198 }
199
200 // Insert cluster in another region
201 for (int i = 0; i < 20; ++i)
202 {
203 tree.insert(Point(900 + i, 900 + i));
204 }
205
206 EXPECT_EQ(tree.size(), 40);
207}
208
209// ============================================================================
210// Nearest Neighbor Tests
211// ============================================================================
212
214{
215 K2TreeInt tree(0, 0, 100, 100);
216
217 tree.insert(Point(50, 50));
218
219 auto nearest = tree.nearest(Point(55, 55));
220 ASSERT_TRUE(nearest.has_value());
221 EXPECT_EQ(nearest->get_x(), 50);
222 EXPECT_EQ(nearest->get_y(), 50);
223}
224
226{
227 K2TreeInt tree(0, 0, 100, 100);
228
229 tree.insert(Point(50, 50));
230 tree.insert(Point(10, 10));
231 tree.insert(Point(90, 90));
232
233 // Query near (50, 50)
234 auto nearest = tree.nearest(Point(52, 48));
235 ASSERT_TRUE(nearest.has_value());
236 EXPECT_EQ(nearest->get_x(), 50);
237 EXPECT_EQ(nearest->get_y(), 50);
238
239 // Query near (10, 10)
240 nearest = tree.nearest(Point(12, 12));
241 ASSERT_TRUE(nearest.has_value());
242 EXPECT_EQ(nearest->get_x(), 10);
243 EXPECT_EQ(nearest->get_y(), 10);
244
245 // Query near (90, 90)
246 nearest = tree.nearest(Point(88, 92));
247 ASSERT_TRUE(nearest.has_value());
248 EXPECT_EQ(nearest->get_x(), 90);
249 EXPECT_EQ(nearest->get_y(), 90);
250}
251
253{
254 K2TreeInt tree(0, 0, 100, 100);
255
256 auto nearest = tree.nearest(Point(50, 50));
257 EXPECT_FALSE(nearest.has_value());
258}
259
261{
262 K2TreeInt tree(0, 0, 100, 100);
263
264 tree.insert(Point(50, 50));
265 tree.insert(Point(75, 75));
266
267 auto nearest = tree.nearest(Point(50, 50));
268 ASSERT_TRUE(nearest.has_value());
269 EXPECT_EQ(nearest->get_x(), 50);
270 EXPECT_EQ(nearest->get_y(), 50);
271}
272
274{
275 K2TreeInt tree(0, 0, 100, 100);
276
277 // Insert grid
278 for (int i = 0; i <= 100; i += 10)
279 {
280 for (int j = 0; j <= 100; j += 10)
281 {
282 tree.insert(Point(i, j));
283 }
284 }
285
286 // Query between grid points
287 auto nearest = tree.nearest(Point(43, 57));
288 ASSERT_TRUE(nearest.has_value());
289
290 // Should find (40, 60) or (40, 50) or (50, 60) or (50, 50)
291 Geom_Number dist = nearest->distance_to(Point(43, 57));
292 EXPECT_LT(dist, 10); // Should be within one grid cell
293}
294
295// ============================================================================
296// Range Query Tests
297// ============================================================================
298
300{
301 K2TreeInt tree(0, 0, 100, 100);
302
303 Rectangle rect(20, 20, 80, 80);
304 DynList<Point> result;
305 tree.range(rect, &result);
306
307 EXPECT_TRUE(result.is_empty());
308}
309
311{
312 K2TreeInt tree(0, 0, 100, 100);
313
314 tree.insert(Point(30, 30));
315 tree.insert(Point(50, 50));
316 tree.insert(Point(70, 70));
317
318 Rectangle rect(0, 0, 100, 100);
319 DynList<Point> result;
320 tree.range(rect, &result);
321
322 EXPECT_EQ(result.size(), 3);
323}
324
326{
327 K2TreeInt tree(0, 0, 100, 100);
328
329 tree.insert(Point(10, 10));
330 tree.insert(Point(90, 90));
331
332 Rectangle rect(40, 40, 60, 60);
333 DynList<Point> result;
334 tree.range(rect, &result);
335
336 EXPECT_TRUE(result.is_empty());
337}
338
340{
341 K2TreeInt tree(0, 0, 100, 100);
342
343 tree.insert(Point(25, 25)); // Inside
344 tree.insert(Point(50, 50)); // Inside
345 tree.insert(Point(75, 75)); // Inside
346 tree.insert(Point(10, 10)); // Outside
347 tree.insert(Point(90, 90)); // Outside
348
349 Rectangle rect(20, 20, 80, 80);
350 DynList<Point> result;
351 tree.range(rect, &result);
352
353 EXPECT_EQ(result.size(), 3);
354
355 // Verify the right points are in the result
356 bool found_25 = false, found_50 = false, found_75 = false;
357 for (const auto & p : result)
358 {
359 if (p == Point(25, 25)) found_25 = true;
360 if (p == Point(50, 50)) found_50 = true;
361 if (p == Point(75, 75)) found_75 = true;
362 }
363
367}
368
370{
371 K2TreeInt tree(0, 0, 100, 100);
372
373 tree.insert(Point(20, 20)); // On boundary
374 tree.insert(Point(80, 80)); // On boundary
375 tree.insert(Point(50, 50)); // Inside
376
377 Rectangle rect(20, 20, 80, 80);
378 DynList<Point> result;
379 tree.range(rect, &result);
380
381 // Boundary behavior depends on Rectangle::contains implementation
382 EXPECT_GE(result.size(), 1); // At least the inside point
383 EXPECT_LE(result.size(), 3);
384}
385
386// ============================================================================
387// Stress Tests
388// ============================================================================
389
391{
392 K2TreeInt tree(0, 0, 10000, 10000);
393
394 std::mt19937 gen(54321);
395 std::uniform_real_distribution<> dis(0, 10000);
396
397 const size_t num_points = 10000;
398 std::vector<Point> points;
399
400 for (size_t i = 0; i < num_points; ++i)
401 {
402 Point p(dis(gen), dis(gen));
403 points.push_back(p);
404 tree.insert(p);
405 // May return nullptr for duplicates
406 }
407
408 // Size should be <= num_points due to possible duplicates
409 EXPECT_LE(tree.size(), num_points);
410 EXPECT_GT(tree.size(), num_points * 0.9); // Expect most to be unique
411}
412
414{
415 K2TreeInt tree(0, 0, 1000, 1000);
416
417 std::mt19937 gen(99999);
418 std::uniform_real_distribution<> dis(0, 1000);
419
420 // Insert points
421 for (int i = 0; i < 1000; ++i)
422 {
423 tree.insert(Point(dis(gen), dis(gen)));
424 }
425
426 // Perform many nearest queries
427 for (int i = 0; i < 1000; ++i)
428 {
429 Point query(dis(gen), dis(gen));
430 auto nearest = tree.nearest(query);
431 EXPECT_TRUE(nearest.has_value());
432 }
433}
434
436{
437 K2TreeInt tree(0, 0, 1000, 1000);
438
439 std::mt19937 gen(11111);
440 std::uniform_real_distribution<> dis(0, 1000);
441
442 // Insert points
443 for (int i = 0; i < 1000; ++i)
444 {
445 tree.insert(Point(dis(gen), dis(gen)));
446 }
447
448 // Perform many range queries
449 for (int i = 0; i < 100; ++i)
450 {
451 double x1 = dis(gen), y1 = dis(gen);
452 double x2 = dis(gen), y2 = dis(gen);
453
454 if (x1 > x2) std::swap(x1, x2);
455 if (y1 > y2) std::swap(y1, y2);
456
457 Rectangle rect(x1, y1, x2, y2);
458 DynList<Point> result;
459 tree.range(rect, &result);
460
461 // Just verify it doesn't crash
462 EXPECT_GE(result.size(), 0);
463 }
464}
465
467{
468 K2TreeInt tree(0, 0, 1000, 1000);
469
470 // Dense region: [100, 200] × [100, 200]
471 for (int i = 100; i <= 200; i += 2)
472 {
473 for (int j = 100; j <= 200; j += 2)
474 {
475 tree.insert(Point(i, j));
476 }
477 }
478
479 // Sparse region: [700, 900] × [700, 900]
480 for (int i = 700; i <= 900; i += 50)
481 {
482 for (int j = 700; j <= 900; j += 50)
483 {
484 tree.insert(Point(i, j));
485 }
486 }
487
488 // Query dense region
489 Rectangle dense_rect(100, 100, 200, 200);
492 EXPECT_GT(dense_result.size(), 0);
493
494 // Query sparse region
495 Rectangle sparse_rect(700, 700, 900, 900);
498 EXPECT_GT(sparse_result.size(), 0);
499 EXPECT_LT(sparse_result.size(), dense_result.size());
500}
501
502// ============================================================================
503// Edge Cases
504// ============================================================================
505
507{
508 K2TreeInt tree(0, 0, 100, 100);
509
510 // Insert points along a line
511 for (int i = 0; i <= 100; i += 10)
512 {
513 tree.insert(Point(i, i)); // Diagonal line
514 }
515
516 EXPECT_EQ(tree.size(), 11);
517
518 // Verify all can be found
519 for (int i = 0; i <= 100; i += 10)
520 {
521 EXPECT_TRUE(tree.contains(Point(i, i)));
522 }
523}
524
526{
527 K2TreeInt tree(0, 0, 100, 100);
528
529 for (int i = 0; i <= 100; i += 10)
530 {
531 tree.insert(Point(50, i));
532 }
533
534 EXPECT_EQ(tree.size(), 11);
535}
536
538{
539 K2TreeInt tree(0, 0, 100, 100);
540
541 for (int i = 0; i <= 100; i += 10)
542 {
543 tree.insert(Point(i, 50));
544 }
545
546 EXPECT_EQ(tree.size(), 11);
547}
548
550{
551 K2TreeInt tree(0, 0, 1, 1);
552
553 tree.insert(Point(0.1, 0.1));
554 tree.insert(Point(0.100001, 0.100001));
555 tree.insert(Point(0.9, 0.9));
556
557 EXPECT_EQ(tree.size(), 3);
558}
559
561{
562 K2TreeInt tree(-100, -100, 100, 100);
563
564 tree.insert(Point(-50, -50));
565 tree.insert(Point(0, 0));
566 tree.insert(Point(50, 50));
567
568 EXPECT_EQ(tree.size(), 3);
569 EXPECT_TRUE(tree.contains(Point(-50, -50)));
570 EXPECT_TRUE(tree.contains(Point(0, 0)));
571 EXPECT_TRUE(tree.contains(Point(50, 50)));
572}
573
574// ============================================================================
575// Correctness Verification Tests
576// ============================================================================
577
579{
580 K2TreeInt tree(0, 0, 100, 100);
581
582 std::vector<Point> points = {
583 Point(10, 10),
584 Point(50, 50),
585 Point(90, 90),
586 Point(30, 70),
587 Point(70, 30)
588 };
589
590 for (const auto & p : points)
591 tree.insert(p);
592
593 Point query(45, 45);
594 auto nearest = tree.nearest(query);
595 ASSERT_TRUE(nearest.has_value());
596
597 // Verify it's actually the nearest
598 Geom_Number min_dist = nearest->distance_to(query);
599 for (const auto & p : points)
600 {
601 Geom_Number dist = p.distance_to(query);
602 EXPECT_LE(min_dist, dist); // Exact arithmetic — no tolerance needed
603 }
604}
605
607{
608 K2TreeInt tree(0, 0, 100, 100);
609
610 std::mt19937 gen(77777);
611 std::uniform_real_distribution<> dis(0, 100);
612
613 std::vector<Point> all_points;
614 for (int i = 0; i < 100; ++i)
615 {
616 Point p(dis(gen), dis(gen));
617 all_points.push_back(p);
618 tree.insert(p);
619 }
620
621 Rectangle rect(25, 25, 75, 75);
622 DynList<Point> result;
623 tree.range(rect, &result);
624
625 // Verify all points in result are actually in rectangle
626 for (const auto & p : result)
627 {
628 EXPECT_TRUE(rect.contains(p));
629 }
630
631 // Verify all points in rectangle are in result
632 for (const auto & p : all_points)
633 {
634 if (rect.contains(p))
635 {
636 bool found = false;
637 for (const auto & r : result)
638 {
639 if (r == p)
640 {
641 found = true;
642 break;
643 }
644 }
645 EXPECT_TRUE(found) << "Point in rectangle not found in result";
646 }
647 }
648}
649
650// ============================================================================
651// Fuzz Testing
652// ============================================================================
653
655{
656 K2TreeInt tree(0, 0, 10000, 10000);
657
658 std::mt19937 gen(31415);
659 std::uniform_real_distribution<> coord_dis(0, 10000);
660 std::uniform_int_distribution<> op_dis(0, 2);
661
662 std::set<std::pair<double, double>> inserted;
663
664 for (int i = 0; i < 1000; ++i)
665 {
666 int op = op_dis(gen);
667
668 if (op == 0) // Insert
669 {
671 bool ok = tree.insert(p);
672 if (ok)
673 {
674 inserted.insert(std::make_pair(static_cast<double>(p.get_x().get_d()),
675 static_cast<double>(p.get_y().get_d())));
676 }
677 }
678 else if (op == 1) // Nearest
679 {
680 Point query(coord_dis(gen), coord_dis(gen));
681 auto nearest = tree.nearest(query);
682
683 if (not tree.is_empty())
684 EXPECT_TRUE(nearest.has_value());
685 }
686 else // Range
687 {
688 double x1 = coord_dis(gen), y1 = coord_dis(gen);
689 double x2 = coord_dis(gen), y2 = coord_dis(gen);
690 if (x1 > x2) std::swap(x1, x2);
691 if (y1 > y2) std::swap(y1, y2);
692
693 Rectangle rect(x1, y1, x2, y2);
694 DynList<Point> result;
695 tree.range(rect, &result);
696 }
697 }
698
699 // Verify all inserted points can be found
700 for (const auto & [x, y] : inserted)
701 {
702 EXPECT_TRUE(tree.contains(Point(x, y)));
703 }
704}
705
706// ============================================================================
707// Insert Correctness Tests
708// ============================================================================
709
711{
712 K2TreeInt tree(0, 0, 100, 100);
713
714 EXPECT_TRUE(tree.insert(Point(10, 20)));
715 EXPECT_TRUE(tree.insert(Point(30, 40)));
716 EXPECT_TRUE(tree.insert(Point(50, 60)));
717 EXPECT_EQ(tree.size(), 3);
718}
719
721{
722 K2TreeInt tree(0, 0, 100, 100);
723
724 EXPECT_TRUE(tree.insert(Point(42, 17)));
725 EXPECT_FALSE(tree.insert(Point(42, 17)));
726 EXPECT_EQ(tree.size(), 1);
727}
728
730{
731 K2TreeInt tree(0, 0, 1000, 1000);
732
733 std::mt19937 gen(55555);
734 std::uniform_real_distribution<> dis(0, 1000);
735
736 std::vector<Point> points;
737 for (int i = 0; i < 200; ++i)
738 {
739 Point p(dis(gen), dis(gen));
740 if (tree.insert(p))
741 points.push_back(p);
742 }
743
744 for (const auto & p : points)
745 EXPECT_TRUE(tree.contains(p));
746
747 EXPECT_EQ(tree.size(), points.size());
748}
749
750// ============================================================================
751// Move Semantics Tests
752// ============================================================================
753
755{
756 K2TreeInt src(0, 0, 100, 100);
757 src.insert(Point(10, 20));
758 src.insert(Point(30, 40));
759 src.insert(Point(50, 60));
760 ASSERT_EQ(src.size(), 3);
761
762 K2TreeInt dst(std::move(src));
763
764 // dst owns the nodes now
765 EXPECT_EQ(dst.size(), 3);
766 EXPECT_TRUE(dst.contains(Point(10, 20)));
767 EXPECT_TRUE(dst.contains(Point(30, 40)));
768 EXPECT_TRUE(dst.contains(Point(50, 60)));
769
770 // src is empty after move
771 EXPECT_EQ(src.size(), 0);
772 EXPECT_TRUE(src.is_empty());
773}
774
776{
777 K2TreeInt src(0, 0, 100, 100);
778 src.insert(Point(10, 20));
779 src.insert(Point(30, 40));
780
781 K2TreeInt dst(0, 0, 200, 200);
782 dst.insert(Point(99, 99));
783 ASSERT_EQ(dst.size(), 1);
784
785 dst = std::move(src);
786
787 EXPECT_EQ(dst.size(), 2);
788 EXPECT_TRUE(dst.contains(Point(10, 20)));
789 EXPECT_TRUE(dst.contains(Point(30, 40)));
790 EXPECT_FALSE(dst.contains(Point(99, 99))); // old node freed
791
792 EXPECT_EQ(src.size(), 0);
793 EXPECT_TRUE(src.is_empty());
794}
795
797{
798 K2TreeInt tree(0, 0, 100, 100);
799 tree.insert(Point(5, 5));
800
801 K2TreeInt * self = &tree;
802 tree = std::move(*self);
803
804 // Self-move should be a no-op
805 EXPECT_EQ(tree.size(), 1);
806 EXPECT_TRUE(tree.contains(Point(5, 5)));
807}
808
809// ============================================================================
810// Balanced Build Tests
811// ============================================================================
812
814{
816 auto tree = K2TreeInt::build(pts, Point(0, 0), Point(100, 100));
817
818 EXPECT_TRUE(tree.is_empty());
819 EXPECT_EQ(tree.size(), 0);
820}
821
823{
825 pts.append(Point(42, 17));
826
827 auto tree = K2TreeInt::build(pts, Point(0, 0), Point(100, 100));
828
829 EXPECT_EQ(tree.size(), 1);
830 EXPECT_TRUE(tree.contains(Point(42, 17)));
831}
832
834{
836 pts.append(Point(10, 10));
837 pts.append(Point(20, 20));
838 pts.append(Point(30, 30));
839 pts.append(Point(40, 40));
840 pts.append(Point(50, 50));
841
842 auto tree = K2TreeInt::build(pts, Point(0, 0), Point(100, 100));
843
844 EXPECT_EQ(tree.size(), 5);
845 for (size_t i = 0; i < pts.size(); ++i)
846 EXPECT_TRUE(tree.contains(pts(i)));
847}
848
850{
852 pts.append(Point(10, 10));
853 pts.append(Point(10, 10));
854 pts.append(Point(20, 20));
855 pts.append(Point(20, 20));
856 pts.append(Point(30, 30));
857
858 auto tree = K2TreeInt::build(pts, Point(0, 0), Point(100, 100));
859
860 EXPECT_EQ(tree.size(), 3);
861 EXPECT_TRUE(tree.contains(Point(10, 10)));
862 EXPECT_TRUE(tree.contains(Point(20, 20)));
863 EXPECT_TRUE(tree.contains(Point(30, 30)));
864}
865
867{
869 for (int i = 0; i <= 100; i += 10)
870 for (int j = 0; j <= 100; j += 10)
871 pts.append(Point(i, j));
872
873 auto tree = K2TreeInt::build(pts, Point(0, 0), Point(100, 100));
874
875 EXPECT_EQ(tree.size(), 121);
876
877 auto nearest = tree.nearest(Point(43, 57));
878 ASSERT_TRUE(nearest.has_value());
879
880 // Should find a grid point within one cell (distance < 10)
881 Geom_Number dist = nearest->distance_to(Point(43, 57));
882 EXPECT_LT(dist, 10);
883}
884
886{
887 std::mt19937 gen(12321);
888 std::uniform_real_distribution<> dis(0, 10000);
889
891 for (int i = 0; i < 5000; ++i)
893
894 auto balanced = K2TreeInt::build(pts, Point(0, 0), Point(10000, 10000));
895
896 // All unique points should be contained
897 for (size_t i = 0; i < pts.size(); ++i)
898 EXPECT_TRUE(balanced.contains(pts(i)));
899
900 // Nearest queries should give correct results
901 for (int i = 0; i < 100; ++i)
902 {
903 Point query(dis(gen), dis(gen));
904 auto near_bal = balanced.nearest(query);
905 ASSERT_TRUE(near_bal.has_value());
906
907 // Brute-force verification
908 Geom_Number best_d2 = near_bal->distance_squared_to(query);
909 for (size_t j = 0; j < pts.size(); ++j)
910 {
911 Geom_Number d2 = pts(j).distance_squared_to(query);
912 EXPECT_LE(best_d2, d2);
913 }
914 }
915}
916
917// ============================================================================
918// for_each Tests
919// ============================================================================
920
922{
923 K2TreeInt tree(0, 0, 100, 100);
924
925 size_t count = 0;
926 tree.for_each([&count](const Point &) { ++count; });
927
928 EXPECT_EQ(count, 0);
929}
930
932{
933 K2TreeInt tree(0, 0, 100, 100);
934
935 std::set<std::pair<double, double>> expected;
936 for (int i = 0; i <= 50; i += 10)
937 for (int j = 0; j <= 50; j += 10)
938 {
939 tree.insert(Point(i, j));
940 expected.insert({static_cast<double>(i), static_cast<double>(j)});
941 }
942
943 std::set<std::pair<double, double>> visited;
944 tree.for_each([&visited](const Point & p)
945 {
946 visited.insert({p.get_x().get_d(), p.get_y().get_d()});
947 });
948
949 EXPECT_EQ(visited.size(), expected.size());
950 EXPECT_EQ(visited, expected);
951}
952
954{
956 for (int i = 1; i <= 100; ++i)
957 pts.append(Point(i, i * 2));
958
959 auto tree = K2TreeInt::build(pts, Point(0, 0), Point(200, 200));
960
961 size_t count = 0;
962 tree.for_each([&count](const Point &) { ++count; });
963
964 EXPECT_EQ(count, tree.size());
965 EXPECT_EQ(count, 100);
966}
967
968// ============================================================================
969// Main
970// ============================================================================
971
972int main(int argc, char **argv)
973{
974 ::testing::InitGoogleTest(&argc, argv);
975 return RUN_ALL_TESTS();
976}
Simple dynamic array with automatic resizing and functional operations.
Definition tpl_array.H:139
T & append(const T &data)
Append a copy of data
Definition tpl_array.H:245
Dynamic singly linked list with functional programming support.
Definition htlist.H:1155
constexpr bool is_empty() const noexcept
Definition htlist.H:419
size_t size() const noexcept
Count the number of elements of the list.
Definition htlist.H:1065
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
An axis-aligned rectangle.
Definition point.H:1737
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
constexpr size_t size() const noexcept
Get the number of points in the tree.
Definition tpl_2dtree.H:243
static void range(Node *root, const Rectangle &rect, DynList< Point > *q)
Recursively find points within a rectangle.
Definition tpl_2dtree.H:442
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
bool contains(const Point &p) const noexcept
Check if the tree contains a point.
Definition tpl_2dtree.H:430
std::optional< Point > nearest(const Point &p) const noexcept
Find the nearest point to a query point.
Definition tpl_2dtree.H:557
constexpr bool is_empty() const noexcept
Check if the tree is empty.
Definition tpl_2dtree.H:240
#define TEST(name)
__gmp_expr< T, __gmp_unary_expr< __gmp_expr< T, U >, __gmp_y1_function > > y1(const __gmp_expr< T, U > &expr)
Definition gmpfrxx.h:4103
static mpfr_t y
Definition mpfr_mul_d.c:3
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.
Itor::difference_type count(const Itor &beg, const Itor &end, const T &value)
Count elements equal to a value.
Definition ahAlgo.H:127
gsl_rng * r
2D k-d tree implementation for spatial point indexing.
Dynamic array container with automatic resizing.