43TEST(LineTest, VectorAndVersor) {
52TEST(LineTest, AngleBisector) {
53 Point o(0,0), a(1,1), b(3,0),
c(-4, 0);
54 Point d(0.5231, 0.75223);
84TEST(LineTest, Reflection) {
86 Point pa(10,5), ra(15,0);
89 Point pb(5,1), rb(1,3);
92 Point testra = pa * reflecta;
93 Point testrb = pb * reflectb;
95 constexpr Coord eps{1e-12};
96 EXPECT_near(testra[
X], ra[
X], eps);
97 EXPECT_near(testra[
Y], ra[
Y], eps);
98 EXPECT_near(testrb[
X], rb[
X], eps);
99 EXPECT_near(testrb[
Y], rb[
Y], eps);
102TEST(LineTest, RotationToZero) {
107 for (
unsigned i = 0; i <= 12; ++i) {
108 double t = -1 + 0.25 * i;
114 EXPECT_NEAR(rx[
X], 0, 1e-14);
115 EXPECT_NEAR(ry[
Y], 0, 1e-14);
120 std::vector<Line> lines;
121 lines.emplace_back(
Point(1e3,1e3),
Point(1,1));
124 lines.emplace_back(
Point(1e5,1e5),
Point(1e5,-1e5));
125 lines.emplace_back(
Point(-3,10),
Point(3,10));
126 lines.emplace_back(
Point(250,333),
Point(-72,121));
128 for (
auto & line : lines) {
130 line.coefficients(a, b,
c);
140 EXPECT_DOUBLE_EQ(a, A);
141 EXPECT_DOUBLE_EQ(b, B);
142 EXPECT_DOUBLE_EQ(
c, C);
144 for (
unsigned j = 0; j <= 10; ++j) {
146 Point p = line.pointAt(t);
150 EXPECT_near(A*p[
X] + B*p[
Y] + C, 0., 2e-11);
151 EXPECT_not_near(A*(p[
X]-1) + B*(p[
Y]+1) + C, 0., 1e-6);
163 std::vector<ShapeIntersection> r1, r2, r3;
166 ASSERT_EQ(r1.size(), 1u);
167 EXPECT_EQ(r1[0].point(),
Point(3,0));
168 EXPECT_intersections_valid(a, b, r1, 1e-15);
171 ASSERT_EQ(r2.size(), 1u);
172 EXPECT_EQ(r2[0].point(),
Point(3,0));
173 EXPECT_intersections_valid(a, lsc, r2, 1e-15);
176 ASSERT_EQ(r3.size(), 1u);
177 EXPECT_EQ(r3[0].point(),
Point(3,0));
178 EXPECT_intersections_valid(a, lsc, r3, 1e-15);
187#define RAND10 g_random_double_range(-10.0, 10.0)
192TEST(LineTest, CoincidingIntersect)
194 auto const eps = 1e-14;
197 ASSERT_EQ(xings.size(), 2);
200 EXPECT_intersections_valid(s1, s2, xings, eps);
207 g_random_set_seed(0x13370AFA);
208 for (
size_t _ = 0; _ < 10'000; _++) {
209 auto const a =
Point(RAND10, RAND10);
210 auto const b =
Point(RAND10, RAND10);
213 check_endpoint_intersections(ab, ab);
214 check_endpoint_intersections(ba, ba);
215 check_endpoint_intersections(ab, ba);
223TEST(LineTest, OverlappingIntersect)
225 g_random_set_seed(0xCAFECAFE);
228 for (
size_t _ = 0; _ < 10'000; _++)
230 auto const a =
Point(RAND10, RAND10);
231 auto const d =
Point(RAND10, RAND10);
235 auto xings = ab.intersect(cd);
236 ASSERT_FALSE(xings.empty());
237 EXPECT_TRUE(
are_near(xings[0], ab.initialPoint()));
238 EXPECT_intersections_valid(ab, cd, xings, 1e-12);
242 for (
size_t _ = 0; _ < 10'000; _++)
244 auto const c =
Point(RAND10, RAND10);
245 auto const d =
Point(RAND10, RAND10);
246 auto const a =
lerp(0.25,
c, d);
247 auto const b =
lerp(0.75,
c, d);
250 auto xings = ab.intersect(cd);
251 ASSERT_FALSE(xings.empty());
252 EXPECT_TRUE(
are_near(xings[0], ab.initialPoint()));
253 EXPECT_intersections_valid(ab, cd, xings, 1e-12);
262 for (
double eps : {1e-12, 1e-11, 1e-10, 1e-9, 1e-8, 1e-7, 1e-6, 1e-3, 1.0}) {
267 auto xings = vertical.intersect(horizontal, eps);
268 ASSERT_FALSE(xings.empty());
269 EXPECT_intersections_valid(vertical, horizontal, xings, eps);
270 xings = vertical.intersect(butt, eps);
271 ASSERT_FALSE(xings.empty());
272 EXPECT_intersections_valid(vertical, butt, xings, eps);
273 xings = vertical.intersect(too_far, eps);
274 ASSERT_TRUE(xings.empty());
283 auto xings = ab.intersect(cd, 4);
284 ASSERT_EQ(xings.size(), 2);
285 EXPECT_DOUBLE_EQ(xings[0].point()[1], 10);
286 EXPECT_DOUBLE_EQ(xings[0].first, 0.5);
287 EXPECT_DOUBLE_EQ(xings[0].second, 0.0);
288 EXPECT_DOUBLE_EQ(xings[1].point()[1], 20);
289 EXPECT_DOUBLE_EQ(xings[1].first, 1.0);
290 EXPECT_DOUBLE_EQ(xings[1].second, 0.5);
299 auto xings = ab.intersect(cd, 4);
300 ASSERT_EQ(xings.size(), 1);
301 EXPECT_DOUBLE_EQ(xings[0].point()[1], 10);
302 EXPECT_DOUBLE_EQ(xings[0].first, 1.0);
303 EXPECT_DOUBLE_EQ(xings[0].second, 0.0);
313 auto xings = ab.intersect(cd, 12);
314 ASSERT_EQ(xings.size(), 1);
316 EXPECT_DOUBLE_EQ(x.point()[
X], 0);
317 EXPECT_DOUBLE_EQ(x.point()[
Y], 100);
318 EXPECT_DOUBLE_EQ(x.first, 1.0);
319 EXPECT_DOUBLE_EQ(x.second, 0.0);
329 g_random_set_seed(0x01234567);
331 for (
int exponent = -2; exponent > -13; exponent--) {
332 double const eps = std::pow(10, exponent);
333 for (
size_t _ = 0; _ < 10'000; _++) {
334 auto const distance = g_random_double_range(0.0, 2.0 * eps);
335 size_t const expected_crossing_count = (size_t)(
distance <= eps);
337 ASSERT_EQ(xings.size(), expected_crossing_count);
338 if (expected_crossing_count) {
339 auto const &x = xings[0];
340 EXPECT_DOUBLE_EQ(x.point()[
X], 0.0);
341 EXPECT_DOUBLE_EQ(x.point()[
Y], 1.0 - (0.5 *
distance));
342 EXPECT_DOUBLE_EQ(x.first, 0.5);
343 EXPECT_DOUBLE_EQ(x.second, 1.0);
355 auto const normal = (seg.finalPoint() - seg.initialPoint()).cw().normalized();
356 g_random_set_seed(0xB787A350);
358 for (
int exponent = 1; exponent > -13; exponent--) {
359 double const eps = std::pow(10, exponent);
360 for (
size_t _ = 0; _ < 10'000; _++) {
361 auto const pushoff_distance = g_random_double_range(0.0, 2.0 * eps);
362 std::unique_ptr<LineSegment> pushed_off{
368 auto const xings = seg.
intersect(*pushed_off, eps);
369 bool const too_far = pushoff_distance > eps;
370 EXPECT_EQ(xings.empty(), too_far);
371 for (
auto const &x : xings) {
3x3 affine transformation matrix.
3x3 matrix representing an affine transformation.
static Angle from_degrees(Coord d)
Create an angle from its measure in degrees.
std::vector< CurveIntersection > intersect(Curve const &other, Coord eps=EPSILON) const override
Compute intersections with another curve.
Point finalPoint() const override
Retrieve the end of the curve.
Point initialPoint() const override
Retrieve the start of the curve.
Intersection between two shapes.
Infinite line on a plane.
std::vector< double > coefficients() const
Get the coefficients of the line equation as a vector.
Affine rotationToZero(Dim2 d) const
Compute an affine which transforms all points on the line to zero X or Y coordinate.
Affine reflection() const
Compute an affine matrix representing a reflection about the line.
Point vector() const
Get the line's raw direction vector.
std::vector< ShapeIntersection > intersect(Line const &other) const
Coord angle() const
Angle the line makes with the X axis, in mathematical convention.
Point pointAt(Coord t) const
Point versor() const
Get the line's normalized direction vector.
Two-dimensional point that doubles as a vector.
BezierCurveN< 1 > LineSegment
Line segment.
constexpr Coord lerp(Coord t, Coord a, Coord b)
Numerically stable linear interpolation.
double Coord
Floating point type used to store coordinates.
Various utility functions.
Angle distance(Angle const &a, Angle const &b)
TEST(AffineTest, Equality)
Line make_angle_bisector_line(Point const &A, Point const &O, Point const &B)
bool are_near(Affine const &a1, Affine const &a2, Coord eps=EPSILON)
Point middle_point(LineSegment const &_segment)