Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
robust_predicates_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
41#include <gtest/gtest.h>
42#include <point.H>
44
45// ===================== Orientation tests =====================
46
48{
49 Point a(0, 0), b(1, 0), c(0, 1);
50 EXPECT_EQ(orientation(a, b, c), Orientation::CCW);
51}
52
54{
55 Point a(0, 0), b(0, 1), c(1, 0);
56 EXPECT_EQ(orientation(a, b, c), Orientation::CW);
57}
58
60{
61 Point a(0, 0), b(1, 1), c(2, 2);
62 EXPECT_EQ(orientation(a, b, c), Orientation::COLLINEAR);
63}
64
66{
67 Point a(3, 5), b(3, 5), c(7, 2);
68 EXPECT_EQ(orientation(a, b, c), Orientation::COLLINEAR);
69}
70
71// ===================== in_circle tests =====================
72
74{
75 Point a(0, 0), b(4, 0), c(0, 4);
76 Point p(1, 1);
77 EXPECT_EQ(in_circle(a, b, c, p), InCircleResult::INSIDE);
78}
79
81{
82 Point a(0, 0), b(0, 4), c(4, 0);
83 Point p(1, 1);
84 EXPECT_EQ(in_circle(a, b, c, p), InCircleResult::INSIDE);
85}
86
88{
89 Point a(0, 0), b(4, 0), c(0, 4);
90 Point p(4, 4);
91
94 scene.segments.append(Segment(b, c));
95 scene.segments.append(Segment(c, a));
96 scene.points.append(a);
97 scene.points.append(b);
98 scene.points.append(c);
99 scene.highlighted_points.append(p);
101 "case_incircle_on_circle", scene,
102 "in_circle() / point on circumcircle");
103
104 EXPECT_EQ(in_circle(a, b, c, p), InCircleResult::ON_CIRCLE);
105}
106
107TEST(InCircle, Outside)
108{
109 Point a(0, 0), b(4, 0), c(0, 4);
110 Point p(5, 5);
111 EXPECT_EQ(in_circle(a, b, c, p), InCircleResult::OUTSIDE);
112}
113
115{
116 Point a(0, 0), b(1, 1), c(2, 2);
117 Point p(0, 3);
118 EXPECT_EQ(in_circle(a, b, c, p), InCircleResult::DEGENERATE);
119}
120
122{
123 Point a(0, 0), b(4, 0), c(0, 4);
124 Point p(1, 1);
125
126 const Geom_Number det_ccw = in_circle_determinant(a, b, c, p);
127 const Geom_Number det_cw = in_circle_determinant(a, c, b, p);
128
129 EXPECT_GT(det_ccw, 0);
130 EXPECT_LT(det_cw, 0);
131}
132
133// ===================== on_segment tests =====================
134
135TEST(OnSegment, Endpoint)
136{
137 Segment s(Point(0, 0), Point(4, 4));
138 EXPECT_TRUE(on_segment(s, Point(0, 0)));
139 EXPECT_TRUE(on_segment(s, Point(4, 4)));
140}
141
143{
144 Segment s(Point(0, 0), Point(4, 4));
145 EXPECT_TRUE(on_segment(s, Point(2, 2)));
146}
147
149{
150 Segment s(Point(0, 0), Point(4, 4));
151 EXPECT_FALSE(on_segment(s, Point(5, 5)));
152}
153
155{
156 Segment s(Point(0, 0), Point(4, 4));
157 EXPECT_FALSE(on_segment(s, Point(1, 2)));
158}
159
160// ============== segments_intersect tests =================
161
163{
164 Segment s1(Point(0, 0), Point(2, 2));
165 Segment s2(Point(0, 2), Point(2, 0));
167}
168
170{
171 // endpoint of s2 touches the interior of s1
172 Segment s1(Point(0, 0), Point(4, 0));
173 Segment s2(Point(2, 0), Point(2, 3));
175}
176
183
185{
186 Segment s1(Point(0, 0), Point(3, 0));
187 Segment s2(Point(2, 0), Point(5, 0));
188
191 scene.segments.append(s2);
192 scene.highlighted_points.append(Point(2, 0));
193 scene.highlighted_points.append(Point(3, 0));
195 "case_segments_collinear_overlap", scene,
196 "segments_intersect() / collinear overlap");
197
199}
200
207
209{
210 Segment s1(Point(0, 0), Point(2, 0));
211 Segment s2(Point(0, 1), Point(2, 1));
213}
214
216{
217 Segment s1(Point(0, 0), Point(1, 1));
218 Segment s2(Point(3, 3), Point(4, 5));
220}
221
223{
225 Point(0, 2), Point(2, 0)));
227 Point(0, 1), Point(1, 1)));
228}
229
230// =========== segment_intersection_point tests ============
231
233{
234 Segment s1(Point(0, 0), Point(2, 2));
235 Segment s2(Point(0, 2), Point(2, 0));
237 EXPECT_EQ(p.get_x(), 1);
238 EXPECT_EQ(p.get_y(), 1);
239}
240
242{
243 // Line 1: (0,0) -> (3,0) (horizontal, y=0)
244 // Line 2: (1,1) -> (2,-1) (slope = -2, y = -2(x-1)+1 = -2x+3)
245 // Intersection: -2x+3=0 => x=3/2, y=0
246 Segment s1(Point(0, 0), Point(3, 0));
247 Segment s2(Point(1, 1), Point(2, -1));
249 EXPECT_EQ(p.get_x(), Geom_Number(3, 2));
250 EXPECT_EQ(p.get_y(), 0);
251}
252
254{
255 // Line 1: (0,0) -> (7,2) direction (7,2)
256 // Line 2: (0,3) -> (3,0) direction (3,-3)
257 // Parametric: p = t*(7,2), q = (0,3)+s*(3,-3)
258 // 7t = 3s => s = 7t/3
259 // 2t = 3 - 3s = 3 - 7t => 9t = 3 => t = 1/3
260 // intersection = (7/3, 2/3)
261 Segment s1(Point(0, 0), Point(7, 2));
262 Segment s2(Point(0, 3), Point(3, 0));
264
267 scene.segments.append(s2);
268 scene.highlighted_points.append(p);
270 "case_intersection_exact_rational_non_trivial", scene,
271 "segment_intersection_point() exact rational");
272
273 EXPECT_EQ(p.get_x(), Geom_Number(7, 3));
274 EXPECT_EQ(p.get_y(), Geom_Number(2, 3));
275}
276
278{
279 Segment vertical(Point(2, 0), Point(2, 4));
280 Segment diagonal(Point(0, 0), Point(4, 4));
282 EXPECT_EQ(p.get_x(), 2);
283 EXPECT_EQ(p.get_y(), 2);
284}
285
287{
288 Segment horizontal(Point(0, 3), Point(6, 3));
289 Segment diagonal(Point(0, 0), Point(6, 6));
290 Point p = segment_intersection_point(horizontal, diagonal);
291 EXPECT_EQ(p.get_x(), 3);
292 EXPECT_EQ(p.get_y(), 3);
293}
294
296{
297 Segment s1(Point(0, 0), Point(2, 2));
298 Segment s2(Point(0, 1), Point(2, 3));
299 EXPECT_THROW(segment_intersection_point(s1, s2), std::domain_error);
300}
301
309
317
319{
320 Segment s1(Point(0, 0), Point(2, 0));
321 Segment s2(Point(2, 0), Point(5, 0));
323
326 scene.segments.append(s2);
327 scene.highlighted_points.append(p);
329 "case_intersection_collinear_touch_endpoint", scene,
330 "segment_intersection_point() / endpoint touching");
331
332 EXPECT_EQ(p.get_x(), 2);
333 EXPECT_EQ(p.get_y(), 0);
334}
335
344
346{
347 Segment s1(Point(3, -1), Point(3, -1));
348 Segment s2(Point(3, -1), Point(3, -1));
350 EXPECT_EQ(p.get_x(), 3);
351 EXPECT_EQ(p.get_y(), -1);
352}
353
354// ============== is_parallel_with tests ===================
355
357{
358 Segment s1(Point(0, 0), Point(3, 6));
359 Segment s2(Point(1, 0), Point(4, 6));
360 EXPECT_TRUE(s1.is_parallel_with(s2));
361}
362
364{
365 Segment s1(Point(0, 0), Point(2, 4));
366 Segment s2(Point(4, 8), Point(2, 4));
367 EXPECT_TRUE(s1.is_parallel_with(s2));
368}
369
371{
372 Segment s1(Point(0, 0), Point(1, 1));
373 Segment s2(Point(0, 0), Point(1, 2));
374 EXPECT_FALSE(s1.is_parallel_with(s2));
375}
376
378{
379 Segment s1(Point(0, 0), Point(0, 5));
380 Segment s2(Point(3, 1), Point(3, 7));
381 EXPECT_TRUE(s1.is_parallel_with(s2));
382}
383
385{
386 Segment s1(Point(0, 0), Point(5, 0));
387 Segment s2(Point(0, 3), Point(5, 3));
388 EXPECT_TRUE(s1.is_parallel_with(s2));
389}
390
391// ============== area_of_triangle tests ====================
392
394{
395 // right triangle with legs 3 and 4 => area = 6
396 Point a(0, 0), b(3, 0), c(0, 4);
397 EXPECT_EQ(area_of_triangle(a, b, c), 6);
398}
399
401{
402 Point a(0, 0), b(1, 1), c(2, 2);
403 EXPECT_EQ(area_of_triangle(a, b, c), 0);
404}
405
407{
408 // Triangle (0,0), (1,0), (0,1) => area = 1/2
409 Point a(0, 0), b(1, 0), c(0, 1);
410 EXPECT_EQ(area_of_triangle(a, b, c), Geom_Number(1, 2));
411}
T & append(const T &data)
Append a copy of data
Definition tpl_array.H:245
Represents a point with rectangular coordinates in a 2D plane.
Definition point.H:229
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
Represents a line segment between two points.
Definition point.H:827
#define TEST(name)
bool vertical
If true, use vertical layout (default).
std::filesystem::path emit_case_svg(const std::string &case_id, const SvgScene &scene, const std::string &note="")
Orientation
Classification of three-point orientation.
Definition point.H:2812
Geom_Number in_circle_determinant(const Point &a, const Point &b, const Point &c, const Point &p)
Return the exact in-circle determinant for (a,b,c,p).
Definition point.H:2835
bool on_segment(const Segment &s, const Point &p)
Return true if p lies on segment s (exact).
Definition point.H:2876
bool segments_intersect(const Segment &s1, const Segment &s2)
Return true if segments s1 and s2 intersect (including endpoints).
Definition point.H:2883
InCircleResult in_circle(const Point &a, const Point &b, const Point &c, const Point &p)
Classify point p against circumcircle of triangle (a,b,c), exactly.
Definition point.H:2857
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.
Point segment_intersection_point(const Segment &s1, const Segment &s2)
Compute the exact intersection point of segments s1 and s2.
Definition point.H:2900
Geom_Number area_of_triangle(const Point &a, const Point &b, const Point &c)
Return the (unsigned) area of triangle (a, b, c) as an exact rational.
Definition point.H:2956
Orientation orientation(const Point &a, const Point &b, const Point &c)
Return the orientation of the triple (a, b, c).
Definition point.H:2821
mpq_class Geom_Number
Numeric type used by the geometry module.
Definition point.H:115
2D point and geometric utilities.