Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
geom_algorithms.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
101# ifndef GEOM_ALGORITHMS_H
102# define GEOM_ALGORITHMS_H
103
104# include <polygon.H>
105# include <htlist.H>
106# include <tpl_dynSetTree.H>
107# include <tpl_sort_utils.H>
108# include <ah-errors.H>
109
110namespace Aleph
111{
112
113// ============================================================================
114// Triangulation Algorithms
115// ============================================================================
116
169{
171
172public:
173
184 static bool diagonalie(const Polygon & p, const Segment & s)
185 {
186 for (Polygon::Segment_Iterator it(p); it.has_curr(); it.next_ne())
187 {
188 if (Segment curr = it.get_current_segment();
189 (curr.get_src_point() != s.get_src_point()) and
190 (curr.get_tgt_point() != s.get_src_point()) and
191 (curr.get_src_point() != s.get_tgt_point()) and
192 (curr.get_tgt_point() != s.get_tgt_point()) and
193 s.intersects_with(curr))
194 return false;
195 }
196 return true;
197 }
198
209 static bool in_cone(const Polygon & p, const Vertex & a, const Vertex & b)
210 {
211 // a0 -> a -> a1 are consecutive vertices
212 const Vertex & a0 = p.get_prev_vertex(a);
213 const Vertex & a1 = p.get_next_vertex(a);
214
215 if (a0.is_to_left_on_from(a, a1))
216 return a0.is_to_left_from(a, b) and a1.is_to_left_from(b, a);
217
218 return not (a1.is_to_left_on_from(a, b) and
219 a0.is_to_left_on_from(b, a));
220 }
221
230 static bool diagonal(const Polygon & p, const Vertex & a, const Vertex & b)
231 {
232 return in_cone(p, a, b) and in_cone(p, b, a) and
233 diagonalie(p, Segment(a, b));
234 }
235
242 static EarsSet init_ears(const Polygon & p)
243 {
244 EarsSet ret;
245
246 for (Polygon::Vertex_Iterator it(p); it.has_curr(); it.next_ne())
247 {
248 Vertex & curr = it.get_current_vertex();
249 const Vertex & prev = p.get_prev_vertex(curr);
250 const Vertex & next = p.get_next_vertex(curr);
251 if (diagonal(p, prev, next))
252 ret.insert(&curr);
253 }
254
255 return ret;
256 }
257
258public:
259
271 {
272 ah_domain_error_if(p.size() < 3) << "Polygon has less than 3 vertices";
273
275
277
278 while (p.size() > 3)
279 {
280 const Vertex *curr = ears.remove_pos(0);
281
282 const Vertex & prev = p.get_prev_vertex(*curr);
283 const Vertex & prev_prev = p.get_prev_vertex(prev);
284 const Vertex & next = p.get_next_vertex(*curr);
286
287 if (diagonal(p, prev_prev, next))
288 ears.insert(&prev);
289 else
290 ears.remove(&prev);
291
292 if (diagonal(p, prev, next_next))
293 ears.insert(&next);
294 else
295 ears.remove(&next);
296
297 ret.append(Triangle(prev, *curr, next));
298
299 p.remove_vertex(*curr);
300 }
301
302 assert(p.size() == 3);
303
304 const Vertex & a = p.get_first_vertex();
305 const Vertex & b = a.next_vertex();
306 const Vertex & c = b.next_vertex();
307
308 ret.append(Triangle(a, b, c));
309
310 return ret;
311 }
312};
313
314// ============================================================================
315// Convex Hull Algorithms
316// ============================================================================
317
348{
350 {
351 bool cmp_point(const Point & p1, const Point & p2) const
352 {
353 if (p1.get_x() < p2.get_x())
354 return true;
355
356 return not (p2.get_x() < p1.get_x()) and p1.get_y() < p2.get_y();
357 }
358
359 bool operator ()(const Segment & s1, const Segment & s2)
360 {
361 if (cmp_point(s1.get_src_point(), s2.get_src_point()))
362 return true;
363
364 return not (cmp_point(s2.get_src_point(), s1.get_src_point())) and
365 cmp_point(s1.get_tgt_point(), s2.get_tgt_point());
366 }
367 };
368
371
373 {
374 for (PointIt it(l); it.has_curr(); it.next_ne())
375 {
376 const Point & p = it.get_curr();
377
378 if (p.is_to_right_from(s))
379 return false;
380 }
381
382 return true;
383 }
384
386 {
388
389 for (PointIt i(point_set); i.has_curr(); i.next_ne())
390 {
391 const Point & p_i = i.get_curr();
392
393 for (PointIt j(point_set); j.has_curr(); j.next_ne())
394 {
395 const Point & p_j = j.get_curr();
396
397 if (p_i == p_j)
398 continue;
399
400 Segment s(p_i, p_j);
401
403 ret.insert(s);
404 }
405 }
406
407 return ret;
408 }
409
410public:
411
419 {
420 Polygon ret;
421
423
424 Segment first_segment = extremes.remove_pos(0);
425 ret.add_vertex(first_segment.get_src_point());
426 ret.add_vertex(first_segment.get_tgt_point());
427
428 while (true)
429 {
430 const Vertex & last_vertex = ret.get_last_vertex();
431
432 Segment *ptr = extremes.find_ptr([&last_vertex](const Segment & s)
433 {
434 return s.get_src_point() == last_vertex;
435 });
436
437 assert(ptr != nullptr);
438
439 if (ptr->get_tgt_point() == ret.get_first_vertex())
440 break;
441
442 ret.add_vertex(ptr->get_tgt_point());
443
444 extremes.remove(*ptr);
445 }
446
447 ret.close();
448 return ret;
449 }
450};
451
482{
484 {
486 Point *ret = &it.get_curr();
487 it.next();
488
489 for (/* nothing */; it.has_curr(); it.next_ne())
490 {
491 Point & p = it.get_curr();
492
493 if (p.get_y() < ret->get_y())
494 ret = &p;
495 }
496
497 return ret;
498 }
499
500public:
501
509 {
510 Polygon ret;
511
512 Point *lowest_point = get_lowest_point(point_set);
513 Point *p_i = lowest_point;
514 ret.add_vertex(*lowest_point);
515
516 Segment last_segment = Segment(Point(0, 0), Point(1, 0));
517
518 while (true)
519 {
520 Point *p_k = nullptr;
521
522 double min_angle = std::numeric_limits<double>::max();
523
524 for (DynList<Point>::Iterator it(point_set); it.has_curr(); it.next_ne())
525 {
526 Point & p_j = it.get_curr();
527
528 if (p_j == *p_i)
529 continue;
530
531 double angle =
533
534 if (angle < min_angle)
535 {
536 min_angle = angle;
537 p_k = &p_j;
538 }
539 }
540
541 assert(p_k != nullptr);
542
543 if (p_k == lowest_point)
544 break;
545
546 ret.add_vertex(*p_k);
547
548 last_segment = ret.get_last_segment();
549
550 p_i = p_k;
551 }
552
553 ret.close();
554 return ret;
555 }
556};
557
587{
589 {
591 Point ret;
592
593 for (DynList<Point>::Iterator it(point_set); it.has_curr(); it.next_ne())
594 {
595 const Point & p = it.get_curr();
596
598
599 Geom_Number sz = s1.size();
600
601 if (sz > max_distance)
602 {
603 ret = p;
604 max_distance = sz;
605 }
606 }
607
608 return ret;
609 }
610
611 std::pair<DynList<Point>, DynList<Point>>
613 const Point & a, const Point & b, const Point & c)
614 {
615 std::pair<DynList<Point>, DynList<Point>> ret;
616
617 while (not point_set.is_empty())
618 {
619 Point p = point_set.remove_first();
620
621 if (p != a and p != c and p.is_to_right_from(a, c))
622 {
623 ret.first.append(p);
624 continue;
625 }
626
627 if (p != c and p != b and p.is_to_right_from(c, b))
628 ret.second.append(p);
629 }
630
631 return ret;
632 }
633
635 const Point & b)
636 {
637 if (point_set.is_empty())
638 return DynList<Point>();
639
640 Point c = get_fartest_point(point_set, Segment(a, b));
641
642 auto r = get_right_points(point_set, a, b, c);
643
644 DynList<Point> ret = quick_hull(r.first, a, c);
645 DynList<Point> tmp = quick_hull(r.second, c, b);
646 ret.append(c);
647 ret.concat(tmp);
648
649 return ret;
650 }
651
652 std::pair<Point, Point> search_extremes(DynList<Point> & point_set)
653 {
655 Point leftmost = it.get_curr();
656 Point rightmost = it.get_curr();
657 it.next();
658
659 for (/* nothing */; it.has_curr(); it.next_ne())
660 {
661 const Point & p = it.get_curr();
662
663 if (p.get_x() < leftmost.get_x())
664 leftmost = p;
665
666 if (p.get_x() > rightmost.get_x())
667 rightmost = p;
668 }
669
670 return std::make_pair(leftmost, rightmost);
671 }
672
673 std::pair<DynList<Point>, DynList<Point>>
674 partition(DynList<Point> & point_set, const Point & a, const Point & b)
675 {
676 std::pair<DynList<Point>, DynList<Point>> ret;
677
678 for (DynList<Point>::Iterator it(point_set); it.has_curr(); it.next_ne())
679 {
680 const Point & p = it.get_curr();
681
682 if (p.is_to_right_from(a, b))
683 ret.first.append(p);
684 else
685 ret.second.append(p);
686 }
687
688 return ret;
689 }
690
691public:
692
700 {
701 Polygon ret;
702
703 auto e = search_extremes(point_set);
704 auto p = partition(point_set, e.first, e.second);
705
706 DynList<Point> s1 = quick_hull(p.first, e.first, e.second);
707 DynList<Point> s2 = quick_hull(p.second, e.second, e.first);
708
710 convex_set.append(e.first);
712 convex_set.append(e.second);
714
715 for (DynList<Point>::Iterator it(convex_set); it.has_curr(); it.next_ne())
716 ret.add_vertex(it.get_curr());
717
718 ret.close();
719 return ret;
720 }
721};
722
723} // namespace Aleph
724
725# endif // GEOM_ALGORITHMS_H
Exception handling system with formatted messages for Aleph-w.
#define ah_domain_error_if(C)
Throws std::domain_error if condition holds.
Definition ah-errors.H:522
Brute force convex hull algorithm.
DynList< Point >::Iterator PointIt
Polygon operator()(DynList< Point > &point_set)
Compute the convex hull of a point set.
bool are_all_points_on_left(DynList< Point > &l, const Segment &s)
SegmentSet extreme_edges(DynList< Point > &point_set)
Polygon triangulation using the ear-cutting algorithm.
static bool diagonalie(const Polygon &p, const Segment &s)
Check if a segment is a valid diagonal of the polygon.
static bool diagonal(const Polygon &p, const Vertex &a, const Vertex &b)
Check if segment (a, b) is a valid internal diagonal.
DynList< Triangle > operator()(Polygon &p)
Triangulate the polygon.
static EarsSet init_ears(const Polygon &p)
Initialize the set of ear vertices.
static bool in_cone(const Polygon &p, const Vertex &a, const Vertex &b)
Check if vertex b is inside the cone formed at vertex a.
Iterator on the items of list.
Definition htlist.H:1714
T & get_curr() const
Return the current item.
Definition htlist.H:1740
Dynamic singly linked list with functional programming support.
Definition htlist.H:1423
T & insert(const T &item)
Insert a new item by copy.
Definition htlist.H:1502
T & append(const T &item)
Append a new item by copy.
Definition htlist.H:1562
T remove()
Remove the first item of the list.
Definition htlist.H:1611
Dynamic set backed by balanced binary search trees with automatic memory management.
Gift wrapping (Jarvis march) convex hull algorithm.
Point * get_lowest_point(DynList< Point > &point_set)
Polygon operator()(DynList< Point > &point_set)
Compute the convex hull of a point set.
void next_ne() noexcept
Move the iterator one position forward guaranteeing no exception.
Definition htlist.H:1190
void next()
Move the iterator one item forward.
Definition htlist.H:1222
bool has_curr() const noexcept
Return true if iterator has current item.
Definition htlist.H:1150
constexpr bool is_empty() const noexcept
Return true if list is empty.
Definition htlist.H:523
size_t size() const noexcept
Count the number of elements of the list.
Definition htlist.H:1319
void concat(HTList &l) noexcept
Concat to 'this' all 'l' list; 'l' becomes empty.
Definition htlist.H:660
QuickHull convex hull algorithm.
std::pair< Point, Point > search_extremes(DynList< Point > &point_set)
Polygon operator()(DynList< Point > &point_set)
Compute the convex hull of a point set.
std::pair< DynList< Point >, DynList< Point > > get_right_points(DynList< Point > &point_set, const Point &a, const Point &b, const Point &c)
DynList< Point > quick_hull(DynList< Point > &point_set, const Point &a, const Point &b)
std::pair< DynList< Point >, DynList< Point > > partition(DynList< Point > &point_set, const Point &a, const Point &b)
Point get_fartest_point(DynList< Point > &point_set, const Segment &s)
Type * find_ptr(Operation &operation) noexcept(operation_is_noexcept< Operation >())
Find a pointer to an item in the container according to a searching criteria.
Definition ah-dry.H:318
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 remove_vertex(const Vertex &v)
Remove a vertex from the polygon.
Definition polygon.H:680
const Vertex & get_next_vertex(const Vertex &v) const
Get the vertex after the given vertex.
Definition polygon.H:533
const size_t & size() const
Get the number of vertices.
Definition polygon.H:407
const Vertex & get_first_vertex() const
Get the first vertex of the polygon.
Definition polygon.H:510
const Vertex & get_prev_vertex(const Vertex &v) const
Get the vertex before the given vertex.
Definition polygon.H:545
Fundamental segment defined by two points.
Definition point.H:417
const Point & get_tgt_point() const
Definition point.H:470
Segment get_perpendicular(const Point &p) const
Construct the segment perpendicular to this passing through p.
Definition point.H:618
double counterclockwise_angle_with(const Segment &s) const
Compute the counterclockwise wise angle respect another segment s.
Definition point.H:550
bool intersects_with(const Segment &s) const
Return true if s intersects this segment (including endpoints).
Definition point.H:713
const Point & get_src_point() const
Definition point.H:468
A vertex in a polygon's doubly-linked vertex list.
Definition polygon.H:113
const Vertex & next_vertex() const
Get the next vertex in the polygon.
Definition polygon.H:179
Singly linked list implementations with head-tail access.
Main namespace for Aleph-w library functions.
Definition ah-arena.H:89
void next()
Advance all underlying iterators (bounds-checked).
Definition ah-zip.H:175
DynList< T > maps(const C &c, Op op)
Classic map operation.
2D polygon representation and geometric operations.
bool operator()(const Segment &s1, const Segment &s2)
bool cmp_point(const Point &p1, const Point &p2) const
Iterator over the vertices of a polygon.
Definition polygon.H:419
Dynamic set implementations based on balanced binary search trees.
Comprehensive sorting algorithms and search utilities for Aleph-w.
DynList< int > l