Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
point_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
52#include <gtest/gtest.h>
53#include <cmath>
54#include <unordered_set>
55#include <point.H>
56
57using namespace Aleph;
58
59// Tolerance for floating-point comparisons
60constexpr double EPSILON = 1e-9;
61
62// Helper to compare Geom_Number with tolerance
63bool approx_equal(const Geom_Number & a, const Geom_Number & b,
64 double tol = EPSILON)
65{
66 return std::abs(a.get_d() - b.get_d()) < tol;
67}
68
69bool approx_equal(double a, double b, double tol = EPSILON)
70{
71 return std::abs(a - b) < tol;
72}
73
74//============================================================================
75// Point Tests
76//============================================================================
77
78class PointTest : public ::testing::Test
79{
80protected:
82 Point p1{1, 2};
83 Point p2{3, 4};
84 Point p3{-1, -1};
85};
86
88{
89 EXPECT_EQ(origin.get_x(), 0);
90 EXPECT_EQ(origin.get_y(), 0);
91}
92
94{
95 EXPECT_EQ(p1.get_x(), 1);
96 EXPECT_EQ(p1.get_y(), 2);
97}
98
100{
101 Point p1_copy{1, 2};
102 EXPECT_EQ(p1, p1_copy);
103 EXPECT_NE(p1, p2);
104}
105
107{
108 Point sum = p1 + p2;
109 EXPECT_EQ(sum.get_x(), 4);
110 EXPECT_EQ(sum.get_y(), 6);
111}
112
114{
115 Point p = p1;
116 p += p2;
117 EXPECT_EQ(p.get_x(), 4);
118 EXPECT_EQ(p.get_y(), 6);
119}
120
122{
123 Point diff = p2 - p1;
124 EXPECT_EQ(diff.get_x(), 2);
125 EXPECT_EQ(diff.get_y(), 2);
126}
127
129{
130 Point p = p2;
131 p -= p1;
132 EXPECT_EQ(p.get_x(), 2);
133 EXPECT_EQ(p.get_y(), 2);
134}
135
137{
138 std::string str = origin.to_string();
139 EXPECT_FALSE(str.empty());
140 EXPECT_NE(str.find("0"), std::string::npos);
141}
142
144{
145 std::string str = static_cast<std::string>(p1);
146 EXPECT_FALSE(str.empty());
147}
148
150{
151 Point a{0, 0};
152 Point b{3, 4};
153 Geom_Number dist = a.distance_to(b);
154 EXPECT_TRUE(approx_equal(dist, 5.0));
155}
156
158{
159 Point a{0, 0};
160 Point b{3, 4};
161 Geom_Number dist_sq = a.distance_squared_to(b);
162 EXPECT_EQ(dist_sq, 25);
163}
164
166{
167 Point a{0, 0};
168 Point b{1, 1};
169 Point c{2, 2};
170 Point d{1, 0};
171
172 EXPECT_TRUE(a.is_colinear_with(b, c));
173 EXPECT_FALSE(a.is_colinear_with(b, d));
174}
175
177{
178 Point a{0, 0};
179 Point b{1, 0};
180 Point left{0.5, 1};
181 Point right{0.5, -1};
182
183 EXPECT_TRUE(left.is_left_of(a, b));
184 EXPECT_FALSE(right.is_left_of(a, b));
185}
186
188{
189 Point a{0, 0};
190 Point b{1, 0};
191 Point left{0.5, 1};
192 Point right{0.5, -1};
193
194 EXPECT_TRUE(right.is_to_right_from(a, b)); // intentionally kept with legacy name for this overload (backward compatibility; differs from is_left_of naming pattern)
195 EXPECT_FALSE(left.is_to_right_from(a, b));
196}
197
199{
200 Point a{0, 0};
201 Point b{1, 0};
202 Point on_line{0.5, 0};
203 Point left{0.5, 1};
204
205 EXPECT_TRUE(on_line.is_to_left_on_from(a, b)); // not deprecated
206 EXPECT_TRUE(left.is_to_left_on_from(a, b));
207}
208
210{
211 Point a{0, 0};
212 Point b{1, 0};
213 Point c{0.5, -1}; // Below line a-b -> clockwise
214
215 EXPECT_TRUE(a.is_clockwise_with(b, c));
216}
217
219{
220 Point a{0, 0};
221 Point b{2, 2};
222 Point between{1, 1};
223 Point outside{3, 3};
224
225 EXPECT_TRUE(between.is_between(a, b));
226 EXPECT_FALSE(outside.is_between(a, b));
227}
228
230{
231 Point ref{0, 0};
232 Point near{1, 1};
233 Point far{10, 10};
234
235 const Point & nearest = ref.nearest_point(near, far);
236 EXPECT_EQ(nearest, near);
237}
238
240{
241 EXPECT_EQ(p1.highest_point(), p1);
242 EXPECT_EQ(p1.lowest_point(), p1);
243 EXPECT_EQ(p1.leftmost_point(), p1);
244 EXPECT_EQ(p1.rightmost_point(), p1);
245}
246
248{
249 Point v{3, 4};
250 EXPECT_EQ(v.norm_squared(), Geom_Number(25));
251 EXPECT_TRUE(approx_equal(v.norm(), Geom_Number(5), 1e-9));
252
253 Point unit = v.normalize();
254 EXPECT_TRUE(approx_equal(unit.norm(), Geom_Number(1), 1e-6));
255
257 EXPECT_TRUE(approx_equal(rotated.get_x(), Geom_Number(0), 1e-6));
258 EXPECT_TRUE(approx_equal(rotated.get_y(), Geom_Number(1), 1e-6));
259
260 Point a{0, 0};
261 Point b{10, 10};
262 EXPECT_EQ(a.midpoint(b), Point(5, 5));
263 EXPECT_EQ(a.lerp(b, Geom_Number(1, 2)), Point(5, 5));
264 EXPECT_EQ(Geom_Number(2) * Point(3, 4), Point(6, 8));
265}
266
268{
269 EXPECT_TRUE(Point(0, 0) < Point(0, 1));
270 EXPECT_TRUE(Point(0, 1) < Point(1, 0));
271 EXPECT_FALSE(Point(1, 0) < Point(1, 0));
272}
273
275{
276 std::unordered_set<Point> set;
277 set.insert(Point(1, 2));
278 EXPECT_EQ(set.count(Point(1, 2)), 1u);
279}
280
281//============================================================================
282// Polar_Point Tests
283//============================================================================
284
285class PolarPointTest : public ::testing::Test
286{
287protected:
290};
291
296
298{
299 Point back(polar);
300 EXPECT_TRUE(approx_equal(back.get_x(), 3.0));
301 EXPECT_TRUE(approx_equal(back.get_y(), 4.0));
302}
303
313
315{
316 Point p{1, 1};
317 Polar_Point pp{p};
318 EXPECT_EQ(pp.get_quadrant(), Polar_Point::First);
319}
320
322{
323 Point p{-1, 1};
324 Polar_Point pp{p};
325 EXPECT_EQ(pp.get_quadrant(), Polar_Point::Second);
326}
327
329{
330 Point p{-1, -1};
331 Polar_Point pp{p};
332 EXPECT_EQ(pp.get_quadrant(), Polar_Point::Third);
333}
334
336{
337 Point p{1, -1};
338 Polar_Point pp{p};
339 EXPECT_EQ(pp.get_quadrant(), Polar_Point::Fourth);
340}
341
343{
344 std::string str = polar.to_string();
345 EXPECT_FALSE(str.empty());
346 EXPECT_EQ(str[0], '[');
347}
348
350{
352 EXPECT_EQ(pp.get_r(), 0);
353 EXPECT_EQ(pp.get_theta(), 0);
354}
355
356//============================================================================
357// Segment Tests
358//============================================================================
359
360class SegmentTest : public ::testing::Test
361{
362protected:
364 Point p1{1, 0};
365 Point p2{0, 1};
366 Point p3{1, 1};
367
371};
372
374{
375 Segment s;
376 // Should not crash
377}
378
380{
381 EXPECT_EQ(horizontal.get_src_point(), origin);
382 EXPECT_EQ(horizontal.get_tgt_point(), p1);
383}
384
386{
387 Segment s1{origin, p1};
388 Segment s2{origin, p1};
389 Segment s3{origin, p2};
390
391 EXPECT_EQ(s1, s2);
392 EXPECT_NE(s1, s3);
393}
394
396{
397 Geom_Number len = horizontal.length();
398 EXPECT_TRUE(approx_equal(len, 1.0));
399
400 Segment longer{Point{0, 0}, Point{3, 4}};
401 EXPECT_TRUE(approx_equal(longer.length(), 5.0));
402}
403
405{
406 EXPECT_TRUE(approx_equal(horizontal.slope(), 0.0));
407 EXPECT_TRUE(approx_equal(diagonal.slope(), 1.0));
408}
409
411{
412 Point mid = diagonal.mid_point();
413 EXPECT_TRUE(approx_equal(mid.get_x(), 0.5));
414 EXPECT_TRUE(approx_equal(mid.get_y(), 0.5));
415}
416
418{
419 Segment s{Point{0, 0}, Point{1, 2}};
420 const Point & h = s.highest_point();
421 EXPECT_EQ(h.get_y(), 2);
422}
423
425{
426 Segment s{Point{0, 0}, Point{1, 2}};
427 const Point & l = s.lowest_point();
428 EXPECT_EQ(l.get_y(), 0);
429}
430
432{
433 Segment s{Point{2, 0}, Point{0, 1}};
434 const Point & l = s.leftmost_point();
435 EXPECT_EQ(l.get_x(), 0);
436}
437
439{
440 Segment s{Point{2, 0}, Point{0, 1}};
441 const Point & r = s.rightmost_point();
442 EXPECT_EQ(r.get_x(), 2);
443}
444
446{
447 Point inside{0.5, 0.5};
448 Point outside{2, 2};
449
450 EXPECT_TRUE(diagonal.contains(inside));
451 EXPECT_FALSE(diagonal.contains(outside));
452}
453
455{
456 Point colinear{0.5, 0.5};
457 Point not_colinear{0.5, 0.6};
458
459 EXPECT_TRUE(diagonal.is_colinear_with(colinear));
460 EXPECT_FALSE(diagonal.is_colinear_with(not_colinear));
461}
462
464{
465 Segment s1{Point{0, 0}, Point{1, 1}};
466 Segment s2{Point{1, 0}, Point{2, 1}}; // Parallel
467 Segment s3{Point{0, 0}, Point{1, 0}}; // Not parallel
468
469 EXPECT_TRUE(s1.is_parallel_with(s2));
470 EXPECT_FALSE(s1.is_parallel_with(s3));
471}
472
474{
475 Segment s1{Point{0, 0}, Point{2, 2}};
476 Segment s2{Point{0, 2}, Point{2, 0}}; // Cross
477 Segment s3{Point{3, 0}, Point{4, 0}}; // No intersection
478
479 EXPECT_TRUE(s1.intersects_with(s2));
480 EXPECT_FALSE(s1.intersects_with(s3));
481}
482
484{
485 Segment s1{Point{0, 0}, Point{2, 2}};
486 Segment s2{Point{0, 2}, Point{2, 0}}; // Proper cross
487
488 EXPECT_TRUE(s1.intersects_properly_with(s2));
489}
490
492{
493 Segment s1{Point{0, 0}, Point{2, 2}};
494 Segment s2{Point{0, 2}, Point{2, 0}};
495
496 Point inter = s1.intersection_with(s2);
497 EXPECT_TRUE(approx_equal(inter.get_x(), 1.0));
498 EXPECT_TRUE(approx_equal(inter.get_y(), 1.0));
499}
500
502{
503 Segment s1{Point{0, 0}, Point{1, 1}};
504 Segment s2{Point{0, 1}, Point{1, 2}}; // Parallel
505
506 EXPECT_THROW(s1.intersection_with(s2), std::domain_error);
507}
508
510{
511 Segment s{Point{0, 0}, Point{1, 0}};
512 EXPECT_EQ(s.sense(), Segment::E);
513}
514
516{
517 Segment s{Point{1, 0}, Point{0, 0}};
518 EXPECT_EQ(s.sense(), Segment::W);
519}
520
522{
523 Segment s{Point{0, 0}, Point{0, 1}};
524 EXPECT_EQ(s.sense(), Segment::N);
525}
526
528{
529 Segment s{Point{0, 1}, Point{0, 0}};
530 EXPECT_EQ(s.sense(), Segment::S);
531}
532
534{
535 Segment s{Point{0, 0}, Point{1, 1}};
536 EXPECT_EQ(s.sense(), Segment::NE);
537}
538
540{
541 Segment s{Point{1, 1}, Point{0, 0}};
542 EXPECT_EQ(s.sense(), Segment::SW);
543}
544
546{
547 Segment s{Point{1, 0}, Point{0, 1}};
548 EXPECT_EQ(s.sense(), Segment::NW);
549}
550
552{
553 Segment s{Point{0, 1}, Point{1, 0}};
554 EXPECT_EQ(s.sense(), Segment::SE);
555}
556
558{
559 std::string str = diagonal.to_string();
560 EXPECT_FALSE(str.empty());
561}
562
564{
565 Segment s{Point{0, 0}, Point{1, 0}};
566 s.rotate(PI / 2); // Rotate 90 degrees
567
568 EXPECT_TRUE(approx_equal(s.get_tgt_point().get_x(), 0.0, 1e-6));
569 EXPECT_TRUE(approx_equal(s.get_tgt_point().get_y(), 1.0, 1e-6));
570}
571
573{
574 Segment s{Point{0, 0}, Point{2, 0}};
575 Point p{1, 1};
576
578 // Perpendicular from (1,1) to horizontal line should hit (1,0)
579 EXPECT_TRUE(approx_equal(perp.get_src_point().get_x(), 1.0, 1e-6));
580 EXPECT_TRUE(approx_equal(perp.get_src_point().get_y(), 0.0, 1e-6));
581}
582
584{
585 Segment s{Point{0, 0}, Point{1, 0}};
586 double angle = s.counterclockwise_angle();
587 EXPECT_TRUE(approx_equal(angle, 0.0, 1e-6));
588}
589
590//============================================================================
591// Triangle Tests
592//============================================================================
593
594class TriangleTest : public ::testing::Test
595{
596protected:
597 Point p1{0, 0};
598 Point p2{4, 0};
599 Point p3{0, 3};
601};
602
604{
605 EXPECT_EQ(t.get_p1(), p1);
606 EXPECT_EQ(t.get_p2(), p2);
607 EXPECT_EQ(t.get_p3(), p3);
608}
609
611{
612 Segment s{p2, p3};
613 Triangle t2{p1, s};
614
615 EXPECT_EQ(t2.get_p1(), p1);
616}
617
619{
620 Segment s{p1, p2};
621 Triangle t2{s, p3};
622
623 EXPECT_EQ(t2.get_p3(), p3);
624}
625
627{
628 Point a{0, 0};
629 Point b{1, 1};
630 Point c{2, 2};
631
632 EXPECT_THROW(Triangle(a, b, c), std::domain_error);
633}
634
636{
637 // 3-4-5 right triangle has area = (1/2)*3*4 = 6
638 Geom_Number area = t.area();
639 EXPECT_EQ(area, 6);
640}
641
643{
644 Point inside{1, 1};
645 Point outside{5, 5};
646
647 EXPECT_TRUE(t.contains(inside));
648 EXPECT_FALSE(t.contains(outside));
649}
650
652{
653 const Point & h = t.highest_point();
654 EXPECT_EQ(h.get_y(), 3);
655}
656
658{
659 const Point & l = t.lowest_point();
660 EXPECT_EQ(l.get_y(), 0);
661}
662
664{
665 const Point & l = t.leftmost_point();
666 EXPECT_EQ(l.get_x(), 0);
667}
668
670{
671 const Point & r = t.rightmost_point();
672 EXPECT_EQ(r.get_x(), 4);
673}
674
676{
677 // Counter-clockwise triangle
678 Triangle ccw{Point{0,0}, Point{1,0}, Point{0,1}};
679
680 // Clockwise triangle
681 Triangle cw{Point{0,0}, Point{0,1}, Point{1,0}};
682
683 // Note: the is_clockwise check depends on sign of area
684 EXPECT_NE(ccw.is_clockwise(), cw.is_clockwise());
685}
686
687//============================================================================
688// Rectangle Tests
689//============================================================================
690
691class RectangleTest : public ::testing::Test
692{
693protected:
694 Rectangle r{0, 0, 4, 3};
695};
696
698{
700 EXPECT_EQ(r_default.get_xmin(), 0);
701 EXPECT_EQ(r_default.get_ymin(), 0);
702 EXPECT_EQ(r_default.get_xmax(), 0);
703 EXPECT_EQ(r_default.get_ymax(), 0);
704}
705
707{
708 EXPECT_EQ(r.get_xmin(), 0);
709 EXPECT_EQ(r.get_ymin(), 0);
710 EXPECT_EQ(r.get_xmax(), 4);
711 EXPECT_EQ(r.get_ymax(), 3);
712}
713
715{
716 EXPECT_THROW(Rectangle(4, 0, 0, 3), std::range_error); // xmax < xmin
717 EXPECT_THROW(Rectangle(0, 3, 4, 0), std::range_error); // ymax < ymin
718}
719
721{
722 EXPECT_EQ(r.width(), 4);
723}
724
726{
727 EXPECT_EQ(r.height(), 3);
728}
729
731{
732 Point inside{2, 1};
733 Point outside{5, 5};
734 Point on_edge{0, 0};
735
736 EXPECT_TRUE(r.contains(inside));
737 EXPECT_FALSE(r.contains(outside));
738 EXPECT_TRUE(r.contains(on_edge));
739}
740
742{
743 Rectangle r2{2, 1, 6, 4}; // Overlaps
744 Rectangle r3{5, 5, 6, 6}; // No overlap
745
746 EXPECT_TRUE(r.intersects(r2));
747 EXPECT_FALSE(r.intersects(r3));
748}
749
751{
752 Point inside{2, 1};
753 Point outside{5, 0}; // Distance 1 from right edge
754
755 EXPECT_EQ(r.distance_squared_to(inside), 0);
756 EXPECT_EQ(r.distance_squared_to(outside), 1);
757}
758
760{
761 Point outside{5, 0};
762 Geom_Number dist = r.distance_to(outside);
763 EXPECT_TRUE(approx_equal(dist, 1.0));
764}
765
767{
769 r_mod.set_rect(1, 2, 3, 4);
770
771 EXPECT_EQ(r_mod.get_xmin(), 1);
772 EXPECT_EQ(r_mod.get_ymin(), 2);
773 EXPECT_EQ(r_mod.get_xmax(), 3);
774 EXPECT_EQ(r_mod.get_ymax(), 4);
775}
776
778{
780 EXPECT_THROW(r_mod.set_rect(3, 2, 1, 4), std::range_error);
781}
782
783//============================================================================
784// Ellipse Tests
785//============================================================================
786
787class EllipseTest : public ::testing::Test
788{
789protected:
791 Ellipse circle{center, 1, 1}; // Unit circle
792 Ellipse ellipse{center, 2, 1}; // Horizontal ellipse
793};
794
796{
797 Ellipse e;
798 // Should not crash
799}
800
802{
803 EXPECT_EQ(ellipse.get_center(), center);
804 EXPECT_EQ(ellipse.get_hradius(), 2);
805 EXPECT_EQ(ellipse.get_vradius(), 1);
806}
807
809{
810 Ellipse e2{ellipse};
811 EXPECT_EQ(e2.get_center(), ellipse.get_center());
812 EXPECT_EQ(e2.get_hradius(), ellipse.get_hradius());
813 EXPECT_EQ(e2.get_vradius(), ellipse.get_vradius());
814}
815
817{
818 Point h = ellipse.highest_point();
819 EXPECT_EQ(h.get_x(), 0);
820 EXPECT_EQ(h.get_y(), 1);
821}
822
824{
825 Point l = ellipse.lowest_point();
826 EXPECT_EQ(l.get_x(), 0);
827 EXPECT_EQ(l.get_y(), -1);
828}
829
831{
832 Point l = ellipse.leftmost_point();
833 EXPECT_EQ(l.get_x(), -2);
834 EXPECT_EQ(l.get_y(), 0);
835}
836
838{
839 Point r = ellipse.rightmost_point();
840 EXPECT_EQ(r.get_x(), 2);
841 EXPECT_EQ(r.get_y(), 0);
842}
843
845{
846 EXPECT_TRUE(circle.contains(center));
847}
848
850{
851 Point inside{0.5, 0.5};
852 EXPECT_TRUE(circle.contains(inside));
853}
854
856{
857 Point outside{2, 2};
858 EXPECT_FALSE(circle.contains(outside));
859}
860
862{
863 Point on_border{1, 0};
864 EXPECT_TRUE(circle.contains(on_border));
865}
866
868{
869 Point on_border{1, 0};
870 EXPECT_TRUE(circle.intersects_with(on_border));
871}
872
877
879{
880 Point inside{0.5, 0};
881 EXPECT_TRUE(inside.is_inside(circle));
882}
883
890
892{
893 Ellipse e(Point(0, 0), 5, 3);
894 Segment horizontal(Point(-10, 0), Point(10, 0));
895 Segment inter = e.intersection_with(horizontal);
896
897 EXPECT_TRUE(approx_equal(inter.get_src_point().get_y(), Geom_Number(0), 1e-8));
898 EXPECT_TRUE(approx_equal(inter.get_tgt_point().get_y(), Geom_Number(0), 1e-8));
899 EXPECT_TRUE(approx_equal(inter.get_src_point().get_x(), Geom_Number(-5), 1e-8));
900 EXPECT_TRUE(approx_equal(inter.get_tgt_point().get_x(), Geom_Number(5), 1e-8));
901}
902
904{
905 EXPECT_TRUE(approx_equal(ellipse.area(), Geom_Number(2) * Geom_Number(PI), 1e-5));
906 EXPECT_GT(ellipse.perimeter(), Geom_Number(0));
907 EXPECT_EQ(ellipse.sample(Geom_Number(0)), Point(2, 0));
908 EXPECT_FALSE(ellipse.to_string().empty());
909 EXPECT_EQ(ellipse, Ellipse(center, 2, 1));
910}
911
912//============================================================================
913// Helper Function Tests
914//============================================================================
915
917{
918 Point a{0, 0};
919 Point b{1, 0};
920 Point c{0, 1};
921
922 Geom_Number area = area_of_parallelogram(a, b, c);
923 EXPECT_EQ(area, 1);
924}
925
927{
928 Point a{0, 0};
929 Point b{0, 1};
930 Point c{1, 0};
931
932 Geom_Number area = area_of_parallelogram(a, b, c);
933 EXPECT_EQ(area, -1);
934}
935
941
947
949{
950 Geom_Number result = arctan(1);
951 EXPECT_TRUE(approx_equal(result.get_d(), PI / 4, 1e-6));
952}
953
955{
956 Geom_Number result = arctan2(1, 1);
957 EXPECT_TRUE(approx_equal(result.get_d(), PI / 4, 1e-6));
958}
959
961{
962 Geom_Number result = sinus(Geom_Number(PI / 2));
963 EXPECT_TRUE(approx_equal(result.get_d(), 1.0, 1e-6));
964}
965
967{
968 Geom_Number result = cosinus(0);
969 EXPECT_TRUE(approx_equal(result.get_d(), 1.0, 1e-6));
970}
971
973{
974 Geom_Number result = square_root(4);
975 EXPECT_TRUE(approx_equal(result.get_d(), 2.0, 1e-6));
976}
977
979{
980 Geom_Number n{3.14159};
981 double d = geom_number_to_double(n);
982 EXPECT_TRUE(approx_equal(d, 3.14159, 1e-4));
983}
984
985//============================================================================
986// Text and String Utility Tests
987//============================================================================
988
990{
991 std::string str = "hello";
992 size_t len = approximate_string_size(str);
993 EXPECT_EQ(len, 5);
994}
995
997{
998 std::string str = "\\alpha"; // Latex command counts as 1
999 size_t len = approximate_string_size(str);
1000 EXPECT_EQ(len, 1);
1001}
1002
1004{
1005 std::string str = "$x$"; // $ signs are skipped
1006 size_t len = approximate_string_size(str);
1007 EXPECT_EQ(len, 1); // Only 'x' counts
1008}
1009
1011{
1012 std::string str = "{ab}";
1013 size_t len = approximate_string_size(str);
1014 EXPECT_EQ(len, 2); // Only 'a' and 'b' count
1015}
1016
1018{
1019 Point p{1, 2};
1020 Text t{p, "Hello"};
1021
1022 EXPECT_EQ(t.get_point(), p);
1023 EXPECT_EQ(t.get_str(), "Hello");
1024 EXPECT_EQ(t.len(), 5);
1025}
1026
1028{
1029 Text t;
1030 // Should not crash
1031}
1032
1034{
1035 Point p{1, 2};
1036 Text t{p, "test"};
1037
1038 EXPECT_EQ(t.highest_point(), p);
1039 EXPECT_EQ(t.lowest_point(), p);
1040 EXPECT_EQ(t.leftmost_point(), p);
1041 EXPECT_EQ(t.rightmost_point(), p);
1042}
1043
1044//============================================================================
1045// Geom_Object Tests
1046//============================================================================
1047
1049{
1050 // Test that virtual destructor works properly
1051 Geom_Object *obj = new Point{1, 2};
1052 delete obj; // Should not crash
1053}
1054
1055//============================================================================
1056// Edge Cases and Regression Tests
1057//============================================================================
1058
1060{
1061 Segment vertical{Point{0, 0}, Point{0, 1}};
1062 double slope = vertical.slope();
1063 EXPECT_GT(slope, 1e10); // Should be very large positive
1064}
1065
1067{
1068 Segment vertical{Point{0, 1}, Point{0, 0}};
1069 double slope = vertical.slope();
1070 EXPECT_LT(slope, -1e10); // Should be very large negative
1071}
1072
1074{
1075 Point src{0, 0};
1076 Geom_Number slope{1}; // 45 degrees
1077 Geom_Number length{std::sqrt(2)};
1078
1079 Segment s{src, slope, length};
1080
1081 EXPECT_TRUE(approx_equal(s.length(), length, 1e-6));
1082}
1083
1085{
1086 Segment original{Point{0, 0}, Point{2, 0}};
1087 Geom_Number dist{1};
1088
1089 Segment parallel{original, dist};
1090
1091 // Parallel segment should have same length
1092 EXPECT_TRUE(approx_equal(parallel.length(), original.length(), 1e-6));
1093}
1094
1096{
1097 Segment s{Point{1, 0}, Point{2, 0}};
1098 Geom_Number original_size = s.length();
1099
1100 s.enlarge_src(1);
1101
1102 // Segment should be longer now
1103 EXPECT_GT(s.length(), original_size);
1104}
1105
1107{
1108 Segment s{Point{0, 0}, Point{1, 0}};
1109 Geom_Number original_size = s.length();
1110
1111 s.enlarge_tgt(1);
1112
1113 // Segment should be longer now
1114 EXPECT_GT(s.length(), original_size);
1115}
1116
1118{
1119 // Points on a line should fail to create a triangle
1120 EXPECT_THROW(Triangle(Point{0,0}, Point{1,1}, Point{2,2}), std::domain_error);
1121}
1122
1124{
1125 Segment s{Point{0, 0}, Point{2, 2}};
1126 Point on_segment{1, 1};
1127
1128 EXPECT_TRUE(on_segment.is_inside(s));
1129}
1130
1132{
1133 Segment s{Point{0, 0}, Point{2, 0}};
1135
1136 // Midpoint of perpendicular should be near midpoint of original
1137 Point mid = s.mid_point();
1138 Point perp_mid = perp.mid_point();
1139
1140 EXPECT_TRUE(approx_equal(mid.distance_to(perp_mid), 0.0, 1e-6));
1141}
1142
1144{
1145 Segment s{Point{1, 1}, Point{1, 1}};
1146 EXPECT_THROW(s.mid_perpendicular(1), std::domain_error);
1147}
1148
1149//============================================================================
1150// Segment-Triangle Intersection Tests
1151//============================================================================
1152
1154{
1155 Triangle t{Point{0, 0}, Point{4, 0}, Point{2, 4}};
1156 Segment s{Point{2, -1}, Point{2, 5}}; // Vertical through triangle
1157
1158 EXPECT_TRUE(s.intersects_with(t));
1159}
1160
1162{
1163 Triangle t{Point{0, 0}, Point{4, 0}, Point{2, 4}};
1164 Segment s{Point{10, 10}, Point{11, 11}}; // Far away
1165
1166 EXPECT_FALSE(s.intersects_with(t));
1167}
1168
1169//============================================================================
1170// Main
1171//============================================================================
1172
1173int main(int argc, char **argv)
1174{
1175 testing::InitGoogleTest(&argc, argv);
1176 return RUN_ALL_TESTS();
1177}
long double h
Definition btreepic.C:154
An axis-aligned ellipse.
Definition point.H:2006
bool intersects_with(const Segment &s) const
Checks if a segment intersects the ellipse.
Definition point.H:2224
static bool is_clockwise()
Returns the orientation of the ellipse.
Definition point.H:2156
Segment intersection_with(const Segment &sg) const
Computes the intersection segment between a line segment and this ellipse.
Definition point.H:2311
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 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 & nearest_point(const Point &p1, const Point &p2) const
Returns which of the two points, p1 or p2, is nearer to this point.
Definition point.H:618
Point rotate(const Geom_Number &angle) const
Rotates the point around the origin by a given angle.
Definition point.H:424
Point normalize() const
Returns a normalized copy of this vector (magnitude 1).
Definition point.H:412
Polar representation of a 2D point.
Definition point.H:726
An axis-aligned rectangle.
Definition point.H:1737
void set_rect(const Geom_Number &xmin, const Geom_Number &ymin, const Geom_Number &xmax, const Geom_Number &ymax)
Sets the coordinates of the rectangle.
Definition point.H:1803
Represents a line segment between two points.
Definition point.H:827
Segment mid_perpendicular(const Geom_Number &dist) const
Returns the perpendicular chord of a given length passing through the midpoint.
Definition point.H:1212
Segment get_perpendicular(const Point &p) const
Constructs a segment perpendicular to this that passes through point p.
Definition point.H:1190
Represents a text string positioned at a 2D point.
Definition point.H:2739
A non-degenerate triangle defined by three points.
Definition point.H:1478
Ellipse ellipse
Ellipse circle
Point origin
Definition point_test.cc:81
Polar_Point polar
Rectangle r
Segment diagonal
Segment vertical
Segment horizontal
#define TEST(name)
bool vertical
If true, use vertical layout (default).
Main namespace for Aleph-w library functions.
Definition ah-arena.H:89
Geom_Number area_of_parallelogram(const Point &a, const Point &b, const Point &c)
Compute the signed area of the parallelogram defined by vectors a->b and a->c.
Definition point.H:2803
bool on_segment(const Segment &s, const Point &p)
Return true if p lies on segment s (exact).
Definition point.H:2876
Geom_Number cosinus(const Geom_Number &x)
Cosine of x (wrapper over mpfr).
Definition point.H:199
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.
Geom_Number square_root(const Geom_Number &x)
Square root of x (wrapper over mpfr).
Definition point.H:205
double geom_number_to_double(const Geom_Number &n)
Converts a Geom_Number to its double precision representation.
Definition point.H:122
bool diff(const C1 &c1, const C2 &c2, Eq e=Eq())
Check if two containers differ.
constexpr double PI_2
Definition point.H:133
mpq_class Geom_Number
Numeric type used by the geometry module.
Definition point.H:115
Geom_Number arctan2(const Geom_Number &m, const Geom_Number &n)
Two-argument arc tangent (wrapper over mpfr).
Definition point.H:187
size_t approximate_string_size(const std::string &str)
Estimate the count of printable characters in a LaTeX string.
Definition point.H:2700
Geom_Number arctan(const Geom_Number &m)
Arc tangent of m (wrapper over mpfr).
Definition point.H:181
Geom_Number euclidean_distance(const Geom_Number &x, const Geom_Number &y)
Euclidean distance (hypotenuse) of the vector (x, y).
Definition point.H:167
constexpr double PI
Definition point.H:132
T sum(const Container &container, const T &init=T{})
Compute sum of all elements.
Geom_Number sinus(const Geom_Number &x)
Sine of x (wrapper over mpfr).
Definition point.H:193
2D point and geometric utilities.
constexpr double EPSILON
Definition point_test.cc:60
TEST_F(PointTest, DefaultConstruction)
Definition point_test.cc:87
bool approx_equal(const Geom_Number &a, const Geom_Number &b, double tol=EPSILON)
Definition point_test.cc:63
bool between(const Point &a, const Point &b, const Point &c)
Definition point_utils.H:99
Base class for all geometric objects.
Definition point.H:214
gsl_rng * r
DynList< int > l