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
305{
306 Point original{7, 11};
308 Point back{polar_form};
309
310 EXPECT_TRUE(approx_equal(back.get_x(), original.get_x()));
311 EXPECT_TRUE(approx_equal(back.get_y(), original.get_y()));
312}
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 Ellipse e(Point(0, 0), 5, 3);
906
907 const Segment inside(Point(-1, 0), Point(1, 0));
910
911 const Segment leaving(Point(0, 0), Point(10, 0));
914 EXPECT_EQ(leaving_clip.get_src_point(), Point(0, 0));
915 EXPECT_EQ(leaving_clip.get_tgt_point(), Point(5, 0));
916
917 const Segment entering(Point(10, 0), Point(0, 0));
918 const Segment entering_clip = e.intersection_with(entering);
919 EXPECT_EQ(entering_clip.get_src_point(), Point(5, 0));
920 EXPECT_EQ(entering_clip.get_tgt_point(), Point(0, 0));
921
922 const Segment tangent(Point(-10, 3), Point(10, 3));
924 EXPECT_EQ(tangent_clip.get_src_point(), Point(0, 3));
925 EXPECT_EQ(tangent_clip.get_tgt_point(), Point(0, 3));
926
927 const Segment crossing(Point(-10, 0), Point(10, 0));
929 Segment(Point(-5, 0), Point(5, 0)));
930
931 const Segment reverse_crossing(Point(10, 0), Point(-10, 0));
933 Segment(Point(5, 0), Point(-5, 0)));
934}
935
937{
938 Ellipse e(Point(0, 0), 5, 3);
939 const Segment inside(Point(1, 1), Point(1, 1));
940 const Segment outside(Point(8, 8), Point(8, 8));
941
944 EXPECT_FALSE(e.intersects_with(outside));
945 EXPECT_THROW(e.intersection_with(outside), std::domain_error);
946}
947
949{
950 EXPECT_TRUE(approx_equal(ellipse.area(), Geom_Number(2) * Geom_Number(PI), 1e-5));
951 EXPECT_GT(ellipse.perimeter(), Geom_Number(0));
952 EXPECT_EQ(ellipse.sample(Geom_Number(0)), Point(2, 0));
953 EXPECT_FALSE(ellipse.to_string().empty());
954 EXPECT_EQ(ellipse, Ellipse(center, 2, 1));
955}
956
957//============================================================================
958// Helper Function Tests
959//============================================================================
960
962{
963 Point a{0, 0};
964 Point b{1, 0};
965 Point c{0, 1};
966
967 Geom_Number area = area_of_parallelogram(a, b, c);
968 EXPECT_EQ(area, 1);
969}
970
972{
973 Point a{0, 0};
974 Point b{0, 1};
975 Point c{1, 0};
976
977 Geom_Number area = area_of_parallelogram(a, b, c);
978 EXPECT_EQ(area, -1);
979}
980
986
992
994{
995 Geom_Number result = arctan(1);
996 EXPECT_TRUE(approx_equal(result.get_d(), PI / 4, 1e-6));
997}
998
1000{
1001 Geom_Number result = arctan2(1, 1);
1002 EXPECT_TRUE(approx_equal(result.get_d(), PI / 4, 1e-6));
1003}
1004
1006{
1007 Geom_Number result = sinus(Geom_Number(PI / 2));
1008 EXPECT_TRUE(approx_equal(result.get_d(), 1.0, 1e-6));
1009}
1010
1012{
1013 Geom_Number result = cosinus(0);
1014 EXPECT_TRUE(approx_equal(result.get_d(), 1.0, 1e-6));
1015}
1016
1018{
1019 Geom_Number result = square_root(4);
1020 EXPECT_TRUE(approx_equal(result.get_d(), 2.0, 1e-6));
1021}
1022
1024{
1025 Geom_Number n{3.14159};
1026 double d = geom_number_to_double(n);
1027 EXPECT_TRUE(approx_equal(d, 3.14159, 1e-4));
1028}
1029
1030//============================================================================
1031// Text and String Utility Tests
1032//============================================================================
1033
1035{
1036 std::string str = "hello";
1037 size_t len = approximate_string_size(str);
1038 EXPECT_EQ(len, 5);
1039}
1040
1042{
1043 std::string str = "\\alpha"; // Latex command counts as 1
1044 size_t len = approximate_string_size(str);
1045 EXPECT_EQ(len, 1);
1046}
1047
1049{
1050 std::string str = "$x$"; // $ signs are skipped
1051 size_t len = approximate_string_size(str);
1052 EXPECT_EQ(len, 1); // Only 'x' counts
1053}
1054
1056{
1057 std::string str = "{ab}";
1058 size_t len = approximate_string_size(str);
1059 EXPECT_EQ(len, 2); // Only 'a' and 'b' count
1060}
1061
1063{
1064 Point p{1, 2};
1065 Text t{p, "Hello"};
1066
1067 EXPECT_EQ(t.get_point(), p);
1068 EXPECT_EQ(t.get_str(), "Hello");
1069 EXPECT_EQ(t.len(), 5);
1070}
1071
1073{
1074 Text t;
1075 // Should not crash
1076}
1077
1079{
1080 Point p{1, 2};
1081 Text t{p, "test"};
1082
1083 EXPECT_EQ(t.highest_point(), p);
1084 EXPECT_EQ(t.lowest_point(), p);
1085 EXPECT_EQ(t.leftmost_point(), p);
1086 EXPECT_EQ(t.rightmost_point(), p);
1087}
1088
1089//============================================================================
1090// Geom_Object Tests
1091//============================================================================
1092
1094{
1095 // Test that virtual destructor works properly
1096 Geom_Object *obj = new Point{1, 2};
1097 delete obj; // Should not crash
1098}
1099
1100//============================================================================
1101// Edge Cases and Regression Tests
1102//============================================================================
1103
1105{
1106 Segment vertical{Point{0, 0}, Point{0, 1}};
1107 double slope = vertical.slope();
1108 EXPECT_GT(slope, 1e10); // Should be very large positive
1109}
1110
1112{
1113 Segment vertical{Point{0, 1}, Point{0, 0}};
1114 double slope = vertical.slope();
1115 EXPECT_LT(slope, -1e10); // Should be very large negative
1116}
1117
1119{
1120 Point src{0, 0};
1121 Geom_Number slope{1}; // 45 degrees
1122 Geom_Number length{std::sqrt(2)};
1123
1124 Segment s{src, slope, length};
1125
1126 EXPECT_TRUE(approx_equal(s.length(), length, 1e-6));
1127}
1128
1130{
1131 Segment original{Point{0, 0}, Point{2, 0}};
1132 Geom_Number dist{1};
1133
1134 Segment parallel{original, dist};
1135
1136 // Parallel segment should have same length
1137 EXPECT_TRUE(approx_equal(parallel.length(), original.length(), 1e-6));
1138}
1139
1141{
1142 Segment s{Point{1, 0}, Point{2, 0}};
1143 Geom_Number original_size = s.length();
1144
1145 s.enlarge_src(1);
1146
1147 // Segment should be longer now
1148 EXPECT_GT(s.length(), original_size);
1149}
1150
1152{
1153 Segment s{Point{0, 0}, Point{1, 0}};
1154 Geom_Number original_size = s.length();
1155
1156 s.enlarge_tgt(1);
1157
1158 // Segment should be longer now
1159 EXPECT_GT(s.length(), original_size);
1160}
1161
1163{
1164 // Points on a line should fail to create a triangle
1165 EXPECT_THROW(Triangle(Point{0,0}, Point{1,1}, Point{2,2}), std::domain_error);
1166}
1167
1169{
1170 Segment s{Point{0, 0}, Point{2, 2}};
1171 Point on_segment{1, 1};
1172
1173 EXPECT_TRUE(on_segment.is_inside(s));
1174}
1175
1177{
1178 Segment s{Point{0, 0}, Point{2, 0}};
1180
1181 // Midpoint of perpendicular should be near midpoint of original
1182 Point mid = s.mid_point();
1183 Point perp_mid = perp.mid_point();
1184
1185 EXPECT_TRUE(approx_equal(mid.distance_to(perp_mid), 0.0, 1e-6));
1186}
1187
1189{
1190 Segment s{Point{1, 1}, Point{1, 1}};
1191 EXPECT_THROW(s.mid_perpendicular(1), std::domain_error);
1192}
1193
1194//============================================================================
1195// Segment-Triangle Intersection Tests
1196//============================================================================
1197
1199{
1200 Triangle t{Point{0, 0}, Point{4, 0}, Point{2, 4}};
1201 Segment s{Point{2, -1}, Point{2, 5}}; // Vertical through triangle
1202
1203 EXPECT_TRUE(s.intersects_with(t));
1204}
1205
1207{
1208 Triangle t{Point{0, 0}, Point{4, 0}, Point{2, 4}};
1209 Segment s{Point{10, 10}, Point{11, 11}}; // Far away
1210
1211 EXPECT_FALSE(s.intersects_with(t));
1212}
1213
1215{
1216 const Triangle t{Point{0, 0}, Point{6, 0}, Point{0, 6}};
1217
1218 const Segment inside{Point{1, 1}, Point{2, 1}};
1219 EXPECT_TRUE(inside.intersects_with(t));
1220 EXPECT_EQ(inside.intersection_with(t), inside);
1221
1222 const Segment leaving{Point{1, 1}, Point{10, 1}};
1224 EXPECT_EQ(leaving_clip.get_src_point(), Point(1, 1));
1225 EXPECT_EQ(leaving_clip.get_tgt_point(), Point(5, 1));
1226
1227 const Segment entering{Point{10, 1}, Point{1, 1}};
1228 const Segment entering_clip = entering.intersection_with(t);
1229 EXPECT_EQ(entering_clip.get_src_point(), Point(5, 1));
1230 EXPECT_EQ(entering_clip.get_tgt_point(), Point(1, 1));
1231
1232 const Segment tangent{Point{-1, 1}, Point{1, -1}};
1234 EXPECT_EQ(tangent_clip.get_src_point(), Point(0, 0));
1235 EXPECT_EQ(tangent_clip.get_tgt_point(), Point(0, 0));
1236
1237 const Segment crossing{Point{-2, 2}, Point{8, 2}};
1238 EXPECT_EQ(crossing.intersection_with(t),
1239 Segment(Point(0, 2), Point(4, 2)));
1240
1241 const Segment reverse_crossing{Point{8, 2}, Point{-2, 2}};
1242 EXPECT_EQ(reverse_crossing.intersection_with(t),
1243 Segment(Point(4, 2), Point(0, 2)));
1244
1245 const Segment boundary_overlap{Point{-2, 0}, Point{8, 0}};
1246 EXPECT_EQ(boundary_overlap.intersection_with(t),
1247 Segment(Point(0, 0), Point(6, 0)));
1248
1249 const Segment reverse_boundary_overlap{Point{8, 0}, Point{-2, 0}};
1250 EXPECT_EQ(reverse_boundary_overlap.intersection_with(t),
1251 Segment(Point(6, 0), Point(0, 0)));
1252}
1253
1255{
1256 const Triangle t{Point{0, 0}, Point{6, 0}, Point{0, 6}};
1257 const Segment inside{Point{1, 1}, Point{1, 1}};
1258 const Segment outside{Point{8, 8}, Point{8, 8}};
1259
1260 EXPECT_TRUE(inside.intersects_with(t));
1261 EXPECT_EQ(inside.intersection_with(t), inside);
1262 EXPECT_FALSE(outside.intersects_with(t));
1263 EXPECT_THROW(outside.intersection_with(t), std::domain_error);
1264}
1265
1266//============================================================================
1267// Main
1268//============================================================================
1269
1270int main(int argc, char **argv)
1271{
1272 testing::InitGoogleTest(&argc, argv);
1273 return RUN_ALL_TESTS();
1274}
int main()
long double h
Definition btreepic.C:154
An axis-aligned ellipse.
Definition point.H:2076
bool intersects_with(const Segment &s) const
Checks if a segment intersects the ellipse.
Definition point.H:2298
static bool is_clockwise()
Returns the orientation of the ellipse.
Definition point.H:2228
Segment intersection_with(const Segment &sg) const
Computes the intersection segment between a line segment and this ellipse.
Definition point.H:2391
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 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 & 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:607
Point rotate(const Geom_Number &angle) const
Rotates the point around the origin by a given angle.
Definition point.H:415
Point normalize() const
Returns a normalized copy of this vector (magnitude 1).
Definition point.H:403
Polar representation of a 2D point.
Definition point.H:728
An axis-aligned rectangle.
Definition point.H:1789
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:1866
Represents a line segment between two points.
Definition point.H:837
Point intersection_with(const Segment &s) const
Computes the intersection point of the infinite lines defined by two segments.
Definition point.H:1334
Segment mid_perpendicular(const Geom_Number &dist) const
Returns the perpendicular chord of a given length passing through the midpoint.
Definition point.H:1225
Segment get_perpendicular(const Point &p) const
Constructs a segment perpendicular to this that passes through point p.
Definition point.H:1203
Represents a text string positioned at a 2D point.
Definition point.H:2817
A non-degenerate triangle defined by three points.
Definition point.H:1512
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).
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
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:2886
bool on_segment(const Segment &s, const Point &p)
Return true if p lies on segment s (exact).
Definition point.H:2961
Geom_Number cosinus(const Geom_Number &x)
Cosine of x (wrapper over mpfr).
Definition point.H:191
Geom_Number square_root(const Geom_Number &x)
Square root of x (wrapper over mpfr).
Definition point.H:197
double geom_number_to_double(const Geom_Number &n)
Converts a Geom_Number to its double precision representation.
Definition point.H:120
bool diff(const C1 &c1, const C2 &c2, Eq e=Eq())
Check if two containers differ.
constexpr double PI_2
Definition point.H:130
mpq_class Geom_Number
Numeric type used by the geometry module.
Definition point.H:113
Geom_Number arctan2(const Geom_Number &m, const Geom_Number &n)
Two-argument arc tangent (wrapper over mpfr).
Definition point.H:179
bool between(const Point &a, const Point &b, const Point &c)
size_t approximate_string_size(const std::string &str)
Estimate the count of printable characters in a LaTeX string.
Definition point.H:2778
Geom_Number arctan(const Geom_Number &m)
Arc tangent of m (wrapper over mpfr).
Definition point.H:173
Geom_Number euclidean_distance(const Geom_Number &x, const Geom_Number &y)
Euclidean distance (hypotenuse) of the vector (x, y).
Definition point.H:160
constexpr double PI
Definition point.H:129
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:185
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
Base class for all geometric objects.
Definition point.H:206
gsl_rng * r
DynList< int > l