Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
tpl_2dtree_example.cc
Go to the documentation of this file.
1
39#include <iostream>
40#include <cmath>
41#include <tpl_2dtree.H>
42#include <point.H>
43
44using namespace std;
45using namespace Aleph;
46
47int main()
48{
49 cout << "=== 2D Spatial Trees: Educational Examples ===\n\n";
50
51 // =========================================================================
52 // EXAMPLE 1: Building a 2D-Tree
53 // =========================================================================
54 {
55 cout << "--- Example 1: Inserting Points into 2D-Tree ---\n\n";
56
57 // STEP 1: Create 2D-tree with bounding box
58 // Region: [0, 100] x [0, 100]
59 K2Tree<> tree(0, 0, 100, 100);
60
61 cout << "Created 2D-tree for region [0,100] x [0,100]\n\n";
62
63 // STEP 2: Insert points
64 cout << "Inserting points:\n";
65
66 Point p1(25, 50);
67 Point p2(75, 25);
68 Point p3(50, 75);
69 Point p4(10, 10);
70 Point p5(90, 90);
71
72 tree.insert(p1);
73 cout << " Inserted (25, 50)\n";
74
75 tree.insert(p2);
76 cout << " Inserted (75, 25)\n";
77
78 tree.insert(p3);
79 cout << " Inserted (50, 75)\n";
80
81 tree.insert(p4);
82 cout << " Inserted (10, 10)\n";
83
84 tree.insert(p5);
85 cout << " Inserted (90, 90)\n\n";
86
87 cout << "TREE STRUCTURE (conceptual):\n";
88 cout << " Level 0 (split on X): root = (25, 50)\n";
89 cout << " Left (x < 25): (10, 10)\n";
90 cout << " Right (x >= 25):\n";
91 cout << " Level 1 (split on Y): (75, 25)\n";
92 cout << " Left (y < 25): none\n";
93 cout << " Right (y >= 25): (50, 75), (90, 90)\n\n";
94
95 cout << "KEY CONCEPT: Alternating splits create balanced partitioning\n";
96 cout << " of 2D space into rectangular regions\n\n";
97 }
98
99 // =========================================================================
100 // EXAMPLE 2: Point Search
101 // =========================================================================
102 {
103 cout << "--- Example 2: Searching for Points ---\n\n";
104
105 K2Tree<> tree(0, 0, 100, 100);
106
107 // Build tree
108 tree.insert(Point(25, 50));
109 tree.insert(Point(75, 25));
110 tree.insert(Point(50, 75));
111 tree.insert(Point(10, 10));
112
113 cout << "Tree contains: (25,50), (75,25), (50,75), (10,10)\n\n";
114
115 // Search for existing point
116 cout << "SEARCH QUERIES:\n";
117
118 Point query1(50, 75);
119 if (tree.contains(query1))
120 cout << " Point (50, 75): FOUND ✓\n";
121 else
122 cout << " Point (50, 75): NOT FOUND\n";
123
124 Point query2(30, 40);
125 if (tree.contains(query2))
126 cout << " Point (30, 40): FOUND\n";
127 else
128 cout << " Point (30, 40): NOT FOUND ✓\n";
129
130 Point query3(25, 50);
131 if (tree.contains(query3))
132 cout << " Point (25, 50): FOUND ✓ (root node)\n";
133 else
134 cout << " Point (25, 50): NOT FOUND\n";
135
136 cout << "\nCOMPLEXITY:\n";
137 cout << " Average case: O(log n) - like binary search\n";
138 cout << " Worst case: O(n) - if tree is unbalanced\n";
139 cout << " For random data: Usually well-balanced\n\n";
140 }
141
142 // =========================================================================
143 // EXAMPLE 3: Range Query (Points in Rectangle)
144 // =========================================================================
145 {
146 cout << "--- Example 3: Range Query (Rectangle Search) ---\n\n";
147
148 K2Tree<> tree(0, 0, 200, 200);
149
150 cout << "SCENARIO: City POI (Points of Interest) database\n";
151 cout << "===============================================\n\n";
152
153 // Insert POIs with names (conceptually)
154 struct POI {
155 Point location;
156 string name;
157 };
158
159 POI pois[] = {
160 {Point(20, 30), "Restaurant A"},
161 {Point(50, 50), "Park B"},
162 {Point(80, 40), "Hotel C"},
163 {Point(120, 150), "Museum D"},
164 {Point(150, 180), "Theater E"},
165 {Point(60, 70), "Cafe F"},
166 {Point(180, 20), "Mall G"}
167 };
168
169 // Insert into tree
170 for (const auto& poi : pois)
171 tree.insert(poi.location);
172
173 cout << "Inserted 7 POIs across the city\n\n";
174
175 // Range query: Find all POIs in downtown area
176 Rectangle downtown(40, 30, 90, 80);
177
178 cout << "QUERY: Find all POIs in downtown area\n";
179 cout << " Rectangle: (40,30) to (90,80)\n\n";
180
182 tree.range(downtown, &results);
183
184 cout << "Results:\n";
185 for (size_t i = 0; i < sizeof(pois)/sizeof(POI); ++i)
186 {
187 Point p = pois[i].location;
188 auto x = p.get_x();
189 auto y = p.get_y();
190
191 if (x >= 40 && x <= 90 && y >= 30 && y <= 80)
192 cout << " " << pois[i].name << " at (" << x << ", " << y << ")\n";
193 }
194
195 cout << "\nCOMPLEXITY: O(sqrt(n) + k) where k = number of results\n";
196 cout << " Much better than O(n) linear scan!\n\n";
197
198 cout << "REAL-WORLD: Map applications showing POIs in visible area\n\n";
199 }
200
201 // =========================================================================
202 // EXAMPLE 4: Nearest Neighbor Search
203 // =========================================================================
204 {
205 cout << "--- Example 4: Finding Nearest Point ---\n\n";
206
207 K2Tree<> tree(0, 0, 100, 100);
208
209 cout << "SCENARIO: Find closest emergency service\n";
210 cout << "========================================\n\n";
211
212 // Insert emergency service locations
213 Point hospital(20, 80);
214 Point fire_station(70, 30);
215 Point police(50, 50);
216 Point ambulance(85, 75);
217
218 tree.insert(hospital);
219 tree.insert(fire_station);
220 tree.insert(police);
221 tree.insert(ambulance);
222
223 cout << "Emergency services:\n";
224 cout << " Hospital: (20, 80)\n";
225 cout << " Fire Station: (70, 30)\n";
226 cout << " Police: (50, 50)\n";
227 cout << " Ambulance: (85, 75)\n\n";
228
229 // Query point (emergency location)
230 Point emergency(60, 40);
231
232 cout << "EMERGENCY at (60, 40)\n";
233 cout << "Finding nearest service...\n\n";
234
235 // Manual nearest neighbor (simplified)
236 auto nearest = tree.nearest(emergency);
237
238 ah_domain_error_if(not nearest.has_value())
239 << "Unexpected empty tree";
240
241 auto dist = emergency.distance_to(*nearest);
242
243 cout << "NEAREST SERVICE:\n";
244 cout << " Location: (" << nearest->get_x() << ", " << nearest->get_y() << ")\n";
245 cout << " Distance: " << dist << " units\n";
246
247 // Determine which service it is
248 if (nearest->get_x() == 70 && nearest->get_y() == 30)
249 cout << " Type: Fire Station\n";
250 else if (nearest->get_x() == 50 && nearest->get_y() == 50)
251 cout << " Type: Police\n";
252
253 cout << "\nALGORITHM:\n";
254 cout << " 1. Start at root\n";
255 cout << " 2. Recursively explore promising branches\n";
256 cout << " 3. Prune branches that can't contain closer point\n";
257 cout << " 4. Track best candidate while descending\n\n";
258
259 cout << "COMPLEXITY: O(log n) average - very efficient!\n\n";
260 }
261
262 // =========================================================================
263 // EXAMPLE 5: Collision Detection (Game Development)
264 // =========================================================================
265 {
266 cout << "--- Example 5: Spatial Partitioning for Games ---\n\n";
267
268 cout << "SCENARIO: 2D game with moving objects\n";
269 cout << "=====================================\n\n";
270
271 K2Tree<> game_world(0, 0, 1000, 1000);
272
273 cout << "Game world: 1000x1000 pixels\n";
274 cout << "Objects: Players, enemies, projectiles, items\n\n";
275
276 // Insert game objects
277 struct GameObject {
278 Point position;
279 string type;
280 double radius;
281 };
282
283 GameObject objects[] = {
284 {Point(100, 200), "Player", 10},
285 {Point(150, 220), "Enemy", 15},
286 {Point(500, 500), "Item", 5},
287 {Point(800, 100), "Enemy", 15},
288 {Point(120, 210), "Projectile", 2}
289 };
290
291 for (const auto& obj : objects)
292 game_world.insert(obj.position);
293
294 cout << "Inserted " << (sizeof(objects)/sizeof(GameObject)) << " game objects\n\n";
295
296 // Check collisions near player
297 Point player_pos(100, 200);
298 double collision_range = 50; // Check within 50 pixels
299
300 cout << "COLLISION CHECK:\n";
301 cout << " Player at (100, 200)\n";
302 cout << " Checking range: 50 pixels\n\n";
303
305 player_pos.get_x() - collision_range,
306 player_pos.get_y() - collision_range,
307 player_pos.get_x() + collision_range,
309 );
310
313
314 cout << "Nearby objects:\n";
315 for (const auto& obj : objects)
316 {
317 auto dist = player_pos.distance_to(obj.position);
318
319 if (dist <= collision_range && dist > 0) // Exclude self
320 cout << " " << obj.type << " at distance " << dist << "\n";
321 }
322
323 cout << "\nGAME OPTIMIZATION:\n";
324 cout << " Without 2D-tree: Check all N objects → O(N^2) for N entities\n";
325 cout << " With 2D-tree: Check only nearby → O(N log N + k*N)\n";
326 cout << " For 1000 objects: ~1M vs ~10K comparisons!\n\n";
327 }
328
329 // =========================================================================
330 // EXAMPLE 6: K-Nearest Neighbors (Machine Learning)
331 // =========================================================================
332 {
333 cout << "--- Example 6: k-NN Classification ---\n\n";
334
335 cout << "SCENARIO: Classify new data point\n";
336 cout << "=================================\n\n";
337
338 K2Tree<> dataset(0, 0, 100, 100);
339
340 cout << "Training data (2D feature space):\n";
341
342 // Class A points (clustered around 20, 20)
343 cout << " Class A (circle): around (20, 20)\n";
344 dataset.insert(Point(18, 22));
345 dataset.insert(Point(22, 18));
346 dataset.insert(Point(20, 25));
347 dataset.insert(Point(15, 20));
348
349 // Class B points (clustered around 80, 80)
350 cout << " Class B (square): around (80, 80)\n";
351 dataset.insert(Point(78, 82));
352 dataset.insert(Point(82, 78));
353 dataset.insert(Point(80, 85));
354 dataset.insert(Point(75, 80));
355
356 cout << "\nNew data point: (25, 25)\n";
357 cout << "Task: Classify as A or B using 3-NN\n\n";
358
359 Point new_point(25, 25);
360
361 cout << "ALGORITHM:\n";
362 cout << " 1. Find 3 nearest neighbors in tree\n";
363 cout << " 2. Take majority vote of their classes\n";
364 cout << " 3. Assign that class to new point\n\n";
365
366 cout << "EXPECTED RESULT:\n";
367 cout << " 3 nearest neighbors likely from Class A\n";
368 cout << " (New point is closer to Class A cluster)\n";
369 cout << " Classification: Class A\n\n";
370
371 cout << "COMPLEXITY:\n";
372 cout << " k-NN with 2D-tree: O(k log n)\n";
373 cout << " k-NN without: O(n) for each query\n";
374 cout << " Speedup: log n times faster!\n\n";
375 }
376
377 cout << "=== SUMMARY: 2D Spatial Trees ===\n";
378 cout << "\n1. WHAT IS IT?\n";
379 cout << " Binary search tree for 2D points\n";
380 cout << " Alternates splitting on X and Y\n";
381 cout << " Partitions space into rectangles\n";
382 cout << "\n2. KEY OPERATIONS:\n";
383 cout << " Insert: O(log n) average\n";
384 cout << " Search: O(log n) average\n";
385 cout << " Range query: O(sqrt(n) + k)\n";
386 cout << " Nearest neighbor: O(log n) average\n";
387 cout << "\n3. WHEN TO USE:\n";
388 cout << " ✓ 2D spatial data (maps, games)\n";
389 cout << " ✓ Range queries (find points in region)\n";
390 cout << " ✓ Nearest neighbor queries\n";
391 cout << " ✓ Collision detection\n";
392 cout << " ✓ k-NN classification\n";
393 cout << "\n4. ADVANTAGES:\n";
394 cout << " * Much faster than linear scan\n";
395 cout << " * Simple to implement\n";
396 cout << " * Low memory overhead\n";
397 cout << " * Good for dynamic data (insert/delete)\n";
398 cout << "\n5. LIMITATIONS:\n";
399 cout << " * Can become unbalanced (worst case O(n))\n";
400 cout << " * Best for random data\n";
401 cout << " * 2D only (use k-d tree for higher dimensions)\n";
402 cout << " * Not cache-friendly (pointer chasing)\n";
403 cout << "\n6. REAL-WORLD APPLICATIONS:\n";
404 cout << " * GIS: Find POIs near location\n";
405 cout << " * Games: Collision detection, AI\n";
406 cout << " * ML: k-NN classification\n";
407 cout << " * Graphics: Ray tracing, culling\n";
408 cout << " * Robotics: Path planning\n";
409 cout << "\n7. ALTERNATIVES:\n";
410 cout << " QuadTree: Better for clustered data\n";
411 cout << " R-Tree: Better for rectangles\n";
412 cout << " Grid: Simpler but less flexible\n";
413 cout << " KD-Tree: Generalization to k dimensions\n";
414 cout << "\n8. BEST PRACTICES:\n";
415 cout << " * Use for uniformly distributed data\n";
416 cout << " * Set appropriate bounding box\n";
417 cout << " * Consider rebalancing for skewed data\n";
418 cout << " * Batch insert for better balance\n";
419
420 return 0;
421}
#define ah_domain_error_if(C)
Throws std::domain_error if condition holds.
Definition ah-errors.H:522
Dynamic singly linked list with functional programming support.
Definition htlist.H:1155
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
static void range(Node *root, const Rectangle &rect, DynList< Point > *q)
Recursively find points within a rectangle.
Definition tpl_2dtree.H:442
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
static mpfr_t y
Definition mpfr_mul_d.c:3
Main namespace for Aleph-w library functions.
Definition ah-arena.H:89
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.
STL namespace.
2D point and geometric utilities.
2D k-d tree implementation for spatial point indexing.
int main()