Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
polygon_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
46#include <gtest/gtest.h>
47#include <cmath>
48#include <limits>
49#include <vector>
50#include <polygon.H>
51
52using namespace Aleph;
53
54// Tolerance for floating-point comparisons
55constexpr double EPSILON = 1e-6;
56
57// Helper to compare Geom_Number with tolerance
58bool approx_equal(const Geom_Number & a, const Geom_Number & b,
59 double tol = EPSILON)
60{
61 return std::abs(a.get_d() - b.get_d()) < tol;
62}
63
64// Helper to compare Points
65bool points_equal(const Point & a, const Point & b, double tol = EPSILON)
66{
67 return approx_equal(a.get_x(), b.get_x(), tol) &&
68 approx_equal(a.get_y(), b.get_y(), tol);
69}
70
71//============================================================================
72// Vertex Class Tests
73//============================================================================
74
75class VertexTest : public ::testing::Test
76{
77protected:
78 void SetUp() override
79 {
80 p1 = Point(10, 20);
81 p2 = Point(30, 40);
82 }
83
85};
86
88{
89 Vertex v;
90 EXPECT_EQ(v.get_x(), 0);
91 EXPECT_EQ(v.get_y(), 0);
92}
93
95{
96 Vertex v(p1);
97 EXPECT_EQ(v.get_x(), p1.get_x());
98 EXPECT_EQ(v.get_y(), p1.get_y());
99}
100
102{
103 Vertex v1(p1);
104 Vertex v2(v1);
105
106 EXPECT_EQ(v2.get_x(), v1.get_x());
107 EXPECT_EQ(v2.get_y(), v1.get_y());
108}
109
111{
112 Vertex v1(p1);
113 Vertex v2(p2);
114
115 v2 = v1;
116
117 EXPECT_EQ(v2.get_x(), v1.get_x());
118 EXPECT_EQ(v2.get_y(), v1.get_y());
119}
120
122{
123 Vertex v(p1);
124 v = v;
125
126 EXPECT_EQ(v.get_x(), p1.get_x());
127 EXPECT_EQ(v.get_y(), p1.get_y());
128}
129
131{
132 Vertex v(p1);
133 Point p = v.to_point();
134
135 EXPECT_EQ(p.get_x(), p1.get_x());
136 EXPECT_EQ(p.get_y(), p1.get_y());
137}
138
140{
141 Vertex v(p1);
142 Dlink * link = &v;
143
145 EXPECT_EQ(recovered, &v);
146 EXPECT_EQ(recovered->get_x(), p1.get_x());
147}
148
150{
151 const Vertex v(p1);
152 const Dlink * link = &v;
153
155 EXPECT_EQ(recovered, &v);
156 EXPECT_EQ(recovered->get_x(), p1.get_x());
157}
158
159//============================================================================
160// Polygon Construction Tests
161//============================================================================
162
163class PolygonConstructionTest : public ::testing::Test
164{
165protected:
167 {
168 Polygon poly;
169 poly.add_vertex(Point(0, 0));
170 poly.add_vertex(Point(100, 0));
171 poly.add_vertex(Point(100, 100));
172 poly.add_vertex(Point(0, 100));
173 poly.close();
174 return poly;
175 }
176
178 {
179 Polygon poly;
180 poly.add_vertex(Point(0, 0));
181 poly.add_vertex(Point(100, 0));
182 poly.add_vertex(Point(50, 100));
183 poly.close();
184 return poly;
185 }
186};
187
194
196{
197 Polygon poly;
198 poly.add_vertex(Point(10, 20));
199
200 EXPECT_EQ(poly.size(), 1u);
201 EXPECT_FALSE(poly.is_closed());
202}
203
205{
206 Polygon poly;
207 poly.add_vertex(Point(0, 0));
208 poly.add_vertex(Point(100, 0));
209 poly.add_vertex(Point(100, 100));
210
211 EXPECT_EQ(poly.size(), 3u);
212 EXPECT_FALSE(poly.is_closed());
213}
214
216{
217 Polygon poly = create_triangle();
218
219 EXPECT_EQ(poly.size(), 3u);
220 EXPECT_TRUE(poly.is_closed());
221}
222
224{
225 Polygon empty;
226 EXPECT_THROW(empty.close(), std::domain_error);
227
230 EXPECT_THROW(one_vertex.close(), std::domain_error);
231
234 two_vertices.add_vertex(Point(100, 0));
235 EXPECT_THROW(two_vertices.close(), std::domain_error);
236}
237
239{
240 Polygon poly = create_triangle();
241
242 EXPECT_THROW(poly.add_vertex(Point(50, 50)), std::domain_error);
243}
244
246{
247 Polygon poly = create_triangle();
248
249 EXPECT_THROW(poly.close(), std::domain_error);
250}
251
253{
254 Polygon original = create_square();
256
257 EXPECT_EQ(copy.size(), original.size());
258 EXPECT_EQ(copy.is_closed(), original.is_closed());
259 EXPECT_TRUE(points_equal(copy.lowest_point(), original.lowest_point()));
260}
261
263{
264 Polygon original = create_square();
265 size_t orig_size = original.size();
266
267 Polygon moved(std::move(original));
268
269 EXPECT_EQ(moved.size(), orig_size);
270 EXPECT_TRUE(moved.is_closed());
271 EXPECT_EQ(original.size(), 0u); // NOLINT - testing moved-from state
272}
273
275{
276 Polygon poly1 = create_square();
278
279 poly2 = poly1;
280
281 EXPECT_EQ(poly2.size(), poly1.size());
282 EXPECT_EQ(poly2.is_closed(), poly1.is_closed());
283}
284
286{
287 Polygon poly1 = create_square();
288 size_t orig_size = poly1.size();
290
291 poly2 = std::move(poly1);
292
293 EXPECT_EQ(poly2.size(), orig_size);
294 EXPECT_TRUE(poly2.is_closed());
295}
296
298{
299 Polygon poly = create_square();
300 poly = poly;
301
302 EXPECT_EQ(poly.size(), 4u);
303 EXPECT_TRUE(poly.is_closed());
304}
305
307{
308 Polygon poly;
309 poly.add_vertex(Geom_Number(50), Geom_Number(75));
310
311 EXPECT_EQ(poly.size(), 1u);
312 EXPECT_EQ(poly.get_first_vertex().get_x(), 50);
313 EXPECT_EQ(poly.get_first_vertex().get_y(), 75);
314}
315
316//============================================================================
317// Polygon Extreme Points Tests
318//============================================================================
319
320class PolygonExtremePointsTest : public ::testing::Test {};
321
323{
324 Polygon poly;
325 poly.add_vertex(Point(50, 75));
326
327 EXPECT_EQ(poly.lowest_point().get_x(), 50);
328 EXPECT_EQ(poly.lowest_point().get_y(), 75);
329 EXPECT_EQ(poly.highest_point().get_y(), 75);
330 EXPECT_EQ(poly.leftmost_point().get_x(), 50);
331 EXPECT_EQ(poly.rightmost_point().get_x(), 50);
332}
333
335{
336 Polygon poly;
337 poly.add_vertex(Point(10, 20));
338 poly.add_vertex(Point(100, 5));
339 poly.add_vertex(Point(50, 150));
340 poly.add_vertex(Point(-20, 80));
341
342 EXPECT_EQ(poly.lowest_point().get_y(), 5);
343 EXPECT_EQ(poly.highest_point().get_y(), 150);
344 EXPECT_EQ(poly.leftmost_point().get_x(), -20);
345 EXPECT_EQ(poly.rightmost_point().get_x(), 100);
346}
347
349{
350 Polygon poly;
351 poly.add_vertex(Point(-100, -100));
352 poly.add_vertex(Point(100, -100));
353 poly.add_vertex(Point(100, 100));
354 poly.add_vertex(Point(-100, 100));
355
356 EXPECT_EQ(poly.lowest_point().get_y(), -100);
357 EXPECT_EQ(poly.highest_point().get_y(), 100);
358 EXPECT_EQ(poly.leftmost_point().get_x(), -100);
359 EXPECT_EQ(poly.rightmost_point().get_x(), 100);
360}
361
362//============================================================================
363// Polygon Vertex Access Tests
364//============================================================================
365
366class PolygonVertexAccessTest : public ::testing::Test
367{
368protected:
369 void SetUp() override
370 {
371 poly.add_vertex(Point(0, 0));
372 poly.add_vertex(Point(100, 0));
373 poly.add_vertex(Point(100, 100));
374 poly.add_vertex(Point(0, 100));
375 }
376
378};
379
381{
382 const Vertex & first = poly.get_first_vertex();
383 EXPECT_EQ(first.get_x(), 0);
384 EXPECT_EQ(first.get_y(), 0);
385}
386
388{
389 const Vertex & last = poly.get_last_vertex();
390 EXPECT_EQ(last.get_x(), 0);
391 EXPECT_EQ(last.get_y(), 100);
392}
393
399
405
407{
408 const Vertex & first = poly.get_first_vertex();
409 EXPECT_TRUE(poly.vertex_belong_polygon(first));
410}
411
413{
414 Vertex external(Point(999, 999));
415 EXPECT_FALSE(poly.vertex_belong_polygon(external));
416}
417
419{
420 const Vertex & first = poly.get_first_vertex();
421 const Vertex & next = poly.get_next_vertex(first);
422
423 EXPECT_EQ(next.get_x(), 100);
424 EXPECT_EQ(next.get_y(), 0);
425}
426
428{
429 const Vertex & last = poly.get_last_vertex();
430 const Vertex & prev = poly.get_prev_vertex(last);
431
432 EXPECT_EQ(prev.get_x(), 100);
433 EXPECT_EQ(prev.get_y(), 100);
434}
435
436//============================================================================
437// Polygon Segment Access Tests
438//============================================================================
439
440class PolygonSegmentAccessTest : public ::testing::Test
441{
442protected:
443 void SetUp() override
444 {
445 poly.add_vertex(Point(0, 0));
446 poly.add_vertex(Point(100, 0));
447 poly.add_vertex(Point(100, 100));
448 }
449
451};
452
454{
455 Segment first = poly.get_first_segment();
456
458 EXPECT_TRUE(points_equal(first.get_tgt_point(), Point(100, 0)));
459}
460
462{
463 Segment last = poly.get_last_segment();
464
466 EXPECT_TRUE(points_equal(last.get_tgt_point(), Point(100, 100)));
467}
468
470{
472 single.add_vertex(Point(0, 0));
473
474 EXPECT_THROW(single.get_first_segment(), std::domain_error);
475}
476
482
483//============================================================================
484// Polygon Vertex Iterator Tests
485//============================================================================
486
487class PolygonVertexIteratorTest : public ::testing::Test
488{
489protected:
490 void SetUp() override
491 {
492 poly.add_vertex(Point(0, 0));
493 poly.add_vertex(Point(100, 0));
494 poly.add_vertex(Point(100, 100));
495 poly.add_vertex(Point(0, 100));
496 }
497
499};
500
502{
503 size_t count = 0;
504 for (Polygon::Vertex_Iterator it(poly); it.has_curr(); it.next_ne())
505 ++count;
506
507 EXPECT_EQ(count, 4u);
508}
509
518
520{
521 Polygon empty;
522 EXPECT_THROW(Polygon::Vertex_Iterator it(empty), std::domain_error);
523}
524
525//============================================================================
526// Polygon Segment Iterator Tests
527//============================================================================
528
529class PolygonSegmentIteratorTest : public ::testing::Test
530{
531protected:
532 void SetUp() override
533 {
534 poly.add_vertex(Point(0, 0));
535 poly.add_vertex(Point(100, 0));
536 poly.add_vertex(Point(100, 100));
537 poly.add_vertex(Point(0, 100));
538 }
539
541};
542
544{
545 // poly is not closed, so 4 vertices = 3 segments
546 size_t count = 0;
547 for (Polygon::Segment_Iterator it(poly); it.has_curr(); it.next_ne())
548 ++count;
549
550 EXPECT_EQ(count, 3u);
551}
552
554{
555 poly.close();
556
557 size_t count = 0;
558 for (Polygon::Segment_Iterator it(poly); it.has_curr(); it.next_ne())
559 ++count;
560
561 EXPECT_EQ(count, 4u);
562}
563
572
578
586
587//============================================================================
588// Polygon Intersection Tests
589//============================================================================
590
591class PolygonIntersectionTest : public ::testing::Test
592{
593protected:
594 void SetUp() override
595 {
596 square.add_vertex(Point(0, 0));
597 square.add_vertex(Point(100, 0));
598 square.add_vertex(Point(100, 100));
599 square.add_vertex(Point(0, 100));
600 square.close();
601 }
602
604};
605
607{
608 Segment cross(Point(-50, 50), Point(150, 50));
609 EXPECT_TRUE(square.intersects_with(cross));
610}
611
613{
614 Segment outside(Point(200, 0), Point(200, 100));
615 EXPECT_FALSE(square.intersects_with(outside));
616}
617
619{
620 Segment inside(Point(25, 25), Point(75, 75));
621 EXPECT_FALSE(square.intersects_with(inside));
622}
623
624//============================================================================
625// Polygon Self-Intersection Prevention Tests
626//============================================================================
627
628class PolygonSelfIntersectionTest : public ::testing::Test {};
629
631{
632 Polygon poly;
634 poly.add_vertex(Point(0, 0));
635 poly.add_vertex(Point(100, 0));
636 poly.add_vertex(Point(100, 100));
637 poly.add_vertex(Point(0, 100));
638 poly.close();
639 });
640}
641
643{
644 Polygon poly;
645 poly.add_vertex(Point(0, 0));
646 poly.add_vertex(Point(100, 0));
647 poly.add_vertex(Point(100, 100));
648 poly.add_vertex(Point(0, 100));
649
650 // Adding a vertex that would create a crossing edge
651 EXPECT_THROW(poly.add_vertex(Point(150, -50)), std::domain_error);
652}
653
655{
656 // Create a polygon where adding a vertex causes self-intersection
657 // Shape: Start at (0,0), go right to (100,0), up to (100,100),
658 // then diagonally down-left toward (-50, 50)
659 Polygon poly;
660 poly.add_vertex(Point(0, 0));
661 poly.add_vertex(Point(100, 0));
662 poly.add_vertex(Point(100, 100));
663 poly.add_vertex(Point(-50, 50));
664
665 // Adding (50, -50) would create an edge from (-50, 50) to (50, -50)
666 // which crosses the edge (0, 0) -> (100, 0)
667 EXPECT_THROW(poly.add_vertex(Point(50, -50)), std::domain_error);
668}
669
670//============================================================================
671// Polygon Colinearity Tests
672//============================================================================
673
674class PolygonColinearityTest : public ::testing::Test {};
675
677{
678 Polygon poly;
679 poly.add_vertex(Point(0, 0));
680 poly.add_vertex(Point(50, 0)); // Will be replaced
681 poly.add_vertex(Point(100, 0)); // Colinear, replaces previous
682
683 // Only 2 vertices: colinear point replaced the previous one
684 EXPECT_EQ(poly.size(), 2u);
685}
686
688{
689 Polygon poly;
690 poly.add_vertex(Point(0, 0));
691 poly.add_vertex(Point(100, 0));
692
693 // Point inside the last segment
694 EXPECT_THROW(poly.add_vertex(Point(50, 0)), std::domain_error);
695}
696
697//============================================================================
698// Polygon Containment Tests
699//============================================================================
700
701class PolygonContainmentTest : public ::testing::Test
702{
703protected:
704 void SetUp() override
705 {
706 // Create a square 0-100 x 0-100
707 square.add_vertex(Point(0, 0));
708 square.add_vertex(Point(100, 0));
709 square.add_vertex(Point(100, 100));
710 square.add_vertex(Point(0, 100));
711 square.close();
712 }
713
715};
716
718{
719 Point inside(50, 50);
720 EXPECT_TRUE(square.contains(inside));
721}
722
724{
725 Point outside(200, 200);
726 EXPECT_FALSE(square.contains(outside));
727}
728
730{
731 Point near_edge(1, 50); // Just inside left edge
732 EXPECT_TRUE(square.contains(near_edge));
733}
734
736{
737 Polygon open;
738 open.add_vertex(Point(0, 0));
739 open.add_vertex(Point(100, 0));
740 open.add_vertex(Point(100, 100));
741
742 EXPECT_THROW(open.contains(Point(50, 50)), std::domain_error);
743}
744
745//============================================================================
746// Polygon Remove Vertex Tests
747//============================================================================
748
749class PolygonRemoveVertexTest : public ::testing::Test
750{
751protected:
752 void SetUp() override
753 {
754 poly.add_vertex(Point(0, 0));
755 poly.add_vertex(Point(100, 0));
756 poly.add_vertex(Point(100, 100));
757 poly.add_vertex(Point(0, 100));
758 }
759
761};
762
764{
765 const Vertex & v = poly.get_first_vertex();
766 poly.remove_vertex(v);
767
768 EXPECT_EQ(poly.size(), 3u);
769}
770
772{
773 Vertex external(Point(999, 999));
774 EXPECT_THROW(poly.remove_vertex(external), std::domain_error);
775}
776
777//============================================================================
778// Polygon from Triangle Tests
779//============================================================================
780
781class PolygonFromTriangleTest : public ::testing::Test {};
782
784{
785 Triangle tr(Point(0, 0), Point(100, 0), Point(50, 100));
786 Polygon poly(tr);
787
788 EXPECT_EQ(poly.size(), 3u);
789 EXPECT_TRUE(poly.is_closed());
790}
791
793{
794 // Use non-colinear points
795 Triangle tr(Point(0, 0), Point(100, 0), Point(50, 87));
796 Polygon poly(tr);
797
798 EXPECT_EQ(poly.size(), 3u);
799 EXPECT_TRUE(poly.is_closed());
800
801 // Verify that the polygon contains the centroid of the triangle
802 Point centroid(50, 29); // Approximately (0+100+50)/3, (0+0+87)/3
803 EXPECT_TRUE(poly.contains(centroid));
804}
805
806//============================================================================
807// Regular Polygon Construction Tests
808//============================================================================
809
810class RegularPolygonConstructionTest : public ::testing::Test {};
811
813{
814 Regular_Polygon poly;
815 EXPECT_EQ(poly.size(), 0u);
816 EXPECT_EQ(poly.get_side_size(), 0);
817 EXPECT_EQ(poly.radius(), 0);
818 EXPECT_EQ(poly.get_center(), Point(0, 0));
819 EXPECT_FALSE(poly.is_closed());
820}
821
823{
824 Regular_Polygon tri(Point(0, 0), 100.0, 3);
825
826 EXPECT_EQ(tri.size(), 3u);
827 EXPECT_TRUE(tri.is_closed());
828 EXPECT_NEAR(tri.get_side_size(), 100.0, EPSILON);
829}
830
832{
833 Regular_Polygon sq(Point(0, 0), 100.0, 4);
834
835 EXPECT_EQ(sq.size(), 4u);
836 EXPECT_NEAR(sq.get_side_size(), 100.0, EPSILON);
837}
838
840{
841 Regular_Polygon hex(Point(100, 100), 50.0, 6);
842
843 EXPECT_EQ(hex.size(), 6u);
844 EXPECT_TRUE(points_equal(hex.get_center(), Point(100, 100)));
845}
846
848{
849 EXPECT_THROW(Regular_Polygon(Point(0, 0), 100.0, 2), std::domain_error);
850 EXPECT_THROW(Regular_Polygon(Point(0, 0), 100.0, 1), std::domain_error);
851 EXPECT_THROW(Regular_Polygon(Point(0, 0), 100.0, 0), std::domain_error);
852}
853
855{
856 EXPECT_THROW(Regular_Polygon(Point(0, 0), 0.0, 4), std::domain_error);
857 EXPECT_THROW(Regular_Polygon(Point(0, 0), -1.0, 4), std::domain_error);
859 std::numeric_limits<double>::infinity(), 4),
860 std::domain_error);
862 std::numeric_limits<double>::max(), 8),
863 std::domain_error);
864 EXPECT_THROW(Regular_Polygon(Point(0, 0), 1.0, 4,
865 std::numeric_limits<double>::quiet_NaN()),
866 std::domain_error);
867}
868
870{
871 // For a regular hexagon with side s, the circumradius r = s
872 Regular_Polygon hex(Point(0, 0), 100.0, 6);
873 EXPECT_NEAR(hex.radius(), 100.0, EPSILON);
874}
875
876//============================================================================
877// Regular Polygon Vertex Access Tests
878//============================================================================
879
880class RegularPolygonVertexTest : public ::testing::Test
881{
882protected:
883 void SetUp() override
884 {
885 // Hexagon centered at origin with side 100
886 hex = std::make_unique<Regular_Polygon>(Point(0, 0), 100.0, 6);
887 }
888
889 std::unique_ptr<Regular_Polygon> hex;
890};
891
893{
894 for (size_t i = 0; i < hex->size(); ++i)
895 EXPECT_NO_THROW(hex->get_vertex(i));
896}
897
899{
900 EXPECT_THROW(hex->get_vertex(6), std::out_of_range);
901 EXPECT_THROW(hex->get_vertex(100), std::out_of_range);
902}
903
905{
906 Point first = hex->get_first_vertex();
907 Point vertex0 = hex->get_vertex(0);
908
910}
911
913{
914 Point last = hex->get_last_vertex();
915 Point vertex5 = hex->get_vertex(5);
916
918}
919
921{
922 double r = hex->radius();
923
924 for (size_t i = 0; i < hex->size(); ++i)
925 {
926 Point v = hex->get_vertex(i);
927 Point center = hex->get_center();
928 double dist = std::sqrt(
929 std::pow(v.get_x().get_d() - center.get_x().get_d(), 2) +
930 std::pow(v.get_y().get_d() - center.get_y().get_d(), 2)
931 );
932 EXPECT_NEAR(dist, r, EPSILON);
933 }
934}
935
936//============================================================================
937// Regular Polygon Segment Access Tests
938//============================================================================
939
940class RegularPolygonSegmentTest : public ::testing::Test
941{
942protected:
943 void SetUp() override
944 {
945 // Square centered at origin
946 sq = std::make_unique<Regular_Polygon>(Point(0, 0), 100.0, 4);
947 }
948
949 std::unique_ptr<Regular_Polygon> sq;
950};
951
953{
954 Segment first = sq->get_first_segment();
955 Point vertex0 = sq->get_vertex(0);
956 Point vertex1 = sq->get_vertex(1);
957
960}
961
963{
964 Segment last = sq->get_last_segment();
965 Point vertex3 = sq->get_vertex(3);
966 Point vertex0 = sq->get_vertex(0);
967
970}
971
973{
974 double expected = sq->get_side_size();
975
976 for (size_t i = 0; i < sq->size(); ++i)
977 {
978 Point v1 = sq->get_vertex(i);
979 Point v2 = sq->get_vertex((i + 1) % sq->size());
980
981 Segment s(v1, v2);
982 EXPECT_NEAR(s.length().get_d(), expected, 0.01); // Larger tolerance for floating point
983 }
984}
985
986//============================================================================
987// Regular Polygon Vertex Iterator Tests
988//============================================================================
989
990class RegularPolygonVertexIteratorTest : public ::testing::Test
991{
992protected:
993 void SetUp() override
994 {
995 pentagon = std::make_unique<Regular_Polygon>(Point(0, 0), 50.0, 5);
996 }
997
998 std::unique_ptr<Regular_Polygon> pentagon;
999};
1000
1002{
1003 size_t count = 0;
1004 for (Regular_Polygon::Vertex_Iterator it(*pentagon); it.has_curr(); it.next())
1005 ++count;
1006
1007 EXPECT_EQ(count, 5u);
1008}
1009
1011{
1013 Vertex & v = it.get_current_vertex();
1014
1015 Point expected = pentagon->get_vertex(0);
1017}
1018
1020{
1022 for (size_t i = 0; i < 5; ++i)
1023 it.next_ne();
1024
1025 EXPECT_FALSE(it.has_curr());
1026 EXPECT_THROW(it.next(), std::overflow_error);
1027}
1028
1030{
1032 for (size_t i = 0; i < 5; ++i)
1033 it.next_ne();
1034
1035 EXPECT_THROW(it.get_current_vertex(), std::overflow_error);
1036}
1037
1038//============================================================================
1039// Regular Polygon Segment Iterator Tests
1040//============================================================================
1041
1042class RegularPolygonSegmentIteratorTest : public ::testing::Test
1043{
1044protected:
1045 void SetUp() override
1046 {
1047 triangle = std::make_unique<Regular_Polygon>(Point(0, 0), 100.0, 3);
1048 }
1049
1050 std::unique_ptr<Regular_Polygon> triangle;
1051};
1052
1054{
1055 size_t count = 0;
1056 for (Regular_Polygon::Segment_Iterator it(*triangle); it.has_curr(); it.next())
1057 ++count;
1058
1059 EXPECT_EQ(count, 3u);
1060}
1061
1063{
1066
1067 Point v0 = triangle->get_vertex(0);
1068 Point v1 = triangle->get_vertex(1);
1069
1072}
1073
1075{
1077 for (size_t i = 0; i < 3; ++i)
1078 it.next_ne();
1079
1080 EXPECT_FALSE(it.has_curr());
1081 EXPECT_THROW(it.next(), std::overflow_error);
1082}
1083
1085{
1087 for (size_t i = 0; i < 3; ++i)
1088 it.next_ne();
1089
1090 EXPECT_THROW(it.get_current_segment(), std::overflow_error);
1091}
1092
1093//============================================================================
1094// Regular Polygon Extreme Points Tests
1095//============================================================================
1096
1097class RegularPolygonExtremePointsTest : public ::testing::Test
1098{
1099protected:
1100 void SetUp() override
1101 {
1102 // Hexagon centered at (100, 100) with radius ~100
1103 hex = std::make_unique<Regular_Polygon>(Point(100, 100), 100.0, 6);
1104 }
1105
1106 std::unique_ptr<Regular_Polygon> hex;
1107};
1108
1110{
1111 Point lowest = hex->lowest_point();
1112 Point center = hex->get_center();
1113 double r = hex->radius();
1114
1115 EXPECT_TRUE(points_equal(lowest, center + Point(0, -r)));
1116}
1117
1119{
1120 Point highest = hex->highest_point();
1121 Point center = hex->get_center();
1122 double r = hex->radius();
1123
1124 EXPECT_TRUE(points_equal(highest, center + Point(0, r)));
1125}
1126
1128{
1129 Point leftmost = hex->leftmost_point();
1130 Point center = hex->get_center();
1131 double r = hex->radius();
1132
1133 EXPECT_TRUE(points_equal(leftmost, center + Point(-r, 0)));
1134}
1135
1137{
1138 Point rightmost = hex->rightmost_point();
1139 Point center = hex->get_center();
1140 double r = hex->radius();
1141
1142 EXPECT_TRUE(points_equal(rightmost, center + Point(r, 0)));
1143}
1144
1145//============================================================================
1146// Regular Polygon Rotation Tests
1147//============================================================================
1148
1149class RegularPolygonRotationTest : public ::testing::Test {};
1150
1152{
1153 Regular_Polygon sq(Point(0, 0), 100.0, 4, 0);
1154
1155 // First vertex should be at the "south" position (negative y)
1156 Point v0 = sq.get_vertex(0);
1157 EXPECT_LT(v0.get_y().get_d(), 0); // Below center
1158 EXPECT_NEAR(v0.get_x().get_d(), 0, 0.1); // On vertical axis
1159}
1160
1162{
1163 Regular_Polygon sq1(Point(0, 0), 100.0, 4, 0);
1164 Regular_Polygon sq2(Point(0, 0), 100.0, 4, PI / 4); // 45 degree rotation
1165
1166 // First vertex of rotated polygon should be different from non-rotated
1167 Point v0_orig = sq1.get_vertex(0);
1168 Point v0_rot = sq2.get_vertex(0);
1169
1170 // The x-coordinate should change after rotation
1171 EXPECT_FALSE(approx_equal(v0_orig.get_x(), v0_rot.get_x(), 0.1));
1172}
1173
1175{
1176 // Rotated hexagon should still have all vertices equidistant from center
1177 Regular_Polygon hex(Point(0, 0), 100.0, 6, PI / 6); // 30 degree rotation
1178 double r = hex.radius();
1179
1180 for (size_t i = 0; i < hex.size(); ++i)
1181 {
1182 Point v = hex.get_vertex(i);
1183 double dist = std::sqrt(
1184 std::pow(v.get_x().get_d(), 2) + std::pow(v.get_y().get_d(), 2)
1185 );
1186 EXPECT_NEAR(dist, r, 0.001);
1187 }
1188}
1189
1190//============================================================================
1191// Polygon from Regular Polygon Tests
1192//============================================================================
1193
1194class PolygonFromRegularTest : public ::testing::Test {};
1195
1197{
1198 Regular_Polygon hex(Point(100, 100), 50.0, 6);
1199 Polygon poly(hex);
1200
1201 EXPECT_EQ(poly.size(), 6u);
1202 EXPECT_TRUE(poly.is_closed());
1203}
1204
1206{
1207 Regular_Polygon sq(Point(0, 0), 100.0, 4);
1208 Polygon poly;
1209
1210 poly = sq;
1211
1212 EXPECT_EQ(poly.size(), 4u);
1213 EXPECT_TRUE(poly.is_closed());
1214}
1215
1217{
1218 Regular_Polygon tri(Point(0, 0), 100.0, 3);
1219 Polygon poly(tri);
1220
1221 // Both should have same number of vertices
1222 EXPECT_EQ(poly.size(), tri.size());
1223
1224 // Verify each vertex
1225 size_t i = 0;
1226 for (Polygon::Vertex_Iterator it(poly); it.has_curr(); it.next_ne(), ++i)
1227 {
1228 Point polyV = it.get_current_vertex();
1229 Point regV = tri.get_vertex(i);
1231 }
1232}
1233
1234//============================================================================
1235// Type Traits and Noexcept Tests
1236//============================================================================
1237
1239{
1240 EXPECT_TRUE(std::is_nothrow_move_constructible<Polygon>::value);
1241}
1242
1244{
1245 EXPECT_TRUE(std::is_nothrow_move_assignable<Polygon>::value);
1246}
1247
1248//============================================================================
1249// Edge Cases and Stress Tests
1250//============================================================================
1251
1253{
1254 Polygon poly;
1255 const size_t N = 1000;
1256
1257 // Create a circle-like polygon with N vertices
1258 for (size_t i = 0; i < N; ++i)
1259 {
1260 double angle = 2.0 * PI * i / N;
1261 double x = 1000.0 * cos(angle);
1262 double y = 1000.0 * sin(angle);
1263 poly.add_vertex(Point(x, y));
1264 }
1265 poly.close();
1266
1267 EXPECT_EQ(poly.size(), N);
1268 EXPECT_TRUE(poly.is_closed());
1269
1270 // Containment test should work
1271 EXPECT_TRUE(poly.contains(Point(0, 0)));
1272 EXPECT_FALSE(poly.contains(Point(2000, 2000)));
1273}
1274
1276{
1277 Regular_Polygon poly(Point(0, 0), 100.0, 100);
1278
1279 EXPECT_EQ(poly.size(), 100u);
1280
1281 // All vertices should be at the same distance from center
1282 double r = poly.radius();
1283 for (size_t i = 0; i < poly.size(); ++i)
1284 {
1285 Point v = poly.get_vertex(i);
1286 double dist = std::sqrt(
1287 std::pow(v.get_x().get_d(), 2) + std::pow(v.get_y().get_d(), 2)
1288 );
1289 EXPECT_NEAR(dist, r, 0.001);
1290 }
1291}
1292
1294{
1295 Polygon poly;
1296 poly.add_vertex(Point(0.0001, 0.0001));
1297 poly.add_vertex(Point(0.0002, 0.0001));
1298 poly.add_vertex(Point(0.00015, 0.0002));
1299 poly.close();
1300
1301 EXPECT_EQ(poly.size(), 3u);
1302 EXPECT_TRUE(poly.is_closed());
1303}
1304
1306{
1307 Polygon poly;
1308 poly.add_vertex(Point(-1000, -1000));
1309 poly.add_vertex(Point(-500, -1000));
1310 poly.add_vertex(Point(-500, -500));
1311 poly.add_vertex(Point(-1000, -500));
1312 poly.close();
1313
1314 EXPECT_TRUE(poly.contains(Point(-750, -750)));
1315 EXPECT_FALSE(poly.contains(Point(0, 0)));
1316}
1317
1318//============================================================================
1319// Polygon Convenience Methods Tests
1320//============================================================================
1321
1323{
1324 Polygon square;
1325 square.add_vertex(Point(0, 0));
1326 square.add_vertex(Point(1, 0));
1327 square.add_vertex(Point(1, 1));
1328 square.add_vertex(Point(0, 1));
1329 square.close();
1330
1331 EXPECT_EQ(square.area(), Geom_Number(1));
1332 EXPECT_EQ(square.signed_area(), Geom_Number(1)); // CCW => positive
1333}
1334
1336{
1337 Polygon square;
1338 square.add_vertex(Point(0, 0));
1339 square.add_vertex(Point(0, 1));
1340 square.add_vertex(Point(1, 1));
1341 square.add_vertex(Point(1, 0));
1342 square.close();
1343
1344 EXPECT_EQ(square.area(), Geom_Number(1));
1345 EXPECT_EQ(square.signed_area(), Geom_Number(-1)); // CW => negative
1346}
1347
1349{
1350 Polygon tri;
1351 tri.add_vertex(Point(0, 0));
1352 tri.add_vertex(Point(4, 0));
1353 tri.add_vertex(Point(0, 3));
1354 tri.close();
1355
1356 EXPECT_EQ(tri.area(), Geom_Number(6)); // (4*3)/2 = 6
1357}
1358
1360{
1361 Polygon square;
1362 square.add_vertex(Point(0, 0));
1363 square.add_vertex(Point(1, 0));
1364 square.add_vertex(Point(1, 1));
1365 square.add_vertex(Point(0, 1));
1366 square.close();
1367
1368 EXPECT_EQ(square.perimeter(), Geom_Number(4));
1369}
1370
1372{
1373 Polygon tri;
1374 tri.add_vertex(Point(0, 0));
1375 tri.add_vertex(Point(3, 0));
1376 tri.add_vertex(Point(0, 4));
1377 tri.close();
1378
1379 // 3 + 4 + 5 = 12
1380 EXPECT_EQ(tri.perimeter(), Geom_Number(12));
1381}
1382
1384{
1385 Polygon square;
1386 square.add_vertex(Point(0, 0));
1387 square.add_vertex(Point(2, 0));
1388 square.add_vertex(Point(2, 2));
1389 square.add_vertex(Point(0, 2));
1390 square.close();
1391
1392 Point c = square.centroid();
1393 EXPECT_EQ(c.get_x(), Geom_Number(1));
1394 EXPECT_EQ(c.get_y(), Geom_Number(1));
1395}
1396
1398{
1399 Polygon tri;
1400 tri.add_vertex(Point(0, 0));
1401 tri.add_vertex(Point(3, 0));
1402 tri.add_vertex(Point(0, 3));
1403 tri.close();
1404
1405 Point c = tri.centroid();
1406 EXPECT_EQ(c.get_x(), Geom_Number(1));
1407 EXPECT_EQ(c.get_y(), Geom_Number(1));
1408}
1409
1411{
1412 Polygon square;
1413 square.add_vertex(Point(0, 0));
1414 square.add_vertex(Point(1, 0));
1415 square.add_vertex(Point(1, 1));
1416 square.add_vertex(Point(0, 1));
1417 square.close();
1418
1419 EXPECT_TRUE(square.is_convex());
1420}
1421
1423{
1424 Polygon tri;
1425 tri.add_vertex(Point(0, 0));
1426 tri.add_vertex(Point(1, 0));
1427 tri.add_vertex(Point(0.5, 1));
1428 tri.close();
1429
1430 EXPECT_TRUE(tri.is_convex());
1431}
1432
1434{
1435 // L-shaped polygon (non-convex)
1437 lshape.add_vertex(Point(0, 0));
1438 lshape.add_vertex(Point(2, 0));
1439 lshape.add_vertex(Point(2, 1));
1440 lshape.add_vertex(Point(1, 1));
1441 lshape.add_vertex(Point(1, 2));
1442 lshape.add_vertex(Point(0, 2));
1443 lshape.close();
1444
1445 EXPECT_FALSE(lshape.is_convex());
1446}
1447
1449{
1450 Polygon line;
1451 line.add_vertex(Point(0, 0));
1452 line.add_vertex(Point(1, 1));
1453
1454 EXPECT_THROW(line.area(), std::domain_error);
1455}
1456
1458{
1460 single.add_vertex(Point(0, 0));
1461
1462 EXPECT_THROW(single.perimeter(), std::domain_error);
1463}
1464
1466{
1467 Polygon line;
1468 line.add_vertex(Point(0, 0));
1469 line.add_vertex(Point(1, 1));
1470
1471 EXPECT_THROW(line.centroid(), std::domain_error);
1472}
1473
1475{
1476 Polygon line;
1477 line.add_vertex(Point(0, 0));
1478 line.add_vertex(Point(1, 1));
1479
1480 EXPECT_THROW(line.is_convex(), std::domain_error);
1481}
1482
1483//============================================================================
1484// Main
1485//============================================================================
1486
1487int main(int argc, char **argv)
1488{
1489 ::testing::InitGoogleTest(&argc, argv);
1490 return RUN_ALL_TESTS();
1491}
int main()
Graph create_triangle()
Creates a triangle (K_3) - the simplest non-bipartite graph.
Represents a point with rectangular coordinates in a 2D plane.
Definition point.H:221
const Point & rightmost_point() const
Returns the rightmost point (largest x-coordinate).
Definition point.H:706
const Geom_Number & get_x() const noexcept
Gets the x-coordinate value.
Definition point.H:448
const Point & leftmost_point() const
Returns the leftmost point (smallest x-coordinate).
Definition point.H:697
const Geom_Number & get_y() const noexcept
Gets the y-coordinate value.
Definition point.H:457
const Point & highest_point() const
Returns the highest point (largest y-coordinate).
Definition point.H:679
const Point & lowest_point() const
Returns the lowest point (smallest y-coordinate).
Definition point.H:688
Iterator over the edges (segments) of a polygon.
Definition polygon.H:521
Segment get_current_segment() const
Get the current segment (edge).
Definition polygon.H:549
bool has_curr() const
Check if there is a current segment.
Definition polygon.H:538
A general (irregular) 2D polygon defined by a sequence of vertices.
Definition polygon.H:247
const Point & rightmost_point() const
Get the vertex with the maximum x-coordinate.
Definition polygon.H:470
Geom_Number signed_area() const
Compute the signed area of the polygon using the shoelace formula.
Definition polygon.H:946
Point centroid() const
Compute the centroid (center of mass) of the polygon.
Definition polygon.H:996
Geom_Number perimeter() const
Compute the perimeter of the polygon.
Definition polygon.H:979
const Point & highest_point() const
Get the vertex with the maximum y-coordinate.
Definition polygon.H:462
Geom_Number area() const
Compute the absolute area of the polygon.
Definition polygon.H:966
const Vertex & get_first_vertex() const
Get the first vertex of the polygon.
Definition polygon.H:579
const Vertex & get_last_vertex() const
Get the last vertex of the polygon.
Definition polygon.H:589
bool is_convex() const
Check if the polygon is convex.
Definition polygon.H:1024
void add_vertex(const Point &point)
Add a vertex to the polygon.
Definition polygon.H:678
Segment get_first_segment() const
Get the first edge (segment) of the polygon.
Definition polygon.H:627
void close()
Close the polygon.
Definition polygon.H:843
const Point & leftmost_point() const
Get the vertex with the minimum x-coordinate.
Definition polygon.H:466
const bool & is_closed() const
Check if the polygon is closed.
Definition polygon.H:474
const size_t & size() const
Get the number of vertices.
Definition polygon.H:478
const Point & lowest_point() const
Get the vertex with the minimum y-coordinate.
Definition polygon.H:458
bool contains(const Point &p) const
Check if a point is inside the polygon (or on its boundary).
Definition polygon.H:929
Iterator over the edges (segments) of a regular polygon.
Definition polygon.H:1329
void next()
Advance to the next segment.
Definition polygon.H:1361
Segment get_current_segment() const
Get the current segment (edge).
Definition polygon.H:1349
bool has_curr() const
Check if there is a current segment.
Definition polygon.H:1344
void next_ne() noexcept
Advance to the next segment (no exception on overflow).
Definition polygon.H:1357
Iterator over the vertices of a regular polygon.
Definition polygon.H:1266
Vertex & get_current_vertex()
Get the current vertex.
Definition polygon.H:1287
bool has_curr() const
Check if there is a current vertex.
Definition polygon.H:1282
void next()
Advance to the next vertex.
Definition polygon.H:1301
void next_ne() noexcept
Advance to the next vertex (no exception on overflow).
Definition polygon.H:1297
A regular polygon defined by center, side length, and vertex count.
Definition polygon.H:1135
Point get_vertex(const size_t &i) const
Get the i-th vertex of the polygon.
Definition polygon.H:1218
const size_t & size() const
Get the number of vertices.
Definition polygon.H:1196
const double & get_side_size() const
Get the side length.
Definition polygon.H:1188
const Point & get_center() const
Get the center point.
Definition polygon.H:1192
bool is_closed() const noexcept
Check if the polygon is a valid closed regular polygon.
Definition polygon.H:1207
const double & radius() const
Get the circumradius.
Definition polygon.H:1200
Represents a line segment between two points.
Definition point.H:837
const Point & get_tgt_point() const noexcept
Gets the target point of the segment.
Definition point.H:933
const Point & get_src_point() const noexcept
Gets the source point of the segment.
Definition point.H:924
Geom_Number length() const
Returns the Euclidean length of the segment.
Definition point.H:1069
A non-degenerate triangle defined by three points.
Definition point.H:1512
A vertex in a polygon's doubly linked vertex list.
Definition polygon.H:120
static Vertex * dlink_to_vertex(Dlink *link)
Convert a Dlink pointer to a Vertex pointer.
Definition polygon.H:160
Point to_point() const
Return this vertex as a plain Point value.
Definition polygon.H:151
Minimal std::expected-style result type for C++20.
void SetUp() override
std::unique_ptr< Regular_Polygon > hex
std::unique_ptr< Regular_Polygon > triangle
std::unique_ptr< Regular_Polygon > sq
std::unique_ptr< Regular_Polygon > pentagon
std::unique_ptr< Regular_Polygon > hex
void SetUp() override
#define TEST(name)
#define N
Definition fib.C:294
__gmp_expr< T, __gmp_unary_expr< __gmp_expr< T, U >, __gmp_cos_function > > cos(const __gmp_expr< T, U > &expr)
Definition gmpfrxx.h:4080
__gmp_expr< T, __gmp_unary_expr< __gmp_expr< T, U >, __gmp_sin_function > > sin(const __gmp_expr< T, U > &expr)
Definition gmpfrxx.h:4081
size_t blossom_maximum_cardinality_matching(const GT &g, DynDlist< typename GT::Arc * > &matching, SA sa=SA())
Alias of compute_maximum_cardinality_general_matching().
Definition Blossom.H:466
static mpfr_t y
Definition mpfr_mul_d.c:3
Main namespace for Aleph-w library functions.
Definition ah-arena.H:89
Itor2 copy(Itor1 sourceBeg, const Itor1 &sourceEnd, Itor2 destBeg)
Copy elements from one range to another.
Definition ahAlgo.H:584
mpq_class Geom_Number
Numeric type used by the geometry module.
Definition point.H:113
void next()
Advance all underlying iterators (bounds-checked).
Definition ah-zip.H:171
constexpr double PI
Definition point.H:129
Itor::difference_type count(const Itor &beg, const Itor &end, const T &value)
Count elements equal to a value.
Definition ahAlgo.H:127
2D polygon representation and geometric operations.
bool points_equal(const Point &a, const Point &b, double tol=EPSILON)
constexpr double EPSILON
TEST_F(VertexTest, DefaultConstruction)
bool approx_equal(const Geom_Number &a, const Geom_Number &b, double tol=EPSILON)
Iterator over the vertices of a polygon.
Definition polygon.H:490
Vertex & get_current_vertex() const
Get the current vertex.
Definition polygon.H:501
gsl_rng * r