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 <vector>
49#include <polygon.H>
50
51using namespace Aleph;
52
53// Tolerance for floating-point comparisons
54constexpr double EPSILON = 1e-6;
55
56// Helper to compare Geom_Number with tolerance
57bool approx_equal(const Geom_Number & a, const Geom_Number & b,
58 double tol = EPSILON)
59{
60 return std::abs(a.get_d() - b.get_d()) < tol;
61}
62
63// Helper to compare Points
64bool points_equal(const Point & a, const Point & b, double tol = EPSILON)
65{
66 return approx_equal(a.get_x(), b.get_x(), tol) &&
67 approx_equal(a.get_y(), b.get_y(), tol);
68}
69
70//============================================================================
71// Vertex Class Tests
72//============================================================================
73
74class VertexTest : public ::testing::Test
75{
76protected:
77 void SetUp() override
78 {
79 p1 = Point(10, 20);
80 p2 = Point(30, 40);
81 }
82
84};
85
87{
88 Vertex v;
89 EXPECT_EQ(v.get_x(), 0);
90 EXPECT_EQ(v.get_y(), 0);
91}
92
94{
95 Vertex v(p1);
96 EXPECT_EQ(v.get_x(), p1.get_x());
97 EXPECT_EQ(v.get_y(), p1.get_y());
98}
99
101{
102 Vertex v1(p1);
103 Vertex v2(v1);
104
105 EXPECT_EQ(v2.get_x(), v1.get_x());
106 EXPECT_EQ(v2.get_y(), v1.get_y());
107}
108
110{
111 Vertex v1(p1);
112 Vertex v2(p2);
113
114 v2 = v1;
115
116 EXPECT_EQ(v2.get_x(), v1.get_x());
117 EXPECT_EQ(v2.get_y(), v1.get_y());
118}
119
121{
122 Vertex v(p1);
123 v = v;
124
125 EXPECT_EQ(v.get_x(), p1.get_x());
126 EXPECT_EQ(v.get_y(), p1.get_y());
127}
128
130{
131 Vertex v(p1);
132 Point p = v.to_point();
133
134 EXPECT_EQ(p.get_x(), p1.get_x());
135 EXPECT_EQ(p.get_y(), p1.get_y());
136}
137
139{
140 Vertex v(p1);
141 Dlink * link = &v;
142
144 EXPECT_EQ(recovered, &v);
145 EXPECT_EQ(recovered->get_x(), p1.get_x());
146}
147
149{
150 const Vertex v(p1);
151 const Dlink * link = &v;
152
154 EXPECT_EQ(recovered, &v);
155 EXPECT_EQ(recovered->get_x(), p1.get_x());
156}
157
158//============================================================================
159// Polygon Construction Tests
160//============================================================================
161
162class PolygonConstructionTest : public ::testing::Test
163{
164protected:
166 {
167 Polygon poly;
168 poly.add_vertex(Point(0, 0));
169 poly.add_vertex(Point(100, 0));
170 poly.add_vertex(Point(100, 100));
171 poly.add_vertex(Point(0, 100));
172 poly.close();
173 return poly;
174 }
175
177 {
178 Polygon poly;
179 poly.add_vertex(Point(0, 0));
180 poly.add_vertex(Point(100, 0));
181 poly.add_vertex(Point(50, 100));
182 poly.close();
183 return poly;
184 }
185};
186
193
195{
196 Polygon poly;
197 poly.add_vertex(Point(10, 20));
198
199 EXPECT_EQ(poly.size(), 1u);
200 EXPECT_FALSE(poly.is_closed());
201}
202
204{
205 Polygon poly;
206 poly.add_vertex(Point(0, 0));
207 poly.add_vertex(Point(100, 0));
208 poly.add_vertex(Point(100, 100));
209
210 EXPECT_EQ(poly.size(), 3u);
211 EXPECT_FALSE(poly.is_closed());
212}
213
215{
216 Polygon poly = create_triangle();
217
218 EXPECT_EQ(poly.size(), 3u);
219 EXPECT_TRUE(poly.is_closed());
220}
221
223{
224 Polygon empty;
225 EXPECT_THROW(empty.close(), std::domain_error);
226
229 EXPECT_THROW(one_vertex.close(), std::domain_error);
230
233 two_vertices.add_vertex(Point(100, 0));
234 EXPECT_THROW(two_vertices.close(), std::domain_error);
235}
236
238{
239 Polygon poly = create_triangle();
240
241 EXPECT_THROW(poly.add_vertex(Point(50, 50)), std::domain_error);
242}
243
245{
246 Polygon poly = create_triangle();
247
248 EXPECT_THROW(poly.close(), std::domain_error);
249}
250
252{
253 Polygon original = create_square();
255
256 EXPECT_EQ(copy.size(), original.size());
257 EXPECT_EQ(copy.is_closed(), original.is_closed());
258 EXPECT_TRUE(points_equal(copy.lowest_point(), original.lowest_point()));
259}
260
262{
263 Polygon original = create_square();
264 size_t orig_size = original.size();
265
266 Polygon moved(std::move(original));
267
268 EXPECT_EQ(moved.size(), orig_size);
269 EXPECT_TRUE(moved.is_closed());
270 EXPECT_EQ(original.size(), 0u); // NOLINT - testing moved-from state
271}
272
274{
275 Polygon poly1 = create_square();
277
278 poly2 = poly1;
279
280 EXPECT_EQ(poly2.size(), poly1.size());
281 EXPECT_EQ(poly2.is_closed(), poly1.is_closed());
282}
283
285{
286 Polygon poly1 = create_square();
287 size_t orig_size = poly1.size();
289
290 poly2 = std::move(poly1);
291
292 EXPECT_EQ(poly2.size(), orig_size);
293 EXPECT_TRUE(poly2.is_closed());
294}
295
297{
298 Polygon poly = create_square();
299 poly = poly;
300
301 EXPECT_EQ(poly.size(), 4u);
302 EXPECT_TRUE(poly.is_closed());
303}
304
306{
307 Polygon poly;
308 poly.add_vertex(Geom_Number(50), Geom_Number(75));
309
310 EXPECT_EQ(poly.size(), 1u);
311 EXPECT_EQ(poly.get_first_vertex().get_x(), 50);
312 EXPECT_EQ(poly.get_first_vertex().get_y(), 75);
313}
314
315//============================================================================
316// Polygon Extreme Points Tests
317//============================================================================
318
319class PolygonExtremePointsTest : public ::testing::Test {};
320
322{
323 Polygon poly;
324 poly.add_vertex(Point(50, 75));
325
326 EXPECT_EQ(poly.lowest_point().get_x(), 50);
327 EXPECT_EQ(poly.lowest_point().get_y(), 75);
328 EXPECT_EQ(poly.highest_point().get_y(), 75);
329 EXPECT_EQ(poly.leftmost_point().get_x(), 50);
330 EXPECT_EQ(poly.rightmost_point().get_x(), 50);
331}
332
334{
335 Polygon poly;
336 poly.add_vertex(Point(10, 20));
337 poly.add_vertex(Point(100, 5));
338 poly.add_vertex(Point(50, 150));
339 poly.add_vertex(Point(-20, 80));
340
341 EXPECT_EQ(poly.lowest_point().get_y(), 5);
342 EXPECT_EQ(poly.highest_point().get_y(), 150);
343 EXPECT_EQ(poly.leftmost_point().get_x(), -20);
344 EXPECT_EQ(poly.rightmost_point().get_x(), 100);
345}
346
348{
349 Polygon poly;
350 poly.add_vertex(Point(-100, -100));
351 poly.add_vertex(Point(100, -100));
352 poly.add_vertex(Point(100, 100));
353 poly.add_vertex(Point(-100, 100));
354
355 EXPECT_EQ(poly.lowest_point().get_y(), -100);
356 EXPECT_EQ(poly.highest_point().get_y(), 100);
357 EXPECT_EQ(poly.leftmost_point().get_x(), -100);
358 EXPECT_EQ(poly.rightmost_point().get_x(), 100);
359}
360
361//============================================================================
362// Polygon Vertex Access Tests
363//============================================================================
364
365class PolygonVertexAccessTest : public ::testing::Test
366{
367protected:
368 void SetUp() override
369 {
370 poly.add_vertex(Point(0, 0));
371 poly.add_vertex(Point(100, 0));
372 poly.add_vertex(Point(100, 100));
373 poly.add_vertex(Point(0, 100));
374 }
375
377};
378
380{
381 const Vertex & first = poly.get_first_vertex();
382 EXPECT_EQ(first.get_x(), 0);
383 EXPECT_EQ(first.get_y(), 0);
384}
385
387{
388 const Vertex & last = poly.get_last_vertex();
389 EXPECT_EQ(last.get_x(), 0);
390 EXPECT_EQ(last.get_y(), 100);
391}
392
398
404
406{
407 const Vertex & first = poly.get_first_vertex();
408 EXPECT_TRUE(poly.vertex_belong_polygon(first));
409}
410
412{
413 Vertex external(Point(999, 999));
414 EXPECT_FALSE(poly.vertex_belong_polygon(external));
415}
416
418{
419 const Vertex & first = poly.get_first_vertex();
420 const Vertex & next = poly.get_next_vertex(first);
421
422 EXPECT_EQ(next.get_x(), 100);
423 EXPECT_EQ(next.get_y(), 0);
424}
425
427{
428 const Vertex & last = poly.get_last_vertex();
429 const Vertex & prev = poly.get_prev_vertex(last);
430
431 EXPECT_EQ(prev.get_x(), 100);
432 EXPECT_EQ(prev.get_y(), 100);
433}
434
435//============================================================================
436// Polygon Segment Access Tests
437//============================================================================
438
439class PolygonSegmentAccessTest : public ::testing::Test
440{
441protected:
442 void SetUp() override
443 {
444 poly.add_vertex(Point(0, 0));
445 poly.add_vertex(Point(100, 0));
446 poly.add_vertex(Point(100, 100));
447 }
448
450};
451
453{
454 Segment first = poly.get_first_segment();
455
457 EXPECT_TRUE(points_equal(first.get_tgt_point(), Point(100, 0)));
458}
459
461{
462 Segment last = poly.get_last_segment();
463
465 EXPECT_TRUE(points_equal(last.get_tgt_point(), Point(100, 100)));
466}
467
469{
471 single.add_vertex(Point(0, 0));
472
473 EXPECT_THROW(single.get_first_segment(), std::domain_error);
474}
475
481
482//============================================================================
483// Polygon Vertex Iterator Tests
484//============================================================================
485
486class PolygonVertexIteratorTest : public ::testing::Test
487{
488protected:
489 void SetUp() override
490 {
491 poly.add_vertex(Point(0, 0));
492 poly.add_vertex(Point(100, 0));
493 poly.add_vertex(Point(100, 100));
494 poly.add_vertex(Point(0, 100));
495 }
496
498};
499
501{
502 size_t count = 0;
503 for (Polygon::Vertex_Iterator it(poly); it.has_curr(); it.next_ne())
504 ++count;
505
506 EXPECT_EQ(count, 4u);
507}
508
517
519{
520 Polygon empty;
521 EXPECT_THROW(Polygon::Vertex_Iterator it(empty), std::domain_error);
522}
523
524//============================================================================
525// Polygon Segment Iterator Tests
526//============================================================================
527
528class PolygonSegmentIteratorTest : public ::testing::Test
529{
530protected:
531 void SetUp() override
532 {
533 poly.add_vertex(Point(0, 0));
534 poly.add_vertex(Point(100, 0));
535 poly.add_vertex(Point(100, 100));
536 poly.add_vertex(Point(0, 100));
537 }
538
540};
541
543{
544 // poly is not closed, so 4 vertices = 3 segments
545 size_t count = 0;
546 for (Polygon::Segment_Iterator it(poly); it.has_curr(); it.next_ne())
547 ++count;
548
549 EXPECT_EQ(count, 3u);
550}
551
553{
554 poly.close();
555
556 size_t count = 0;
557 for (Polygon::Segment_Iterator it(poly); it.has_curr(); it.next_ne())
558 ++count;
559
560 EXPECT_EQ(count, 4u);
561}
562
571
577
585
586//============================================================================
587// Polygon Intersection Tests
588//============================================================================
589
590class PolygonIntersectionTest : public ::testing::Test
591{
592protected:
593 void SetUp() override
594 {
595 square.add_vertex(Point(0, 0));
596 square.add_vertex(Point(100, 0));
597 square.add_vertex(Point(100, 100));
598 square.add_vertex(Point(0, 100));
599 square.close();
600 }
601
603};
604
606{
607 Segment cross(Point(-50, 50), Point(150, 50));
608 EXPECT_TRUE(square.intersects_with(cross));
609}
610
612{
613 Segment outside(Point(200, 0), Point(200, 100));
614 EXPECT_FALSE(square.intersects_with(outside));
615}
616
618{
619 Segment inside(Point(25, 25), Point(75, 75));
620 EXPECT_FALSE(square.intersects_with(inside));
621}
622
623//============================================================================
624// Polygon Self-Intersection Prevention Tests
625//============================================================================
626
627class PolygonSelfIntersectionTest : public ::testing::Test {};
628
630{
631 Polygon poly;
633 poly.add_vertex(Point(0, 0));
634 poly.add_vertex(Point(100, 0));
635 poly.add_vertex(Point(100, 100));
636 poly.add_vertex(Point(0, 100));
637 poly.close();
638 });
639}
640
642{
643 Polygon poly;
644 poly.add_vertex(Point(0, 0));
645 poly.add_vertex(Point(100, 0));
646 poly.add_vertex(Point(100, 100));
647 poly.add_vertex(Point(0, 100));
648
649 // Adding a vertex that would create a crossing edge
650 EXPECT_THROW(poly.add_vertex(Point(150, -50)), std::domain_error);
651}
652
654{
655 // Create a polygon where adding a vertex causes self-intersection
656 // Shape: Start at (0,0), go right to (100,0), up to (100,100),
657 // then diagonally down-left toward (-50, 50)
658 Polygon poly;
659 poly.add_vertex(Point(0, 0));
660 poly.add_vertex(Point(100, 0));
661 poly.add_vertex(Point(100, 100));
662 poly.add_vertex(Point(-50, 50));
663
664 // Adding (50, -50) would create an edge from (-50, 50) to (50, -50)
665 // which crosses the edge (0, 0) -> (100, 0)
666 EXPECT_THROW(poly.add_vertex(Point(50, -50)), std::domain_error);
667}
668
669//============================================================================
670// Polygon Colinearity Tests
671//============================================================================
672
673class PolygonColinearityTest : public ::testing::Test {};
674
676{
677 Polygon poly;
678 poly.add_vertex(Point(0, 0));
679 poly.add_vertex(Point(50, 0)); // Will be replaced
680 poly.add_vertex(Point(100, 0)); // Colinear, replaces previous
681
682 // Only 2 vertices: colinear point replaced the previous one
683 EXPECT_EQ(poly.size(), 2u);
684}
685
687{
688 Polygon poly;
689 poly.add_vertex(Point(0, 0));
690 poly.add_vertex(Point(100, 0));
691
692 // Point inside the last segment
693 EXPECT_THROW(poly.add_vertex(Point(50, 0)), std::domain_error);
694}
695
696//============================================================================
697// Polygon Containment Tests
698//============================================================================
699
700class PolygonContainmentTest : public ::testing::Test
701{
702protected:
703 void SetUp() override
704 {
705 // Create a square 0-100 x 0-100
706 square.add_vertex(Point(0, 0));
707 square.add_vertex(Point(100, 0));
708 square.add_vertex(Point(100, 100));
709 square.add_vertex(Point(0, 100));
710 square.close();
711 }
712
714};
715
717{
718 Point inside(50, 50);
719 EXPECT_TRUE(square.contains(inside));
720}
721
723{
724 Point outside(200, 200);
725 EXPECT_FALSE(square.contains(outside));
726}
727
729{
730 Point near_edge(1, 50); // Just inside left edge
731 EXPECT_TRUE(square.contains(near_edge));
732}
733
735{
736 Polygon open;
737 open.add_vertex(Point(0, 0));
738 open.add_vertex(Point(100, 0));
739 open.add_vertex(Point(100, 100));
740
741 EXPECT_THROW(open.contains(Point(50, 50)), std::domain_error);
742}
743
744//============================================================================
745// Polygon Remove Vertex Tests
746//============================================================================
747
748class PolygonRemoveVertexTest : public ::testing::Test
749{
750protected:
751 void SetUp() override
752 {
753 poly.add_vertex(Point(0, 0));
754 poly.add_vertex(Point(100, 0));
755 poly.add_vertex(Point(100, 100));
756 poly.add_vertex(Point(0, 100));
757 }
758
760};
761
763{
764 const Vertex & v = poly.get_first_vertex();
765 poly.remove_vertex(v);
766
767 EXPECT_EQ(poly.size(), 3u);
768}
769
771{
772 Vertex external(Point(999, 999));
773 EXPECT_THROW(poly.remove_vertex(external), std::domain_error);
774}
775
776//============================================================================
777// Polygon from Triangle Tests
778//============================================================================
779
780class PolygonFromTriangleTest : public ::testing::Test {};
781
783{
784 Triangle tr(Point(0, 0), Point(100, 0), Point(50, 100));
785 Polygon poly(tr);
786
787 EXPECT_EQ(poly.size(), 3u);
788 EXPECT_TRUE(poly.is_closed());
789}
790
792{
793 // Use non-colinear points
794 Triangle tr(Point(0, 0), Point(100, 0), Point(50, 87));
795 Polygon poly(tr);
796
797 EXPECT_EQ(poly.size(), 3u);
798 EXPECT_TRUE(poly.is_closed());
799
800 // Verify that the polygon contains the centroid of the triangle
801 Point centroid(50, 29); // Approximately (0+100+50)/3, (0+0+87)/3
802 EXPECT_TRUE(poly.contains(centroid));
803}
804
805//============================================================================
806// Regular Polygon Construction Tests
807//============================================================================
808
809class RegularPolygonConstructionTest : public ::testing::Test {};
810
817
819{
820 Regular_Polygon tri(Point(0, 0), 100.0, 3);
821
822 EXPECT_EQ(tri.size(), 3u);
823 EXPECT_TRUE(tri.is_closed());
824 EXPECT_NEAR(tri.get_side_size(), 100.0, EPSILON);
825}
826
828{
829 Regular_Polygon sq(Point(0, 0), 100.0, 4);
830
831 EXPECT_EQ(sq.size(), 4u);
832 EXPECT_NEAR(sq.get_side_size(), 100.0, EPSILON);
833}
834
836{
837 Regular_Polygon hex(Point(100, 100), 50.0, 6);
838
839 EXPECT_EQ(hex.size(), 6u);
840 EXPECT_TRUE(points_equal(hex.get_center(), Point(100, 100)));
841}
842
844{
845 EXPECT_THROW(Regular_Polygon(Point(0, 0), 100.0, 2), std::domain_error);
846 EXPECT_THROW(Regular_Polygon(Point(0, 0), 100.0, 1), std::domain_error);
847 EXPECT_THROW(Regular_Polygon(Point(0, 0), 100.0, 0), std::domain_error);
848}
849
851{
852 // For a regular hexagon with side s, the circumradius r = s
853 Regular_Polygon hex(Point(0, 0), 100.0, 6);
854 EXPECT_NEAR(hex.radius(), 100.0, EPSILON);
855}
856
857//============================================================================
858// Regular Polygon Vertex Access Tests
859//============================================================================
860
861class RegularPolygonVertexTest : public ::testing::Test
862{
863protected:
864 void SetUp() override
865 {
866 // Hexagon centered at origin with side 100
867 hex = std::make_unique<Regular_Polygon>(Point(0, 0), 100.0, 6);
868 }
869
870 std::unique_ptr<Regular_Polygon> hex;
871};
872
874{
875 for (size_t i = 0; i < hex->size(); ++i)
876 EXPECT_NO_THROW(hex->get_vertex(i));
877}
878
880{
881 EXPECT_THROW(hex->get_vertex(6), std::out_of_range);
882 EXPECT_THROW(hex->get_vertex(100), std::out_of_range);
883}
884
886{
887 Point first = hex->get_first_vertex();
888 Point vertex0 = hex->get_vertex(0);
889
891}
892
894{
895 Point last = hex->get_last_vertex();
896 Point vertex5 = hex->get_vertex(5);
897
899}
900
902{
903 double r = hex->radius();
904
905 for (size_t i = 0; i < hex->size(); ++i)
906 {
907 Point v = hex->get_vertex(i);
908 Point center = hex->get_center();
909 double dist = std::sqrt(
910 std::pow(v.get_x().get_d() - center.get_x().get_d(), 2) +
911 std::pow(v.get_y().get_d() - center.get_y().get_d(), 2)
912 );
913 EXPECT_NEAR(dist, r, EPSILON);
914 }
915}
916
917//============================================================================
918// Regular Polygon Segment Access Tests
919//============================================================================
920
921class RegularPolygonSegmentTest : public ::testing::Test
922{
923protected:
924 void SetUp() override
925 {
926 // Square centered at origin
927 sq = std::make_unique<Regular_Polygon>(Point(0, 0), 100.0, 4);
928 }
929
930 std::unique_ptr<Regular_Polygon> sq;
931};
932
934{
935 Segment first = sq->get_first_segment();
936 Point vertex0 = sq->get_vertex(0);
937 Point vertex1 = sq->get_vertex(1);
938
941}
942
944{
945 Segment last = sq->get_last_segment();
946 Point vertex2 = sq->get_vertex(2);
947 Point vertex3 = sq->get_vertex(3);
948
951}
952
954{
955 double expected = sq->get_side_size();
956
957 for (size_t i = 0; i < sq->size(); ++i)
958 {
959 Point v1 = sq->get_vertex(i);
960 Point v2 = sq->get_vertex((i + 1) % sq->size());
961
962 Segment s(v1, v2);
963 EXPECT_NEAR(s.length().get_d(), expected, 0.01); // Larger tolerance for floating point
964 }
965}
966
967//============================================================================
968// Regular Polygon Vertex Iterator Tests
969//============================================================================
970
971class RegularPolygonVertexIteratorTest : public ::testing::Test
972{
973protected:
974 void SetUp() override
975 {
976 pentagon = std::make_unique<Regular_Polygon>(Point(0, 0), 50.0, 5);
977 }
978
979 std::unique_ptr<Regular_Polygon> pentagon;
980};
981
983{
984 size_t count = 0;
985 for (Regular_Polygon::Vertex_Iterator it(*pentagon); it.has_curr(); it.next())
986 ++count;
987
988 EXPECT_EQ(count, 5u);
989}
990
999
1001{
1003 for (size_t i = 0; i < 5; ++i)
1004 it.next_ne();
1005
1006 EXPECT_FALSE(it.has_curr());
1007 EXPECT_THROW(it.next(), std::overflow_error);
1008}
1009
1011{
1013 for (size_t i = 0; i < 5; ++i)
1014 it.next_ne();
1015
1016 EXPECT_THROW(it.get_current_vertex(), std::overflow_error);
1017}
1018
1019//============================================================================
1020// Regular Polygon Segment Iterator Tests
1021//============================================================================
1022
1023class RegularPolygonSegmentIteratorTest : public ::testing::Test
1024{
1025protected:
1026 void SetUp() override
1027 {
1028 triangle = std::make_unique<Regular_Polygon>(Point(0, 0), 100.0, 3);
1029 }
1030
1031 std::unique_ptr<Regular_Polygon> triangle;
1032};
1033
1035{
1036 size_t count = 0;
1037 for (Regular_Polygon::Segment_Iterator it(*triangle); it.has_curr(); it.next())
1038 ++count;
1039
1040 EXPECT_EQ(count, 3u);
1041}
1042
1044{
1047
1048 Point v0 = triangle->get_vertex(0);
1049 Point v1 = triangle->get_vertex(1);
1050
1053}
1054
1056{
1058 for (size_t i = 0; i < 3; ++i)
1059 it.next_ne();
1060
1061 EXPECT_FALSE(it.has_curr());
1062 EXPECT_THROW(it.next(), std::overflow_error);
1063}
1064
1066{
1068 for (size_t i = 0; i < 3; ++i)
1069 it.next_ne();
1070
1071 EXPECT_THROW(it.get_current_segment(), std::overflow_error);
1072}
1073
1074//============================================================================
1075// Regular Polygon Extreme Points Tests
1076//============================================================================
1077
1078class RegularPolygonExtremePointsTest : public ::testing::Test
1079{
1080protected:
1081 void SetUp() override
1082 {
1083 // Hexagon centered at (100, 100) with radius ~100
1084 hex = std::make_unique<Regular_Polygon>(Point(100, 100), 100.0, 6);
1085 }
1086
1087 std::unique_ptr<Regular_Polygon> hex;
1088};
1089
1091{
1092 Point lowest = hex->lowest_point();
1093 Point center = hex->get_center();
1094 double r = hex->radius();
1095
1096 EXPECT_TRUE(points_equal(lowest, center + Point(0, -r)));
1097}
1098
1100{
1101 Point highest = hex->highest_point();
1102 Point center = hex->get_center();
1103 double r = hex->radius();
1104
1105 EXPECT_TRUE(points_equal(highest, center + Point(0, r)));
1106}
1107
1109{
1110 Point leftmost = hex->leftmost_point();
1111 Point center = hex->get_center();
1112 double r = hex->radius();
1113
1114 EXPECT_TRUE(points_equal(leftmost, center + Point(-r, 0)));
1115}
1116
1118{
1119 Point rightmost = hex->rightmost_point();
1120 Point center = hex->get_center();
1121 double r = hex->radius();
1122
1123 EXPECT_TRUE(points_equal(rightmost, center + Point(r, 0)));
1124}
1125
1126//============================================================================
1127// Regular Polygon Rotation Tests
1128//============================================================================
1129
1130class RegularPolygonRotationTest : public ::testing::Test {};
1131
1133{
1134 Regular_Polygon sq(Point(0, 0), 100.0, 4, 0);
1135
1136 // First vertex should be at the "south" position (negative y)
1137 Point v0 = sq.get_vertex(0);
1138 EXPECT_LT(v0.get_y().get_d(), 0); // Below center
1139 EXPECT_NEAR(v0.get_x().get_d(), 0, 0.1); // On vertical axis
1140}
1141
1143{
1144 Regular_Polygon sq1(Point(0, 0), 100.0, 4, 0);
1145 Regular_Polygon sq2(Point(0, 0), 100.0, 4, PI / 4); // 45 degree rotation
1146
1147 // First vertex of rotated polygon should be different from non-rotated
1148 Point v0_orig = sq1.get_vertex(0);
1149 Point v0_rot = sq2.get_vertex(0);
1150
1151 // The x-coordinate should change after rotation
1152 EXPECT_FALSE(approx_equal(v0_orig.get_x(), v0_rot.get_x(), 0.1));
1153}
1154
1156{
1157 // Rotated hexagon should still have all vertices equidistant from center
1158 Regular_Polygon hex(Point(0, 0), 100.0, 6, PI / 6); // 30 degree rotation
1159 double r = hex.radius();
1160
1161 for (size_t i = 0; i < hex.size(); ++i)
1162 {
1163 Point v = hex.get_vertex(i);
1164 double dist = std::sqrt(
1165 std::pow(v.get_x().get_d(), 2) + std::pow(v.get_y().get_d(), 2)
1166 );
1167 EXPECT_NEAR(dist, r, 0.001);
1168 }
1169}
1170
1171//============================================================================
1172// Polygon from Regular Polygon Tests
1173//============================================================================
1174
1175class PolygonFromRegularTest : public ::testing::Test {};
1176
1178{
1179 Regular_Polygon hex(Point(100, 100), 50.0, 6);
1180 Polygon poly(hex);
1181
1182 EXPECT_EQ(poly.size(), 6u);
1183 EXPECT_TRUE(poly.is_closed());
1184}
1185
1187{
1188 Regular_Polygon sq(Point(0, 0), 100.0, 4);
1189 Polygon poly;
1190
1191 poly = sq;
1192
1193 EXPECT_EQ(poly.size(), 4u);
1194 EXPECT_TRUE(poly.is_closed());
1195}
1196
1198{
1199 Regular_Polygon tri(Point(0, 0), 100.0, 3);
1200 Polygon poly(tri);
1201
1202 // Both should have same number of vertices
1203 EXPECT_EQ(poly.size(), tri.size());
1204
1205 // Verify each vertex
1206 size_t i = 0;
1207 for (Polygon::Vertex_Iterator it(poly); it.has_curr(); it.next_ne(), ++i)
1208 {
1209 Point polyV = it.get_current_vertex();
1210 Point regV = tri.get_vertex(i);
1212 }
1213}
1214
1215//============================================================================
1216// Type Traits and Noexcept Tests
1217//============================================================================
1218
1220{
1221 EXPECT_TRUE(std::is_nothrow_move_constructible<Polygon>::value);
1222}
1223
1225{
1226 EXPECT_TRUE(std::is_nothrow_move_assignable<Polygon>::value);
1227}
1228
1229//============================================================================
1230// Edge Cases and Stress Tests
1231//============================================================================
1232
1234{
1235 Polygon poly;
1236 const size_t N = 1000;
1237
1238 // Create a circle-like polygon with N vertices
1239 for (size_t i = 0; i < N; ++i)
1240 {
1241 double angle = 2.0 * PI * i / N;
1242 double x = 1000.0 * cos(angle);
1243 double y = 1000.0 * sin(angle);
1244 poly.add_vertex(Point(x, y));
1245 }
1246 poly.close();
1247
1248 EXPECT_EQ(poly.size(), N);
1249 EXPECT_TRUE(poly.is_closed());
1250
1251 // Containment test should work
1252 EXPECT_TRUE(poly.contains(Point(0, 0)));
1253 EXPECT_FALSE(poly.contains(Point(2000, 2000)));
1254}
1255
1257{
1258 Regular_Polygon poly(Point(0, 0), 100.0, 100);
1259
1260 EXPECT_EQ(poly.size(), 100u);
1261
1262 // All vertices should be at the same distance from center
1263 double r = poly.radius();
1264 for (size_t i = 0; i < poly.size(); ++i)
1265 {
1266 Point v = poly.get_vertex(i);
1267 double dist = std::sqrt(
1268 std::pow(v.get_x().get_d(), 2) + std::pow(v.get_y().get_d(), 2)
1269 );
1270 EXPECT_NEAR(dist, r, 0.001);
1271 }
1272}
1273
1275{
1276 Polygon poly;
1277 poly.add_vertex(Point(0.0001, 0.0001));
1278 poly.add_vertex(Point(0.0002, 0.0001));
1279 poly.add_vertex(Point(0.00015, 0.0002));
1280 poly.close();
1281
1282 EXPECT_EQ(poly.size(), 3u);
1283 EXPECT_TRUE(poly.is_closed());
1284}
1285
1287{
1288 Polygon poly;
1289 poly.add_vertex(Point(-1000, -1000));
1290 poly.add_vertex(Point(-500, -1000));
1291 poly.add_vertex(Point(-500, -500));
1292 poly.add_vertex(Point(-1000, -500));
1293 poly.close();
1294
1295 EXPECT_TRUE(poly.contains(Point(-750, -750)));
1296 EXPECT_FALSE(poly.contains(Point(0, 0)));
1297}
1298
1299//============================================================================
1300// Polygon Convenience Methods Tests
1301//============================================================================
1302
1304{
1305 Polygon square;
1306 square.add_vertex(Point(0, 0));
1307 square.add_vertex(Point(1, 0));
1308 square.add_vertex(Point(1, 1));
1309 square.add_vertex(Point(0, 1));
1310 square.close();
1311
1312 EXPECT_EQ(square.area(), Geom_Number(1));
1313 EXPECT_EQ(square.signed_area(), Geom_Number(1)); // CCW => positive
1314}
1315
1317{
1318 Polygon square;
1319 square.add_vertex(Point(0, 0));
1320 square.add_vertex(Point(0, 1));
1321 square.add_vertex(Point(1, 1));
1322 square.add_vertex(Point(1, 0));
1323 square.close();
1324
1325 EXPECT_EQ(square.area(), Geom_Number(1));
1326 EXPECT_EQ(square.signed_area(), Geom_Number(-1)); // CW => negative
1327}
1328
1330{
1331 Polygon tri;
1332 tri.add_vertex(Point(0, 0));
1333 tri.add_vertex(Point(4, 0));
1334 tri.add_vertex(Point(0, 3));
1335 tri.close();
1336
1337 EXPECT_EQ(tri.area(), Geom_Number(6)); // (4*3)/2 = 6
1338}
1339
1341{
1342 Polygon square;
1343 square.add_vertex(Point(0, 0));
1344 square.add_vertex(Point(1, 0));
1345 square.add_vertex(Point(1, 1));
1346 square.add_vertex(Point(0, 1));
1347 square.close();
1348
1349 EXPECT_EQ(square.perimeter(), Geom_Number(4));
1350}
1351
1353{
1354 Polygon tri;
1355 tri.add_vertex(Point(0, 0));
1356 tri.add_vertex(Point(3, 0));
1357 tri.add_vertex(Point(0, 4));
1358 tri.close();
1359
1360 // 3 + 4 + 5 = 12
1361 EXPECT_EQ(tri.perimeter(), Geom_Number(12));
1362}
1363
1365{
1366 Polygon square;
1367 square.add_vertex(Point(0, 0));
1368 square.add_vertex(Point(2, 0));
1369 square.add_vertex(Point(2, 2));
1370 square.add_vertex(Point(0, 2));
1371 square.close();
1372
1373 Point c = square.centroid();
1374 EXPECT_EQ(c.get_x(), Geom_Number(1));
1375 EXPECT_EQ(c.get_y(), Geom_Number(1));
1376}
1377
1379{
1380 Polygon tri;
1381 tri.add_vertex(Point(0, 0));
1382 tri.add_vertex(Point(3, 0));
1383 tri.add_vertex(Point(0, 3));
1384 tri.close();
1385
1386 Point c = tri.centroid();
1387 EXPECT_EQ(c.get_x(), Geom_Number(1));
1388 EXPECT_EQ(c.get_y(), Geom_Number(1));
1389}
1390
1392{
1393 Polygon square;
1394 square.add_vertex(Point(0, 0));
1395 square.add_vertex(Point(1, 0));
1396 square.add_vertex(Point(1, 1));
1397 square.add_vertex(Point(0, 1));
1398 square.close();
1399
1400 EXPECT_TRUE(square.is_convex());
1401}
1402
1404{
1405 Polygon tri;
1406 tri.add_vertex(Point(0, 0));
1407 tri.add_vertex(Point(1, 0));
1408 tri.add_vertex(Point(0.5, 1));
1409 tri.close();
1410
1411 EXPECT_TRUE(tri.is_convex());
1412}
1413
1415{
1416 // L-shaped polygon (non-convex)
1418 lshape.add_vertex(Point(0, 0));
1419 lshape.add_vertex(Point(2, 0));
1420 lshape.add_vertex(Point(2, 1));
1421 lshape.add_vertex(Point(1, 1));
1422 lshape.add_vertex(Point(1, 2));
1423 lshape.add_vertex(Point(0, 2));
1424 lshape.close();
1425
1426 EXPECT_FALSE(lshape.is_convex());
1427}
1428
1430{
1431 Polygon line;
1432 line.add_vertex(Point(0, 0));
1433 line.add_vertex(Point(1, 1));
1434
1435 EXPECT_THROW(line.area(), std::domain_error);
1436}
1437
1439{
1441 single.add_vertex(Point(0, 0));
1442
1443 EXPECT_THROW(single.perimeter(), std::domain_error);
1444}
1445
1447{
1448 Polygon line;
1449 line.add_vertex(Point(0, 0));
1450 line.add_vertex(Point(1, 1));
1451
1452 EXPECT_THROW(line.centroid(), std::domain_error);
1453}
1454
1456{
1457 Polygon line;
1458 line.add_vertex(Point(0, 0));
1459 line.add_vertex(Point(1, 1));
1460
1461 EXPECT_THROW(line.is_convex(), std::domain_error);
1462}
1463
1464//============================================================================
1465// Main
1466//============================================================================
1467
1468int main(int argc, char **argv)
1469{
1470 ::testing::InitGoogleTest(&argc, argv);
1471 return RUN_ALL_TESTS();
1472}
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:229
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:457
const Point & leftmost_point() const
Returns the leftmost point (smallest x-coordinate).
Definition point.H:700
const Geom_Number & get_y() const noexcept
Gets the y-coordinate value.
Definition point.H:466
const Point & highest_point() const
Returns the highest point (largest y-coordinate).
Definition point.H:688
const Point & lowest_point() const
Returns the lowest point (smallest y-coordinate).
Definition point.H:694
Iterator over the edges (segments) of a polygon.
Definition polygon.H:520
Segment get_current_segment() const
Get the current segment (edge).
Definition polygon.H:548
bool has_curr() const
Check if there is a current segment.
Definition polygon.H:537
A general (irregular) 2D polygon defined by a sequence of vertices.
Definition polygon.H:246
const Point & rightmost_point() const
Get the vertex with the maximum x-coordinate.
Definition polygon.H:469
Geom_Number signed_area() const
Compute the signed area of the polygon using the shoelace formula.
Definition polygon.H:943
Point centroid() const
Compute the centroid (center of mass) of the polygon.
Definition polygon.H:993
Geom_Number perimeter() const
Compute the perimeter of the polygon.
Definition polygon.H:976
const Point & highest_point() const
Get the vertex with the maximum y-coordinate.
Definition polygon.H:461
Geom_Number area() const
Compute the absolute area of the polygon.
Definition polygon.H:963
const Vertex & get_first_vertex() const
Get the first vertex of the polygon.
Definition polygon.H:578
const Vertex & get_last_vertex() const
Get the last vertex of the polygon.
Definition polygon.H:588
bool is_convex() const
Check if the polygon is convex.
Definition polygon.H:1021
void add_vertex(const Point &point)
Add a vertex to the polygon.
Definition polygon.H:677
Segment get_first_segment() const
Get the first edge (segment) of the polygon.
Definition polygon.H:626
void close()
Close the polygon.
Definition polygon.H:840
const Point & leftmost_point() const
Get the vertex with the minimum x-coordinate.
Definition polygon.H:465
const bool & is_closed() const
Check if the polygon is closed.
Definition polygon.H:473
const size_t & size() const
Get the number of vertices.
Definition polygon.H:477
const Point & lowest_point() const
Get the vertex with the minimum y-coordinate.
Definition polygon.H:457
bool contains(const Point &p) const
Check if a point is inside the polygon (or on its boundary).
Definition polygon.H:926
Iterator over the edges (segments) of a regular polygon.
Definition polygon.H:1308
void next()
Advance to the next segment.
Definition polygon.H:1340
Segment get_current_segment() const
Get the current segment (edge).
Definition polygon.H:1328
bool has_curr() const
Check if there is a current segment.
Definition polygon.H:1323
void next_ne() noexcept
Advance to the next segment (no exception on overflow).
Definition polygon.H:1336
Iterator over the vertices of a regular polygon.
Definition polygon.H:1245
Vertex & get_current_vertex()
Get the current vertex.
Definition polygon.H:1266
bool has_curr() const
Check if there is a current vertex.
Definition polygon.H:1261
void next()
Advance to the next vertex.
Definition polygon.H:1280
void next_ne() noexcept
Advance to the next vertex (no exception on overflow).
Definition polygon.H:1276
A regular polygon defined by center, side length, and vertex count.
Definition polygon.H:1132
Point get_vertex(const size_t &i) const
Get the i-th vertex of the polygon.
Definition polygon.H:1197
const size_t & size() const
Get the number of vertices.
Definition polygon.H:1178
const double & get_side_size() const
Get the side length.
Definition polygon.H:1170
const Point & get_center() const
Get the center point.
Definition polygon.H:1174
const double & radius() const
Get the circumradius.
Definition polygon.H:1182
static bool is_closed()
Check if the polygon is closed.
Definition polygon.H:1186
Represents a line segment between two points.
Definition point.H:827
const Point & get_tgt_point() const noexcept
Gets the target point of the segment.
Definition point.H:921
const Point & get_src_point() const noexcept
Gets the source point of the segment.
Definition point.H:915
Geom_Number length() const
Returns the Euclidean length of the segment.
Definition point.H:1056
A non-degenerate triangle defined by three points.
Definition point.H:1478
A vertex in a polygon's doubly linked vertex list.
Definition polygon.H:119
static Vertex * dlink_to_vertex(Dlink *link)
Convert a Dlink pointer to a Vertex pointer.
Definition polygon.H:159
Point to_point() const
Return this vertex as a plain Point value.
Definition polygon.H:150
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: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
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
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.
mpq_class Geom_Number
Numeric type used by the geometry module.
Definition point.H:115
void next()
Advance all underlying iterators (bounds-checked).
Definition ah-zip.H:171
constexpr double PI
Definition point.H:132
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:489
Vertex & get_current_vertex() const
Get the current vertex.
Definition polygon.H:500
gsl_rng * r