Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
segment_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
42#include <gtest/gtest.h>
43#include <point.H>
44#include <cmath>
45
46using namespace std;
47using namespace Aleph;
48
49// =============================================================================
50// Test Fixture
51// =============================================================================
52
53class SegmentTest : public ::testing::Test
54{
55protected:
56 // Common test points
57 Point origin{0, 0};
58 Point p1{10, 0};
59 Point p2{0, 10};
60 Point p3{10, 10};
61 Point p4{5, 5};
62
63 // Helper to compare Geom_Number with tolerance
64 static bool near_equal(const Geom_Number& a, const Geom_Number& b,
65 double epsilon = 1e-9)
66 {
67 return std::abs(geom_number_to_double(a - b)) < epsilon;
68 }
69
70 static bool near_equal(double a, double b, double epsilon = 1e-9)
71 {
72 return std::abs(a - b) < epsilon;
73 }
74};
75
76// =============================================================================
77// Constructor Tests
78// =============================================================================
79
81{
82 Segment s;
83 // Default constructed segment has uninitialized points
84 // Just verify it doesn't crash
85 SUCCEED();
86}
87
89{
90 Segment s(origin, p3);
91 EXPECT_EQ(s.get_src_point(), origin);
92 EXPECT_EQ(s.get_tgt_point(), p3);
93}
94
96{
97 Segment s1(origin, p3);
98 Segment s2(s1);
99 EXPECT_EQ(s2.get_src_point(), s1.get_src_point());
100 EXPECT_EQ(s2.get_tgt_point(), s1.get_tgt_point());
101}
102
104{
105 // Segment from origin with slope 1 and length sqrt(2)
106 Segment s(origin, Geom_Number(1), Geom_Number(std::sqrt(2.0)));
107 // Target should be approximately (1, 1)
108 EXPECT_TRUE(near_equal(s.get_tgt_point().get_x(), 1, 0.01));
109 EXPECT_TRUE(near_equal(s.get_tgt_point().get_y(), 1, 0.01));
110}
111
112// =============================================================================
113// Endpoint Access Tests
114// =============================================================================
115
117{
118 Segment s(origin, p3);
119 EXPECT_EQ(s.get_src_point(), origin);
120 EXPECT_EQ(s.get_tgt_point(), p3);
121}
122
124{
125 Segment s1(origin, p2); // (0,0) to (0,10)
126 EXPECT_EQ(s1.highest_point(), p2);
127
128 Segment s2(p2, origin); // reverse order
129 EXPECT_EQ(s2.highest_point(), p2);
130}
131
133{
134 Segment s1(origin, p2); // (0,0) to (0,10)
135 EXPECT_EQ(s1.lowest_point(), origin);
136
137 Segment s2(p2, origin); // reverse order
138 EXPECT_EQ(s2.lowest_point(), origin);
139}
140
142{
143 Segment s1(origin, p1); // (0,0) to (10,0)
144 EXPECT_EQ(s1.leftmost_point(), origin);
145
146 Segment s2(p1, origin); // reverse order
147 EXPECT_EQ(s2.leftmost_point(), origin);
148}
149
151{
152 Segment s1(origin, p1); // (0,0) to (10,0)
153 EXPECT_EQ(s1.rightmost_point(), p1);
154
155 Segment s2(p1, origin); // reverse order
156 EXPECT_EQ(s2.rightmost_point(), p1);
157}
158
159// =============================================================================
160// Geometric Properties Tests
161// =============================================================================
162
164{
165 Segment horizontal(origin, p1); // length 10
166 EXPECT_TRUE(near_equal(horizontal.length(), 10));
167
168 Segment vertical(origin, p2); // length 10
169 EXPECT_TRUE(near_equal(vertical.length(), 10));
170
171 Segment diagonal(origin, p3); // length sqrt(200) ≈ 14.14
172 EXPECT_TRUE(near_equal(diagonal.length(), std::sqrt(200.0), 0.01));
173}
174
176{
177 Segment s(origin, p3); // (0,0) to (10,10)
178 Point mid = s.mid_point();
179 EXPECT_TRUE(near_equal(mid.get_x(), 5));
180 EXPECT_TRUE(near_equal(mid.get_y(), 5));
181}
182
184{
185 Point n1(-10, -10);
186 Point n2(10, 10);
187 Segment s(n1, n2);
188 Point mid = s.mid_point();
189 EXPECT_TRUE(near_equal(mid.get_x(), 0));
190 EXPECT_TRUE(near_equal(mid.get_y(), 0));
191}
192
194{
195 Segment s45(origin, p3); // 45 degrees, slope = 1
196 EXPECT_TRUE(near_equal(s45.slope(), 1.0));
197
198 Segment horizontal(origin, p1); // slope = 0
199 EXPECT_TRUE(near_equal(horizontal.slope(), 0.0));
200
201 Point neg(-10, 10);
202 Segment negative(origin, neg); // slope = -1
203 EXPECT_TRUE(near_equal(negative.slope(), -1.0));
204}
205
207{
208 Segment vertical(origin, p2); // vertical segment
209 // Vertical segments return max/min double for slope
210 double s = vertical.slope();
211 EXPECT_TRUE(s > 1e10 || s < -1e10);
212}
213
214// =============================================================================
215// Equality Tests
216// =============================================================================
217
219{
220 Segment s1(origin, p3);
221 Segment s2(origin, p3);
222 EXPECT_TRUE(s1 == s2);
223 EXPECT_FALSE(s1 != s2);
224}
225
227{
228 Segment s1(origin, p3);
229 Segment s2(p3, origin);
230 // NOTE: Semantic change from earlier versions:
231 // - Previously, Segment equality was *directed*: Segment(A, B) != Segment(B, A).
232 // - The library now uses *undirected* semantics: Segment(A, B) == Segment(B, A).
233 //
234 // This is a behavioral change that can affect existing code that relied on the
235 // old directed comparison semantics (for example, when using Segment as a key
236 // in associative containers or when detecting orientation-sensitive duplicates).
237 //
238 // Users upgrading from earlier versions should review the API documentation
239 // and migration notes regarding Segment equality/inequality to ensure their
240 // code still behaves as intended.
241 EXPECT_TRUE(s1 == s2);
242}
243
245{
246 Segment s1(origin, p1);
247 Segment s2(origin, p2);
248 EXPECT_FALSE(s1 == s2);
249 EXPECT_TRUE(s1 != s2);
250}
251
252// =============================================================================
253// Colinearity Tests
254// =============================================================================
255
257{
258 Segment s(origin, p3); // diagonal
259 EXPECT_TRUE(s.is_colinear_with(p4)); // (5,5) is on the line
260
261 Point off(5, 6); // not collinear
263}
264
265// =============================================================================
266// Left/Right Tests
267// =============================================================================
268
270{
271 Segment s(origin, p1); // horizontal at y=0
272 Point above(5, 5);
273 Point below(5, -5);
274
275 // Segment is to the left of points above it (depending on orientation)
276 // This depends on the specific implementation
279
280 // Just verify the methods work without crashing
281 SUCCEED();
282}
283
284// =============================================================================
285// Angle Tests
286// =============================================================================
287
289{
290 Segment s(origin, p1); // along x-axis
291 double angle = s.counterclockwise_angle();
292 // Should be close to 0 or 2*PI
293 EXPECT_TRUE(near_equal(angle, 0.0, 0.1) || near_equal(angle, 2*PI, 0.1));
294}
295
297{
298 Segment s1(origin, p1); // along x-axis
299 Segment s2(origin, p2); // along y-axis
300
301 double angle = s1.counterclockwise_angle_with(s2);
302 // 90 degrees counterclockwise from x to y
303 EXPECT_TRUE(near_equal(angle, PI_2, 0.1));
304}
305
307{
308 Segment s(origin, p3);
309 Segment r = s.reversed();
310 EXPECT_EQ(r.get_src_point(), p3);
311 EXPECT_EQ(r.get_tgt_point(), origin);
312}
313
315{
316 Segment s(Point(0, 0), Point(10, 0));
317 Point proj = s.project(Point(3, 4));
318 EXPECT_TRUE(near_equal(proj.get_x(), 3));
319 EXPECT_TRUE(near_equal(proj.get_y(), 0));
320
321 Point clamped = s.project(Point(-5, 2));
322 EXPECT_EQ(clamped, Point(0, 0));
323}
324
326{
327 Segment s(Point(0, 0), Point(10, 0));
328 EXPECT_TRUE(near_equal(s.distance_to(Point(3, 4)), Geom_Number(4), 0.01));
329}
330
331// =============================================================================
332// Parallel Segment Tests
333// =============================================================================
334
336{
337 Segment original(origin, p1); // horizontal at y=0
338 Segment parallel(original, Geom_Number(5)); // 5 units away
339
340 // The parallel segment should have the same length
341 EXPECT_TRUE(near_equal(parallel.length(), original.length(), 0.01));
342
343 // The parallel segment should have a different y coordinate
344 // (shifted by 5 units perpendicular to the original)
345}
346
347// =============================================================================
348// Edge Cases
349// =============================================================================
350
352{
353 Point n1(-10, -10);
354 Point n2(-5, -5);
355 Segment s(n1, n2);
356
357 EXPECT_TRUE(near_equal(s.length(), std::sqrt(50.0), 0.01));
358 Point mid = s.mid_point();
359 EXPECT_TRUE(near_equal(mid.get_x(), -7.5, 0.1));
360 EXPECT_TRUE(near_equal(mid.get_y(), -7.5, 0.1));
361}
362
364{
365 Point same(5, 5);
366 Segment s(same, same);
367 EXPECT_TRUE(near_equal(s.length(), 0));
368}
369
371{
372 Point a(1000000, 1000000);
373 Point b(1000010, 1000010);
374 Segment s(a, b);
375
376 EXPECT_TRUE(near_equal(s.length(), std::sqrt(200.0), 0.01));
377}
378
379int main(int argc, char **argv)
380{
381 ::testing::InitGoogleTest(&argc, argv);
382 return RUN_ALL_TESTS();
383}
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
Point mid_point() const
Returns the midpoint of this segment.
Definition point.H:1115
double slope() const
Returns the slope of the segment.
Definition point.H:999
double counterclockwise_angle() const
Computes the counter-clockwise angle of this segment with respect to the x-axis.
Definition point.H:1046
bool is_left_of(const Point &p) const
Checks if this segment is to the left of a given point.
Definition point.H:1081
Point project(const Point &p) const
Orthogonal projection of a point onto this segment's infinite line, clamped to the segment's endpoint...
Definition point.H:1147
Segment reversed() const
Returns a new segment with the endpoints swapped.
Definition point.H:1127
bool is_right_of(const Point &p) const
Checks if this segment is to the right of a given point.
Definition point.H:1092
Geom_Number distance_to(const Point &p) const
Calculates the Euclidean distance from a point to this segment.
Definition point.H:1169
bool is_colinear_with(const Point &p) const
Checks if a point is collinear with this segment.
Definition point.H:1070
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
static bool near_equal(double a, double b, double epsilon=1e-9)
static bool near_equal(const Geom_Number &a, const Geom_Number &b, double epsilon=1e-9)
bool vertical
If true, use vertical layout (default).
Main namespace for Aleph-w library functions.
Definition ah-arena.H:89
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.
double geom_number_to_double(const Geom_Number &n)
Converts a Geom_Number to its double precision representation.
Definition point.H:122
constexpr double PI_2
Definition point.H:133
mpq_class Geom_Number
Numeric type used by the geometry module.
Definition point.H:115
constexpr double PI
Definition point.H:132
STL namespace.
2D point and geometric utilities.
TEST_F(SegmentTest, DefaultConstructor)
gsl_rng * r