Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
geom_example.C
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
132#include <iostream>
133#include <iomanip>
134#include <cmath>
135#include <chrono>
136#include <cstring>
137
138#include <geom_algorithms.H>
139#include <tpl_dynArray.H>
140
141using namespace std;
142using namespace Aleph;
143
144// ============================================================================
145// Helper functions
146// ============================================================================
147
148void print_header(const string& title)
149{
150 cout << "\n";
151 cout << "+" << string(70, '-') << "+" << endl;
152 cout << "| " << left << setw(68) << title << " |" << endl;
153 cout << "+" << string(70, '-') << "+" << endl;
154}
155
156void print_subheader(const string& subtitle)
157{
158 cout << "\n " << subtitle << endl;
159 cout << " " << string(subtitle.length(), '-') << endl;
160}
161
165inline double to_double(const Geom_Number& n)
166{
167 return n.get_d();
168}
169
173void print_point(const Point& p, const string& label = "")
174{
175 cout << " ";
176 if (!label.empty()) cout << label << ": ";
177 cout << "(" << fixed << setprecision(2) << to_double(p.get_x())
178 << ", " << to_double(p.get_y()) << ")" << endl;
179}
180
184void print_polygon(const Polygon& poly, const string& name)
185{
186 cout << "\n " << name << " (" << poly.size() << " vertices):" << endl;
187 int i = 0;
188 for (Polygon::Vertex_Iterator it(poly); it.has_curr(); it.next_ne())
189 {
190 const Vertex& v = it.get_current_vertex();
191 cout << " V" << i++ << ": (" << fixed << setprecision(2)
192 << to_double(v.get_x()) << ", " << to_double(v.get_y()) << ")" << endl;
193 }
194}
195
199void print_triangle(const Triangle& t, int index)
200{
201 cout << " T" << index << ": ";
202 const Point& a = t.get_p1();
203 const Point& b = t.get_p2();
204 const Point& c = t.get_p3();
205 cout << "(" << fixed << setprecision(1)
206 << to_double(a.get_x()) << "," << to_double(a.get_y()) << ") - "
207 << "(" << to_double(b.get_x()) << "," << to_double(b.get_y()) << ") - "
208 << "(" << to_double(c.get_x()) << "," << to_double(c.get_y()) << ")" << endl;
209}
210
214double triangle_area(const Triangle& t)
215{
216 const Point& a = t.get_p1();
217 const Point& b = t.get_p2();
218 const Point& c = t.get_p3();
219
220 double ax = to_double(b.get_x()) - to_double(a.get_x());
221 double ay = to_double(b.get_y()) - to_double(a.get_y());
222 double bx = to_double(c.get_x()) - to_double(a.get_x());
223 double by = to_double(c.get_y()) - to_double(a.get_y());
224
225 return 0.5 * abs(ax * by - ay * bx);
226}
227
228// ============================================================================
229// Example 1: Basic Polygon Triangulation
230// ============================================================================
231
233{
234 print_header("Example 1: Polygon Triangulation - Basic Shapes");
235
236 // Create a simple square (represents Plaza de Bolivar, Bogota)
237 print_subheader("Square (Plaza de Bolivar)");
238
239 Polygon square;
240 square.add_vertex(Point(0, 0));
241 square.add_vertex(Point(100, 0));
242 square.add_vertex(Point(100, 100));
243 square.add_vertex(Point(0, 100));
244 square.close();
245
246 print_polygon(square, "Original polygon");
247
250
251 cout << "\n Triangulation result:" << endl;
252 int i = 0;
253 double total_area = 0;
254 for (auto it = triangles.get_it(); it.has_curr(); it.next_ne())
255 {
256 const Triangle& t = it.get_curr();
257 print_triangle(t, i++);
259 }
260
261 cout << "\n Total triangles: " << triangles.size() << endl;
262 cout << " Total area: " << fixed << setprecision(2) << total_area
263 << " square units" << endl;
264 cout << " Expected area: 10000.00 square units" << endl;
265
266 // Create a pentagon (star shape simplified)
267 print_subheader("Pentagon");
268
269 Polygon pentagon;
270 double radius = 50;
271 for (int j = 0; j < 5; ++j)
272 {
273 double angle = 2 * M_PI * j / 5 - M_PI / 2;
274 pentagon.add_vertex(Point(radius * cos(angle), radius * sin(angle)));
275 }
276 pentagon.close();
277
278 print_polygon(pentagon, "Pentagon");
279
281
282 cout << "\n Triangulation result:" << endl;
283 i = 0;
284 total_area = 0;
285 for (auto it = pent_triangles.get_it(); it.has_curr(); it.next_ne())
286 {
287 const Triangle& t = it.get_curr();
288 print_triangle(t, i++);
290 }
291
292 cout << "\n Total triangles: " << pent_triangles.size() << endl;
293 cout << " Total area: " << fixed << setprecision(2) << total_area
294 << " square units" << endl;
295}
296
297// ============================================================================
298// Example 2: Triangulation of Complex Polygon
299// ============================================================================
300
302{
303 print_header("Example 2: Complex Polygon Triangulation");
304
305 // Create an L-shaped polygon (like a building footprint)
306 print_subheader("L-shaped polygon (Building footprint)");
307
309 l_shape.add_vertex(Point(0, 0));
310 l_shape.add_vertex(Point(60, 0));
311 l_shape.add_vertex(Point(60, 40));
312 l_shape.add_vertex(Point(40, 40));
313 l_shape.add_vertex(Point(40, 80));
314 l_shape.add_vertex(Point(0, 80));
315 l_shape.close();
316
317 print_polygon(l_shape, "L-shaped polygon");
318
321
322 cout << "\n Triangulation result:" << endl;
323 int i = 0;
324 double total_area = 0;
325 for (auto it = triangles.get_it(); it.has_curr(); it.next_ne())
326 {
327 const Triangle& t = it.get_curr();
328 print_triangle(t, i++);
330 }
331
332 cout << "\n Total triangles: " << triangles.size() << endl;
333 cout << " Total area: " << fixed << setprecision(2) << total_area
334 << " square units" << endl;
335
336 // Verify: L-shape area = 60*40 + 40*40 = 2400 + 1600 = 4000
337 cout << " Expected area: 4000.00 square units (60x40 + 40x40)" << endl;
338}
339
340// ============================================================================
341// Example 3: Convex Hull - Colombian Cities
342// ============================================================================
343
345{
346 print_header("Example 3: Convex Hull - Colombian Cities");
347
348 // Approximate coordinates of Colombian cities (scaled for visibility)
349 // Using a simplified coordinate system where (0,0) is near Leticia
350
352
353 // Major Colombian cities (approximate positions)
354 struct CityCoord { const char* name; double x; double y; };
356 city_data.append({"Bogota", 74, 44});
357 city_data.append({"Medellin", 75, 61});
358 city_data.append({"Cali", 76, 34});
359 city_data.append({"Barranquilla", 74, 109});
360 city_data.append({"Cartagena", 75, 104});
361 city_data.append({"Cucuta", 72, 77});
362 city_data.append({"Bucaramanga", 73, 71});
363 city_data.append({"Pereira", 75, 47});
364 city_data.append({"Santa Marta", 74, 111});
365 city_data.append({"Ibague", 75, 44});
366 city_data.append({"Pasto", 77, 12});
367 city_data.append({"Manizales", 75, 51});
368 city_data.append({"Villavicencio", 73, 41});
369 city_data.append({"Armenia", 75, 44});
370 city_data.append({"Leticia", 70, 0}); // Amazon
371 city_data.append({"Riohacha", 72, 116}); // La Guajira
372
373 cout << "\n Colombian cities included:" << endl;
374 for (size_t i = 0; i < city_data.size(); ++i)
375 {
376 const auto& c = city_data(i);
377 cout << " " << left << setw(15) << c.name
378 << "(" << c.x << ", " << c.y << ")" << endl;
379 cities.append(Point(c.x, c.y));
380 }
381
382 // Make copies for each algorithm
384 for (auto it = cities.get_it(); it.has_curr(); it.next_ne())
385 {
386 cities_bf.append(it.get_curr());
387 cities_gw.append(it.get_curr());
388 cities_qh.append(it.get_curr());
389 }
390
391 // Test each convex hull algorithm
392 print_subheader("Brute Force Convex Hull O(n^3)");
393
395 auto start = chrono::high_resolution_clock::now();
397 auto end = chrono::high_resolution_clock::now();
398 auto bf_time = chrono::duration_cast<chrono::microseconds>(end - start).count();
399
400 cout << " Hull vertices: " << hull_bf.size() << endl;
401 cout << " Time: " << bf_time << " microseconds" << endl;
402
403 print_subheader("Gift Wrapping Convex Hull O(nh)");
404
406 start = chrono::high_resolution_clock::now();
408 end = chrono::high_resolution_clock::now();
409 auto gw_time = chrono::duration_cast<chrono::microseconds>(end - start).count();
410
411 cout << " Hull vertices: " << hull_gw.size() << endl;
412 cout << " Time: " << gw_time << " microseconds" << endl;
413
414 print_subheader("QuickHull O(n log n) average");
415
417 start = chrono::high_resolution_clock::now();
419 end = chrono::high_resolution_clock::now();
420 auto qh_time = chrono::duration_cast<chrono::microseconds>(end - start).count();
421
422 cout << " Hull vertices: " << hull_qh.size() << endl;
423 cout << " Time: " << qh_time << " microseconds" << endl;
424
425 // Show which cities are on the border
426 print_subheader("Cities on the convex hull (border of Colombia)");
427
428 cout << " The convex hull represents the outermost cities:" << endl;
429 for (Polygon::Vertex_Iterator it(hull_qh); it.has_curr(); it.next_ne())
430 {
431 const Vertex& v = it.get_current_vertex();
432 // Find the city name
433 for (size_t i = 0; i < city_data.size(); ++i)
434 {
435 const auto& c = city_data(i);
436 if (abs(c.x - to_double(v.get_x())) < 0.5 &&
437 abs(c.y - to_double(v.get_y())) < 0.5)
438 {
439 cout << " - " << c.name << endl;
440 break;
441 }
442 }
443 }
444}
445
446// ============================================================================
447// Example 4: Convex Hull - Random Points Performance
448// ============================================================================
449
451{
452 print_header("Example 4: Convex Hull Algorithm Performance");
453
454 cout << "\n Comparing algorithms on random point sets:" << endl;
455 cout << " " << string(60, '-') << endl;
456
458 sizes.append(10);
459 sizes.append(50);
460 sizes.append(100);
461 sizes.append(200);
462
463 cout << "\n " << setw(8) << "Points"
464 << setw(15) << "Brute Force"
465 << setw(15) << "Gift Wrap"
466 << setw(15) << "QuickHull"
467 << setw(10) << "Hull Size" << endl;
468 cout << " " << string(60, '-') << endl;
469
470 for (size_t s = 0; s < sizes.size(); ++s)
471 {
472 int n = sizes(s);
473
474 // Generate random points
476 srand(42); // Fixed seed for reproducibility
477
478 for (int i = 0; i < n; ++i)
479 {
480 double x = (rand() % 1000) / 10.0;
481 double y = (rand() % 1000) / 10.0;
482 points_bf.append(Point(x, y));
483 points_gw.append(Point(x, y));
484 points_qh.append(Point(x, y));
485 }
486
487 // Time each algorithm
491
492 auto start = chrono::high_resolution_clock::now();
494 auto end = chrono::high_resolution_clock::now();
495 auto bf_time = chrono::duration_cast<chrono::microseconds>(end - start).count();
496
497 start = chrono::high_resolution_clock::now();
499 end = chrono::high_resolution_clock::now();
500 auto gw_time = chrono::duration_cast<chrono::microseconds>(end - start).count();
501
502 start = chrono::high_resolution_clock::now();
504 end = chrono::high_resolution_clock::now();
505 auto qh_time = chrono::duration_cast<chrono::microseconds>(end - start).count();
506
507 cout << " " << setw(8) << n
508 << setw(12) << bf_time << " us"
509 << setw(12) << gw_time << " us"
510 << setw(12) << qh_time << " us"
511 << setw(10) << hull_qh.size() << endl;
512 }
513
514 cout << "\n Note: Times in microseconds (us)" << endl;
515 cout << " Brute Force grows as O(n^3)" << endl;
516 cout << " Gift Wrapping grows as O(nh) where h = hull size" << endl;
517 cout << " QuickHull grows as O(n log n) on average" << endl;
518}
519
520// ============================================================================
521// Example 5: Geometric Primitives Demo
522// ============================================================================
523
525{
526 print_header("Example 5: Geometric Primitives");
527
528 print_subheader("Points and Segments");
529
530 // Create some points
531 Point bogota(74, 44);
532 Point medellin(75, 61);
533 Point cali(76, 34);
534
535 cout << " Three major Colombian cities:" << endl;
536 print_point(bogota, "Bogota");
537 print_point(medellin, "Medellin");
538 print_point(cali, "Cali");
539
540 // Create segments (routes)
543
544 cout << "\n Route lengths (approximate):" << endl;
545 cout << " Bogota-Medellin: " << fixed << setprecision(2)
546 << to_double(bogota_medellin.size()) << " units" << endl;
547 cout << " Bogota-Cali: " << to_double(bogota_cali.size())
548 << " units" << endl;
549
550 print_subheader("Point Position Tests");
551
552 Point test_point(73, 50);
553 cout << " Test point: (73, 50)" << endl;
554 cout << " Relative to line Bogota-Medellin:" << endl;
555
556 if (test_point.is_to_left_from(bogota, medellin))
557 cout << " Point is to the LEFT" << endl;
558 else if (test_point.is_to_right_from(bogota, medellin))
559 cout << " Point is to the RIGHT" << endl;
560 else
561 cout << " Point is ON the line" << endl;
562
563 print_subheader("Triangle Operations");
564
565 Triangle triangle(bogota, medellin, cali);
566
567 cout << " Triangle formed by Bogota, Medellin, Cali:" << endl;
568 cout << " Area: " << fixed << setprecision(2)
569 << triangle_area(triangle) << " square units" << endl;
570
571 // Check points inside/outside using contains_to
572 Point inside(75, 45); // Somewhere in the middle
573 Point outside(80, 80); // Outside
574
575 cout << "\n Point containment:" << endl;
576 cout << " Point (75, 45): ";
577 if (triangle.contains_to(inside))
578 cout << "INSIDE the triangle" << endl;
579 else
580 cout << "OUTSIDE the triangle" << endl;
581
582 cout << " Point (80, 80): ";
583 if (triangle.contains_to(outside))
584 cout << "INSIDE the triangle" << endl;
585 else
586 cout << "OUTSIDE the triangle" << endl;
587}
588
589// ============================================================================
590// Example 6: Practical Application - Coverage Area
591// ============================================================================
592
594{
595 print_header("Example 6: Coverage Area Calculation");
596
597 cout << "\n Scenario: Calculate coverage area of cell towers" << endl;
598 cout << " " << string(50, '-') << endl;
599
600 // Cell tower locations (representing a region in Colombia)
602 towers.append(Point(0, 0));
603 towers.append(Point(30, 10));
604 towers.append(Point(50, 0));
605 towers.append(Point(55, 25));
606 towers.append(Point(45, 50));
607 towers.append(Point(20, 55));
608 towers.append(Point(5, 40));
609 towers.append(Point(25, 30)); // Interior tower
610 towers.append(Point(35, 25)); // Interior tower
611
612 cout << "\n Tower locations:" << endl;
613 int tower_num = 1;
614 for (auto it = towers.get_it(); it.has_curr(); it.next_ne())
615 {
616 const Point& p = it.get_curr();
617 cout << " Tower " << tower_num++ << ": ("
618 << to_double(p.get_x()) << ", "
619 << to_double(p.get_y()) << ")" << endl;
620 }
621
622 // Calculate convex hull (coverage boundary)
625
626 cout << "\n Coverage boundary (convex hull):" << endl;
627 cout << " Boundary towers: " << coverage.size() << endl;
628 cout << " Interior towers: " << (9 - coverage.size()) << endl;
629
630 // Calculate coverage area using triangulation
631 Polygon coverage_copy = coverage; // triangulation consumes the polygon
634
635 double total_area = 0;
636 for (auto it = triangles.get_it(); it.has_curr(); it.next_ne())
637 total_area += triangle_area(it.get_curr());
638
639 cout << "\n Coverage statistics:" << endl;
640 cout << " Total coverage area: " << fixed << setprecision(2)
641 << total_area << " square km" << endl;
642 cout << " Triangles in mesh: " << triangles.size() << endl;
643
644 // Perimeter calculation
645 double perimeter = 0;
646 for (Polygon::Segment_Iterator it(coverage); it.has_curr(); it.next_ne())
647 {
648 const Segment& seg = it.get_current_segment();
650 }
651
652 cout << " Perimeter: " << perimeter << " km" << endl;
653 cout << " Compactness ratio: " << (4 * M_PI * total_area) / (perimeter * perimeter)
654 << " (1.0 = circle)" << endl;
655}
656
657// ============================================================================
658// Main
659// ============================================================================
660
661static void usage(const char* prog)
662{
663 cout << "Usage: " << prog << " [-s <triangulation|convexhull|all>] [--help]\n";
664 cout << "\nIf no selector is given, all demos are executed.\n";
665}
666
667int main(int argc, char* argv[])
668{
669 string section = "all";
670 for (int i = 1; i < argc; ++i)
671 {
672 const string arg = argv[i];
673 if (arg == "--help" || arg == "-h")
674 {
675 usage(argv[0]);
676 return 0;
677 }
678 if (arg == "-s")
679 {
680 if (i + 1 >= argc)
681 {
682 usage(argv[0]);
683 return 1;
684 }
685 section = argv[++i];
686 continue;
687 }
688
689 cout << "Unknown argument: " << arg << "\n";
690 usage(argv[0]);
691 return 1;
692 }
693
694 cout << "\n";
695 cout << "========================================================================" << endl;
696 cout << " ALEPH-W COMPUTATIONAL GEOMETRY EXAMPLE" << endl;
697 cout << " Triangulation and Convex Hull Algorithms" << endl;
698 cout << "========================================================================" << endl;
699
700 if (section == "all" || section == "triangulation")
701 {
704 }
705
706 if (section == "all" || section == "convexhull")
707 {
710 }
711
712 if (section == "all")
713 {
716 }
717
718 if (!(section == "all" || section == "triangulation" || section == "convexhull"))
719 {
720 cout << "Unknown section: " << section << "\n";
721 usage(argv[0]);
722 return 1;
723 }
724
725 cout << "\n";
726 cout << "========================================================================" << endl;
727 cout << " Example completed successfully!" << endl;
728 cout << "========================================================================" << endl;
729 cout << endl;
730
731 return 0;
732}
int main()
Brute force convex hull algorithm.
Polygon triangulation using the ear-cutting algorithm.
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
Gift wrapping (Jarvis march) convex hull algorithm.
size_t size() const noexcept
Count the number of elements of the list.
Definition htlist.H:1319
QuickHull convex hull algorithm.
size_t length() const noexcept
Count the number of elements of a container.
Definition ah-dry.H:1385
auto get_it() const
Return a properly initialized iterator positioned at the first item on the container.
Definition ah-dry.H:190
Rectangular point in the plane.
Definition point.H:156
const Geom_Number & get_y() const
Returns y value.
Definition point.H:226
const Geom_Number & get_x() const
Returns x value.
Definition point.H:221
Iterator over the edges (segments) of a polygon.
Definition polygon.H:451
bool has_curr() const
Check if there is a current segment.
Definition polygon.H:468
A general (irregular) 2D polygon defined by a sequence of vertices.
Definition polygon.H:233
void close()
Close the polygon.
Definition polygon.H:710
const size_t & size() const
Get the number of vertices.
Definition polygon.H:407
void add_vertex(const Point &point)
Add a vertex to the polygon.
Definition polygon.H:610
Fundamental segment defined by two points.
Definition point.H:417
const Point & get_p1() const
Definition point.H:970
const Point & get_p3() const
Definition point.H:974
bool contains_to(const Point &p) const
Returns true if point p lies inside this triangle.
Definition point.H:977
const Point & get_p2() const
Definition point.H:972
A vertex in a polygon's doubly-linked vertex list.
Definition polygon.H:113
Computational geometry algorithms.
void print_polygon(const Polygon &poly, const string &name)
Print a polygon's vertices.
void demo_convex_hull_performance()
void demo_triangulation_complex()
void demo_coverage_area()
void print_point(const Point &p, const string &label="")
Print a point with optional label.
static void usage(const char *prog)
void demo_triangulation_basic()
void print_triangle(const Triangle &t, int index)
Print a triangle.
void print_subheader(const string &subtitle)
void demo_convex_hull_cities()
double triangle_area(const Triangle &t)
Calculate area of a triangle using cross product.
double to_double(const Geom_Number &n)
Convert Geom_Number to double.
void demo_geometric_primitives()
__gmp_expr< T, __gmp_unary_expr< __gmp_expr< T, U >, __gmp_cos_function > > cos(const __gmp_expr< T, U > &expr)
Definition gmpfrxx.h:4069
__gmp_expr< T, __gmp_unary_expr< __gmp_expr< T, U >, __gmp_sin_function > > sin(const __gmp_expr< T, U > &expr)
Definition gmpfrxx.h:4070
__gmp_expr< T, __gmp_unary_expr< __gmp_expr< T, U >, __gmp_abs_function > > abs(const __gmp_expr< T, U > &expr)
Definition gmpfrxx.h:4051
static mpfr_t y
Definition mpfr_mul_d.c:3
Main namespace for Aleph-w library functions.
Definition ah-arena.H:89
DynList< T > maps(const C &c, Op op)
Classic map operation.
STL namespace.
void print_header()
Iterator over the vertices of a polygon.
Definition polygon.H:419
Lazy and scalable dynamic array implementation.