1use crate::scalar::Scalar;
2use crate::segment::{BoundingBox, Segment};
3use crate::traits::Transformation;
4use crate::utils::min_max;
5use crate::{point, vector, Box2D, Point, Vector};
6use core::mem::swap;
7
8use core::ops::Range;
9
10/// A linear segment.
11#[derive(Copy, Clone, Debug, PartialEq)]
12#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
13pub struct LineSegment<S> {
14 pub from: Point<S>,
15 pub to: Point<S>,
16}
17
18impl<S: Scalar> LineSegment<S> {
19 /// Sample the segment at t (expecting t between 0 and 1).
20 #[inline]
21 pub fn sample(&self, t: S) -> Point<S> {
22 self.from.lerp(self.to, t)
23 }
24
25 /// Sample the x coordinate of the segment at t (expecting t between 0 and 1).
26 #[inline]
27 pub fn x(&self, t: S) -> S {
28 self.from.x * (S::ONE - t) + self.to.x * t
29 }
30
31 /// Sample the y coordinate of the segment at t (expecting t between 0 and 1).
32 #[inline]
33 pub fn y(&self, t: S) -> S {
34 self.from.y * (S::ONE - t) + self.to.y * t
35 }
36
37 #[inline]
38 pub fn from(&self) -> Point<S> {
39 self.from
40 }
41
42 #[inline]
43 pub fn to(&self) -> Point<S> {
44 self.to
45 }
46
47 pub fn solve_t_for_x(&self, x: S) -> S {
48 let dx = self.to.x - self.from.x;
49 if dx == S::ZERO {
50 return S::ZERO;
51 }
52
53 (x - self.from.x) / dx
54 }
55
56 pub fn solve_t_for_y(&self, y: S) -> S {
57 let dy = self.to.y - self.from.y;
58 if dy == S::ZERO {
59 return S::ZERO;
60 }
61
62 (y - self.from.y) / dy
63 }
64
65 pub fn solve_y_for_x(&self, x: S) -> S {
66 self.y(self.solve_t_for_x(x))
67 }
68
69 pub fn solve_x_for_y(&self, y: S) -> S {
70 self.x(self.solve_t_for_y(y))
71 }
72
73 /// Returns an inverted version of this segment where the beginning and the end
74 /// points are swapped.
75 #[inline]
76 pub fn flip(&self) -> Self {
77 LineSegment {
78 from: self.to,
79 to: self.from,
80 }
81 }
82
83 /// Return the sub-segment inside a given range of t.
84 ///
85 /// This is equivalent splitting at the range's end points.
86 pub fn split_range(&self, t_range: Range<S>) -> Self {
87 LineSegment {
88 from: self.from.lerp(self.to, t_range.start),
89 to: self.from.lerp(self.to, t_range.end),
90 }
91 }
92
93 /// Split this curve into two sub-segments.
94 #[inline]
95 pub fn split(&self, t: S) -> (Self, Self) {
96 let split_point = self.sample(t);
97
98 (
99 LineSegment {
100 from: self.from,
101 to: split_point,
102 },
103 LineSegment {
104 from: split_point,
105 to: self.to,
106 },
107 )
108 }
109
110 /// Return the segment before the split point.
111 #[inline]
112 pub fn before_split(&self, t: S) -> Self {
113 LineSegment {
114 from: self.from,
115 to: self.sample(t),
116 }
117 }
118
119 /// Return the segment after the split point.
120 #[inline]
121 pub fn after_split(&self, t: S) -> Self {
122 LineSegment {
123 from: self.sample(t),
124 to: self.to,
125 }
126 }
127
128 pub fn split_at_x(&self, x: S) -> (Self, Self) {
129 self.split(self.solve_t_for_x(x))
130 }
131
132 /// Return the smallest rectangle containing this segment.
133 #[inline]
134 pub fn bounding_box(&self) -> Box2D<S> {
135 let (min_x, max_x) = self.bounding_range_x();
136 let (min_y, max_y) = self.bounding_range_y();
137
138 Box2D {
139 min: point(min_x, min_y),
140 max: point(max_x, max_y),
141 }
142 }
143
144 #[inline]
145 fn bounding_range_x(&self) -> (S, S) {
146 min_max(self.from.x, self.to.x)
147 }
148
149 #[inline]
150 fn bounding_range_y(&self) -> (S, S) {
151 min_max(self.from.y, self.to.y)
152 }
153
154 /// Returns the vector between this segment's `from` and `to` points.
155 #[inline]
156 pub fn to_vector(&self) -> Vector<S> {
157 self.to - self.from
158 }
159
160 /// Returns the line containing this segment.
161 #[inline]
162 pub fn to_line(&self) -> Line<S> {
163 Line {
164 point: self.from,
165 vector: self.to - self.from,
166 }
167 }
168
169 /// Computes the length of this segment.
170 #[inline]
171 pub fn length(&self) -> S {
172 self.to_vector().length()
173 }
174
175 /// Computes the squared length of this segment.
176 #[inline]
177 pub fn square_length(&self) -> S {
178 self.to_vector().square_length()
179 }
180
181 /// Changes the segment's length, moving destination point.
182 pub fn set_length(&mut self, new_length: S) {
183 let v = self.to_vector();
184 let old_length = v.length();
185 self.to = self.from + v * (new_length / old_length);
186 }
187
188 /// Computes third mid-point of this segment.
189 pub fn mid_point(&mut self) -> Point<S> {
190 (self.from + self.to.to_vector()) / S::TWO
191 }
192
193 #[inline]
194 pub fn translate(&mut self, by: Vector<S>) -> Self {
195 LineSegment {
196 from: self.from + by,
197 to: self.to + by,
198 }
199 }
200
201 /// Applies the transform to this segment and returns the results.
202 #[inline]
203 pub fn transformed<T: Transformation<S>>(&self, transform: &T) -> Self {
204 LineSegment {
205 from: transform.transform_point(self.from),
206 to: transform.transform_point(self.to),
207 }
208 }
209
210 /// Computes the intersection (if any) between this segment and another one.
211 ///
212 /// The result is provided in the form of the `t` parameter of each
213 /// segment. To get the intersection point, sample one of the segments
214 /// at the corresponding value.
215 #[allow(clippy::suspicious_operation_groupings)]
216 pub fn intersection_t(&self, other: &Self) -> Option<(S, S)> {
217 if self.to == other.to
218 || self.from == other.from
219 || self.from == other.to
220 || self.to == other.from
221 {
222 return None;
223 }
224
225 let v1 = self.to_vector();
226 let v2 = other.to_vector();
227
228 let v1_cross_v2 = v1.cross(v2);
229
230 if v1_cross_v2 == S::ZERO {
231 // The segments are parallel
232 return None;
233 }
234
235 let sign_v1_cross_v2 = S::signum(v1_cross_v2);
236 let abs_v1_cross_v2 = S::abs(v1_cross_v2);
237
238 let v3 = other.from - self.from;
239
240 // t and u should be divided by v1_cross_v2, but we postpone that to not lose precision.
241 // We have to respect the sign of v1_cross_v2 (and therefore t and u) so we apply it now and
242 // will use the absolute value of v1_cross_v2 afterwards.
243 let t = v3.cross(v2) * sign_v1_cross_v2;
244 let u = v3.cross(v1) * sign_v1_cross_v2;
245
246 if t < S::ZERO || t > abs_v1_cross_v2 || u < S::ZERO || u > abs_v1_cross_v2 {
247 return None;
248 }
249
250 Some((t / abs_v1_cross_v2, u / abs_v1_cross_v2))
251 }
252
253 #[inline]
254 pub fn intersection(&self, other: &Self) -> Option<Point<S>> {
255 self.intersection_t(other).map(|(t, _)| self.sample(t))
256 }
257
258 pub fn line_intersection_t(&self, line: &Line<S>) -> Option<S> {
259 let v1 = self.to_vector();
260 let v2 = line.vector;
261
262 let v1_cross_v2 = v1.cross(v2);
263
264 if v1_cross_v2 == S::ZERO {
265 // The segments are parallel
266 return None;
267 }
268
269 let sign_v1_cross_v2 = S::signum(v1_cross_v2);
270 let abs_v1_cross_v2 = S::abs(v1_cross_v2);
271
272 let v3 = line.point - self.from;
273 let t = v3.cross(v2) * sign_v1_cross_v2;
274
275 if t < S::ZERO || t > abs_v1_cross_v2 {
276 return None;
277 }
278
279 Some(t / abs_v1_cross_v2)
280 }
281
282 #[inline]
283 pub fn line_intersection(&self, line: &Line<S>) -> Option<Point<S>> {
284 self.line_intersection_t(line).map(|t| self.sample(t))
285 }
286
287 // TODO: Consider only intersecting in the [0, 1[ range instead of [0, 1]
288 pub fn horizontal_line_intersection_t(&self, y: S) -> Option<S> {
289 Self::axis_aligned_intersection_1d(self.from.y, self.to.y, y)
290 }
291
292 pub fn vertical_line_intersection_t(&self, x: S) -> Option<S> {
293 Self::axis_aligned_intersection_1d(self.from.x, self.to.x, x)
294 }
295
296 #[inline]
297 pub fn horizontal_line_intersection(&self, y: S) -> Option<Point<S>> {
298 self.horizontal_line_intersection_t(y)
299 .map(|t| self.sample(t))
300 }
301
302 #[inline]
303 pub fn vertical_line_intersection(&self, x: S) -> Option<Point<S>> {
304 self.vertical_line_intersection_t(x).map(|t| self.sample(t))
305 }
306
307 fn axis_aligned_intersection_1d(mut a: S, mut b: S, v: S) -> Option<S> {
308 // TODO: is it really useful to swap?
309 let swap = a > b;
310 if swap {
311 core::mem::swap(&mut a, &mut b);
312 }
313
314 let d = b - a;
315 if d == S::ZERO {
316 return None;
317 }
318
319 let t = (v - a) / d;
320
321 if t < S::ZERO || t > S::ONE {
322 return None;
323 }
324
325 Some(if swap { S::ONE - t } else { t })
326 }
327
328 #[inline]
329 pub fn intersects(&self, other: &Self) -> bool {
330 self.intersection_t(other).is_some()
331 }
332
333 #[inline]
334 pub fn intersects_line(&self, line: &Line<S>) -> bool {
335 self.line_intersection_t(line).is_some()
336 }
337
338 pub fn overlaps_line(&self, line: &Line<S>) -> bool {
339 let v1 = self.to_vector();
340 let v2 = line.vector;
341 let v3 = line.point - self.from;
342
343 v1.cross(v2) == S::ZERO && v1.cross(v3) == S::ZERO
344 }
345
346 pub fn overlaps_segment(&self, other: &LineSegment<S>) -> bool {
347 if !self.overlaps_line(&other.to_line()) {
348 return false;
349 }
350
351 let v1 = self.to - self.from;
352 let v2 = other.from - self.from;
353 let v3 = other.to - self.from;
354 let mut a = S::ZERO;
355 let mut b = v1.dot(v1);
356 let mut c = v1.dot(v2);
357 let mut d = v1.dot(v3);
358
359 if a > b {
360 swap(&mut a, &mut b);
361 }
362 if c > d {
363 swap(&mut d, &mut c);
364 }
365
366 (c > a && c < b)
367 || (d > a && d < b)
368 || (a > c && a < d)
369 || (b > c && b < d)
370 || (a == c && b == d)
371 }
372
373 pub fn contains_segment(&self, other: &LineSegment<S>) -> bool {
374 if !self.overlaps_line(&other.to_line()) {
375 return false;
376 }
377
378 let v1 = self.to - self.from;
379 let v2 = other.from - self.from;
380 let v3 = other.to - self.from;
381 let mut a = S::ZERO;
382 let mut b = v1.dot(v1);
383 let mut c = v1.dot(v2);
384 let mut d = v1.dot(v3);
385
386 if a > b {
387 swap(&mut a, &mut b);
388 }
389 if c > d {
390 swap(&mut d, &mut c);
391 }
392
393 c >= a && c <= b && d >= a && d <= b
394 }
395
396 /// Horizontally clip this segment against a range of the x axis.
397 pub fn clipped_x(&self, clip: Range<S>) -> Option<Self> {
398 if (self.from.x < clip.start && self.to.x < clip.start)
399 || (self.from.x > clip.end && self.to.x > clip.end)
400 {
401 return None;
402 }
403
404 let mut flipped = false;
405 let mut result = *self;
406
407 if result.from.x > result.to.x {
408 flipped = true;
409 result = result.flip();
410 }
411
412 if result.from.x >= clip.start && result.to.x <= clip.end {
413 return Some(*self);
414 }
415
416 if result.from.x < clip.start {
417 let t = result
418 .vertical_line_intersection_t(clip.start)
419 .unwrap_or(S::ZERO);
420 result.from.x = clip.start;
421 result.from.y = result.y(t);
422 }
423
424 if result.to.x > clip.end {
425 let t = result
426 .vertical_line_intersection_t(clip.end)
427 .unwrap_or(S::ZERO);
428 result.to.x = clip.end;
429 result.to.y = result.y(t);
430 }
431
432 if flipped {
433 result = result.flip();
434 }
435
436 Some(result)
437 }
438
439 /// Vertically clip this segment against a range of the y axis.
440 pub fn clipped_y(&self, clip: Range<S>) -> Option<Self> {
441 fn transpose<S: Copy>(r: &LineSegment<S>) -> LineSegment<S> {
442 LineSegment {
443 from: r.from.yx(),
444 to: r.to.yx(),
445 }
446 }
447
448 Some(transpose(&transpose(self).clipped_x(clip)?))
449 }
450
451 /// Clip this segment against a rectangle.
452 pub fn clipped(&self, clip: &Box2D<S>) -> Option<Self> {
453 self.clipped_x(clip.x_range())?.clipped_y(clip.y_range())
454 }
455
456 /// Computes the distance between this segment and a point.
457 #[inline]
458 pub fn distance_to_point(&self, p: Point<S>) -> S {
459 self.square_distance_to_point(p).sqrt()
460 }
461
462 /// Computes the squared distance between this segment and a point.
463 ///
464 /// Can be useful to save a square root and a division when comparing against
465 /// a distance that can be squared.
466 #[inline]
467 pub fn square_distance_to_point(&self, p: Point<S>) -> S {
468 (self.closest_point(p) - p).square_length()
469 }
470
471 /// Computes the closest point on this segment to `p`.
472 #[inline]
473 pub fn closest_point(&self, p: Point<S>) -> Point<S> {
474 let v1 = self.to - self.from;
475 let v2 = p - self.from;
476 let t = S::min(S::max(v2.dot(v1) / v1.dot(v1), S::ZERO), S::ONE);
477
478 self.from + v1 * t
479 }
480
481 #[inline]
482 pub fn to_f32(&self) -> LineSegment<f32> {
483 LineSegment {
484 from: self.from.to_f32(),
485 to: self.to.to_f32(),
486 }
487 }
488
489 #[inline]
490 pub fn to_f64(&self) -> LineSegment<f64> {
491 LineSegment {
492 from: self.from.to_f64(),
493 to: self.to.to_f64(),
494 }
495 }
496}
497
498impl<S: Scalar> Segment for LineSegment<S> {
499 type Scalar = S;
500 fn from(&self) -> Point<S> {
501 self.from
502 }
503 fn to(&self) -> Point<S> {
504 self.to
505 }
506 fn sample(&self, t: S) -> Point<S> {
507 self.sample(t)
508 }
509 fn x(&self, t: S) -> S {
510 self.x(t)
511 }
512 fn y(&self, t: S) -> S {
513 self.y(t)
514 }
515 fn derivative(&self, _t: S) -> Vector<S> {
516 self.to_vector()
517 }
518 fn dx(&self, _t: S) -> S {
519 self.to.x - self.from.x
520 }
521 fn dy(&self, _t: S) -> S {
522 self.to.y - self.from.y
523 }
524 fn split(&self, t: S) -> (Self, Self) {
525 self.split(t)
526 }
527 fn before_split(&self, t: S) -> Self {
528 self.before_split(t)
529 }
530 fn after_split(&self, t: S) -> Self {
531 self.after_split(t)
532 }
533 fn split_range(&self, t_range: Range<S>) -> Self {
534 self.split_range(t_range)
535 }
536 fn flip(&self) -> Self {
537 self.flip()
538 }
539 fn approximate_length(&self, _tolerance: S) -> S {
540 self.length()
541 }
542
543 fn for_each_flattened_with_t(
544 &self,
545 _tolerance: Self::Scalar,
546 callback: &mut dyn FnMut(&LineSegment<S>, Range<S>),
547 ) {
548 callback(self, S::ZERO..S::ONE);
549 }
550}
551
552impl<S: Scalar> BoundingBox for LineSegment<S> {
553 type Scalar = S;
554 fn bounding_range_x(&self) -> (S, S) {
555 self.bounding_range_x()
556 }
557 fn bounding_range_y(&self) -> (S, S) {
558 self.bounding_range_y()
559 }
560 fn fast_bounding_range_x(&self) -> (S, S) {
561 self.bounding_range_x()
562 }
563 fn fast_bounding_range_y(&self) -> (S, S) {
564 self.bounding_range_y()
565 }
566}
567
568/// An infinite line defined by a point and a vector.
569#[derive(Copy, Clone, Debug)]
570#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
571pub struct Line<S> {
572 pub point: Point<S>,
573 pub vector: Vector<S>,
574}
575
576impl<S: Scalar> Line<S> {
577 pub fn intersection(&self, other: &Self) -> Option<Point<S>> {
578 let det = self.vector.cross(other.vector);
579 if S::abs(det) <= S::EPSILON {
580 // The lines are very close to parallel
581 return None;
582 }
583 let inv_det = S::ONE / det;
584 let self_p2 = self.point + self.vector;
585 let other_p2 = other.point + other.vector;
586 let a = self.point.to_vector().cross(self_p2.to_vector());
587 let b = other.point.to_vector().cross(other_p2.to_vector());
588
589 Some(point(
590 (b * self.vector.x - a * other.vector.x) * inv_det,
591 (b * self.vector.y - a * other.vector.y) * inv_det,
592 ))
593 }
594
595 pub fn distance_to_point(&self, p: &Point<S>) -> S {
596 S::abs(self.signed_distance_to_point(p))
597 }
598
599 pub fn signed_distance_to_point(&self, p: &Point<S>) -> S {
600 let v = *p - self.point;
601 self.vector.cross(v) / self.vector.length()
602 }
603
604 /// Returned the squared distance to a point.
605 ///
606 /// Can be useful to avoid a square root when comparing against a
607 /// distance that can be squared instead.
608 pub fn square_distance_to_point(&self, p: Point<S>) -> S {
609 let v = p - self.point;
610 let c = self.vector.cross(v);
611 (c * c) / self.vector.square_length()
612 }
613
614 pub fn equation(&self) -> LineEquation<S> {
615 let a = -self.vector.y;
616 let b = self.vector.x;
617 let c = -(a * self.point.x + b * self.point.y);
618
619 LineEquation::new(a, b, c)
620 }
621
622 pub fn intersects_box(&self, rect: &Box2D<S>) -> bool {
623 let v = self.vector;
624
625 let diagonal = if (v.y >= S::ZERO) ^ (v.x >= S::ZERO) {
626 LineSegment {
627 from: rect.min,
628 to: rect.max,
629 }
630 } else {
631 LineSegment {
632 from: point(rect.max.x, rect.min.y),
633 to: point(rect.min.x, rect.max.y),
634 }
635 };
636
637 diagonal.intersects_line(self)
638 }
639
640 #[inline]
641 pub fn to_f32(&self) -> Line<f32> {
642 Line {
643 point: self.point.to_f32(),
644 vector: self.vector.to_f32(),
645 }
646 }
647
648 #[inline]
649 pub fn to_f64(&self) -> Line<f64> {
650 Line {
651 point: self.point.to_f64(),
652 vector: self.vector.to_f64(),
653 }
654 }
655}
656
657/// A line defined by the equation
658/// `a * x + b * y + c = 0; a * a + b * b = 1`.
659#[derive(Copy, Clone, Debug, PartialEq, Eq)]
660#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
661pub struct LineEquation<S> {
662 a: S,
663 b: S,
664 c: S,
665}
666
667impl<S: Scalar> LineEquation<S> {
668 pub fn new(a: S, b: S, c: S) -> Self {
669 debug_assert!(a != S::ZERO || b != S::ZERO);
670 let div = S::ONE / S::sqrt(a * a + b * b);
671 LineEquation {
672 a: a * div,
673 b: b * div,
674 c: c * div,
675 }
676 }
677
678 #[inline]
679 pub fn a(&self) -> S {
680 self.a
681 }
682
683 #[inline]
684 pub fn b(&self) -> S {
685 self.b
686 }
687
688 #[inline]
689 pub fn c(&self) -> S {
690 self.c
691 }
692
693 pub fn project_point(&self, p: &Point<S>) -> Point<S> {
694 point(
695 self.b * (self.b * p.x - self.a * p.y) - self.a * self.c,
696 self.a * (self.a * p.y - self.b * p.x) - self.b * self.c,
697 )
698 }
699
700 #[inline]
701 pub fn signed_distance_to_point(&self, p: &Point<S>) -> S {
702 self.a * p.x + self.b * p.y + self.c
703 }
704
705 #[inline]
706 pub fn distance_to_point(&self, p: &Point<S>) -> S {
707 S::abs(self.signed_distance_to_point(p))
708 }
709
710 #[inline]
711 pub fn invert(&self) -> Self {
712 LineEquation {
713 a: -self.a,
714 b: -self.b,
715 c: -self.c,
716 }
717 }
718
719 #[inline]
720 pub fn parallel_line(&self, p: &Point<S>) -> Self {
721 let c = -(self.a * p.x + self.b * p.y);
722 LineEquation {
723 a: self.a,
724 b: self.b,
725 c,
726 }
727 }
728
729 #[inline]
730 pub fn offset(&self, d: S) -> Self {
731 LineEquation {
732 a: self.a,
733 b: self.b,
734 c: self.c - d,
735 }
736 }
737
738 #[inline]
739 pub fn tangent(&self) -> Vector<S> {
740 vector(self.b, -self.a)
741 }
742
743 #[inline]
744 pub fn normal(&self) -> Vector<S> {
745 vector(self.a, self.b)
746 }
747
748 #[inline]
749 pub fn solve_y_for_x(&self, x: S) -> Option<S> {
750 if self.b == S::ZERO {
751 return None;
752 }
753
754 Some((self.a * x + self.c) / -self.b)
755 }
756
757 #[inline]
758 pub fn solve_x_for_y(&self, y: S) -> Option<S> {
759 if self.a == S::ZERO {
760 return None;
761 }
762
763 Some((self.b * y + self.c) / -self.a)
764 }
765
766 #[inline]
767 pub fn is_horizontal(&self) -> bool {
768 self.a == S::ZERO
769 }
770
771 #[inline]
772 pub fn is_vertical(&self) -> bool {
773 self.b == S::ZERO
774 }
775}
776
777#[cfg(test)]
778fn fuzzy_eq_f32(a: f32, b: f32, epsilon: f32) -> bool {
779 f32::abs(a - b) <= epsilon
780}
781
782#[cfg(test)]
783fn fuzzy_eq_vector(a: Vector<f32>, b: Vector<f32>, epsilon: f32) -> bool {
784 fuzzy_eq_f32(a.x, b.x, epsilon) && fuzzy_eq_f32(a.y, b.y, epsilon)
785}
786
787#[cfg(test)]
788fn fuzzy_eq_point(a: Point<f32>, b: Point<f32>, epsilon: f32) -> bool {
789 fuzzy_eq_vector(a.to_vector(), b.to_vector(), epsilon)
790}
791
792#[test]
793fn intersection_rotated() {
794 use core::f32::consts::PI;
795 let epsilon = 0.0001;
796 let count: u32 = 100;
797
798 for i in 0..count {
799 for j in 0..count {
800 if i % (count / 2) == j % (count / 2) {
801 // avoid the colinear case.
802 continue;
803 }
804
805 let angle1 = i as f32 / (count as f32) * 2.0 * PI;
806 let angle2 = j as f32 / (count as f32) * 2.0 * PI;
807
808 let l1 = LineSegment {
809 from: point(10.0 * angle1.cos(), 10.0 * angle1.sin()),
810 to: point(-10.0 * angle1.cos(), -10.0 * angle1.sin()),
811 };
812
813 let l2 = LineSegment {
814 from: point(10.0 * angle2.cos(), 10.0 * angle2.sin()),
815 to: point(-10.0 * angle2.cos(), -10.0 * angle2.sin()),
816 };
817
818 assert!(l1.intersects(&l2));
819
820 assert!(fuzzy_eq_point(
821 l1.sample(l1.intersection_t(&l2).unwrap().0),
822 point(0.0, 0.0),
823 epsilon
824 ));
825
826 assert!(fuzzy_eq_point(
827 l2.sample(l1.intersection_t(&l2).unwrap().1),
828 point(0.0, 0.0),
829 epsilon
830 ));
831 }
832 }
833}
834
835#[test]
836fn intersection_touching() {
837 let l1: LineSegment = LineSegment {
838 from: point(x:0.0, y:0.0),
839 to: point(x:10.0, y:10.0),
840 };
841
842 let l2: LineSegment = LineSegment {
843 from: point(x:10.0, y:10.0),
844 to: point(x:10.0, y:0.0),
845 };
846
847 assert!(!l1.intersects(&l2));
848 assert!(l1.intersection(&l2).is_none());
849}
850
851#[test]
852fn intersection_overlap() {
853 // It's hard to define the intersection points of two segments that overlap,
854 // (would be a region rather than a point) and more importantly, in practice
855 // the algorithms in lyon don't need to consider this special case as an intersection,
856 // so we choose to treat overlapping segments as not intersecting.
857
858 let l1: LineSegment = LineSegment {
859 from: point(x:0.0, y:0.0),
860 to: point(x:10.0, y:0.0),
861 };
862
863 let l2: LineSegment = LineSegment {
864 from: point(x:5.0, y:00.0),
865 to: point(x:15.0, y:0.0),
866 };
867
868 assert!(!l1.intersects(&l2));
869 assert!(l1.intersection(&l2).is_none());
870}
871
872#[cfg(test)]
873use euclid::approxeq::ApproxEq;
874
875#[test]
876fn bounding_box() {
877 let l1 = LineSegment {
878 from: point(1.0, 5.0),
879 to: point(5.0, 7.0),
880 };
881 let r1 = Box2D {
882 min: point(1.0, 5.0),
883 max: point(5.0, 7.0),
884 };
885
886 let l2 = LineSegment {
887 from: point(5.0, 5.0),
888 to: point(1.0, 1.0),
889 };
890 let r2 = Box2D {
891 min: point(1.0, 1.0),
892 max: point(5.0, 5.0),
893 };
894
895 let l3 = LineSegment {
896 from: point(3.0, 3.0),
897 to: point(1.0, 5.0),
898 };
899 let r3 = Box2D {
900 min: point(1.0, 3.0),
901 max: point(3.0, 5.0),
902 };
903
904 let cases = std::vec![(l1, r1), (l2, r2), (l3, r3)];
905 for &(ls, r) in &cases {
906 assert_eq!(ls.bounding_box(), r);
907 }
908}
909
910#[test]
911fn distance_to_point() {
912 use crate::vector;
913
914 let l1 = Line {
915 point: point(2.0f32, 3.0),
916 vector: vector(-1.5, 0.0),
917 };
918
919 let l2 = Line {
920 point: point(3.0f32, 3.0),
921 vector: vector(1.5, 1.5),
922 };
923
924 assert!(l1
925 .signed_distance_to_point(&point(1.1, 4.0))
926 .approx_eq(&-1.0));
927 assert!(l1
928 .signed_distance_to_point(&point(2.3, 2.0))
929 .approx_eq(&1.0));
930
931 assert!(l2
932 .signed_distance_to_point(&point(1.0, 0.0))
933 .approx_eq(&(-f32::sqrt(2.0) / 2.0)));
934 assert!(l2
935 .signed_distance_to_point(&point(0.0, 1.0))
936 .approx_eq(&(f32::sqrt(2.0) / 2.0)));
937
938 assert!(l1
939 .equation()
940 .distance_to_point(&point(1.1, 4.0))
941 .approx_eq(&1.0));
942 assert!(l1
943 .equation()
944 .distance_to_point(&point(2.3, 2.0))
945 .approx_eq(&1.0));
946 assert!(l2
947 .equation()
948 .distance_to_point(&point(1.0, 0.0))
949 .approx_eq(&(f32::sqrt(2.0) / 2.0)));
950 assert!(l2
951 .equation()
952 .distance_to_point(&point(0.0, 1.0))
953 .approx_eq(&(f32::sqrt(2.0) / 2.0)));
954
955 assert!(l1
956 .equation()
957 .signed_distance_to_point(&point(1.1, 4.0))
958 .approx_eq(&l1.signed_distance_to_point(&point(1.1, 4.0))));
959 assert!(l1
960 .equation()
961 .signed_distance_to_point(&point(2.3, 2.0))
962 .approx_eq(&l1.signed_distance_to_point(&point(2.3, 2.0))));
963
964 assert!(l2
965 .equation()
966 .signed_distance_to_point(&point(1.0, 0.0))
967 .approx_eq(&l2.signed_distance_to_point(&point(1.0, 0.0))));
968 assert!(l2
969 .equation()
970 .signed_distance_to_point(&point(0.0, 1.0))
971 .approx_eq(&l2.signed_distance_to_point(&point(0.0, 1.0))));
972}
973
974#[test]
975fn solve_y_for_x() {
976 let line = Line {
977 point: Point::new(1.0, 1.0),
978 vector: Vector::new(2.0, 4.0),
979 };
980 let eqn = line.equation();
981
982 if let Some(y) = eqn.solve_y_for_x(line.point.x) {
983 std::println!("{y:?} != {:?}", line.point.y);
984 assert!(f64::abs(y - line.point.y) < 0.000001)
985 }
986
987 if let Some(x) = eqn.solve_x_for_y(line.point.y) {
988 assert!(f64::abs(x - line.point.x) < 0.000001)
989 }
990
991 let mut angle = 0.1;
992 for _ in 0..100 {
993 let (sin, cos) = f64::sin_cos(angle);
994 let line = Line {
995 point: Point::new(-1000.0, 600.0),
996 vector: Vector::new(cos * 100.0, sin * 100.0),
997 };
998 let eqn = line.equation();
999
1000 if let Some(y) = eqn.solve_y_for_x(line.point.x) {
1001 std::println!("{y:?} != {:?}", line.point.y);
1002 assert!(f64::abs(y - line.point.y) < 0.000001)
1003 }
1004
1005 if let Some(x) = eqn.solve_x_for_y(line.point.y) {
1006 assert!(f64::abs(x - line.point.x) < 0.000001)
1007 }
1008
1009 angle += 0.001;
1010 }
1011}
1012
1013#[test]
1014fn offset() {
1015 let l1: LineEquation = LineEquation::new(a:2.0, b:3.0, c:1.0);
1016 let p: Point2D = Point::new(x:10.0, y:3.0);
1017 let d: f64 = l1.signed_distance_to_point(&p);
1018 let l2: LineEquation = l1.offset(d);
1019 assert!(l2.distance_to_point(&p) < 0.0000001f64);
1020}
1021
1022#[test]
1023fn set_length() {
1024 let mut a: LineSegment = LineSegment {
1025 from: point(x:10.0, y:1.0),
1026 to: point(x:100.0, y:-15.0),
1027 };
1028 a.set_length(new_length:1.0);
1029 assert!(a.length().approx_eq(&1.0));
1030 a.set_length(new_length:1.5);
1031 assert!(a.length().approx_eq(&1.5));
1032 a.set_length(new_length:100.0);
1033 assert!(a.length().approx_eq(&100.0));
1034 a.set_length(new_length:-1.0);
1035 assert!(a.length().approx_eq(&1.0));
1036}
1037
1038#[test]
1039fn overlap() {
1040 assert!(LineSegment {
1041 from: point(0.0, 0.0),
1042 to: point(-1.0, 0.0),
1043 }
1044 .overlaps_line(&Line {
1045 point: point(100.0, 0.0),
1046 vector: vector(10.0, 0.0),
1047 }));
1048
1049 assert!(LineSegment {
1050 from: point(0.0, 0.0),
1051 to: point(1.0, 0.0),
1052 }
1053 .overlaps_line(&Line {
1054 point: point(0.0, 0.0),
1055 vector: vector(1.0, 0.0),
1056 }));
1057
1058 assert!(LineSegment {
1059 from: point(0.0, 0.0),
1060 to: point(1.0, 0.0),
1061 }
1062 .overlaps_segment(&LineSegment {
1063 from: point(0.0, 0.0),
1064 to: point(1.0, 0.0),
1065 }));
1066
1067 assert!(!LineSegment {
1068 from: point(0.0, 0.0),
1069 to: point(1.0, 0.0),
1070 }
1071 .overlaps_line(&Line {
1072 point: point(0.0, 1.0),
1073 vector: vector(1.0, 1.0),
1074 }));
1075}
1076
1077#[test]
1078fn contains_segment() {
1079 assert!(LineSegment {
1080 from: point(-1.0, 1.0),
1081 to: point(4.0, 1.0),
1082 }
1083 .contains_segment(&LineSegment {
1084 from: point(2.0, 1.0),
1085 to: point(1.0, 1.0),
1086 }));
1087}
1088
1089#[test]
1090fn horizontal_line_intersection() {
1091 let segment = LineSegment {
1092 from: point(1.0, 2.0),
1093 to: point(2.0, 3.0),
1094 };
1095
1096 assert_eq!(segment.horizontal_line_intersection_t(2.0), Some(0.0));
1097 assert_eq!(segment.horizontal_line_intersection_t(2.25), Some(0.25));
1098 assert_eq!(segment.horizontal_line_intersection_t(2.5), Some(0.5));
1099 assert_eq!(segment.horizontal_line_intersection_t(2.75), Some(0.75));
1100 assert_eq!(segment.horizontal_line_intersection_t(3.0), Some(1.0));
1101
1102 assert_eq!(segment.horizontal_line_intersection_t(1.5), None);
1103 assert_eq!(segment.horizontal_line_intersection_t(3.5), None);
1104
1105 let segment = LineSegment {
1106 from: point(2.0, 3.0),
1107 to: point(1.0, 2.0),
1108 };
1109
1110 assert_eq!(segment.horizontal_line_intersection_t(2.0), Some(1.0));
1111 assert_eq!(segment.horizontal_line_intersection_t(2.25), Some(0.75));
1112 assert_eq!(segment.horizontal_line_intersection_t(2.5), Some(0.5));
1113 assert_eq!(segment.horizontal_line_intersection_t(2.75), Some(0.25));
1114 assert_eq!(segment.horizontal_line_intersection_t(3.0), Some(0.0));
1115
1116 assert_eq!(segment.horizontal_line_intersection_t(1.5), None);
1117 assert_eq!(segment.horizontal_line_intersection_t(3.5), None);
1118}
1119
1120#[test]
1121fn intersection_on_endpoint() {
1122 let l1: LineSegment = LineSegment {
1123 from: point(x:0.0, y:0.0),
1124 to: point(x:0.0, y:10.0),
1125 };
1126
1127 let l2: LineSegment = LineSegment {
1128 from: point(x:0.0, y:5.0),
1129 to: point(x:10.0, y:5.0),
1130 };
1131
1132 assert_eq!(l1.intersection_t(&l2), Some((0.5, 0.0)));
1133 assert_eq!(l2.intersection_t(&l1), Some((0.0, 0.5)));
1134
1135 let l3: LineSegment = LineSegment {
1136 from: point(x:10.0, y:5.0),
1137 to: point(x:0.0, y:5.0),
1138 };
1139
1140 assert_eq!(l1.intersection_t(&l3), Some((0.5, 1.0)));
1141 assert_eq!(l3.intersection_t(&l1), Some((1.0, 0.5)));
1142}
1143
1144#[test]
1145fn intersects_box() {
1146 let b = Box2D {
1147 min: point(1.0, 2.0),
1148 max: point(4.0, 4.0),
1149 };
1150
1151 assert!(!Line {
1152 point: point(0.0, 0.0),
1153 vector: vector(1.0, 0.0)
1154 }
1155 .intersects_box(&b));
1156 assert!(!Line {
1157 point: point(0.0, 0.0),
1158 vector: vector(0.0, 1.0)
1159 }
1160 .intersects_box(&b));
1161 assert!(!Line {
1162 point: point(10.0, 0.0),
1163 vector: vector(10.0, 10.0)
1164 }
1165 .intersects_box(&b));
1166 assert!(!Line {
1167 point: point(0.0, 10.0),
1168 vector: vector(10.0, 10.0)
1169 }
1170 .intersects_box(&b));
1171
1172 assert!(Line {
1173 point: point(1.5, 0.0),
1174 vector: vector(1.0, 6.0)
1175 }
1176 .intersects_box(&b));
1177 assert!(Line {
1178 point: point(1.5, 0.0),
1179 vector: vector(-1.0, 6.0)
1180 }
1181 .intersects_box(&b));
1182 assert!(Line {
1183 point: point(1.5, 2.5),
1184 vector: vector(1.0, 0.5)
1185 }
1186 .intersects_box(&b));
1187 assert!(Line {
1188 point: point(1.5, 2.5),
1189 vector: vector(-1.0, -2.0)
1190 }
1191 .intersects_box(&b));
1192}
1193
1194#[test]
1195fn clipped() {
1196 let b = Box2D {
1197 min: point(1.0, 2.0),
1198 max: point(3.0, 4.0),
1199 };
1200
1201 fn approx_eq(a: LineSegment<f32>, b: LineSegment<f32>) -> bool {
1202 let ok = a.from.approx_eq(&b.from) && a.to.approx_eq(&b.to);
1203 if !ok {
1204 std::println!("{a:?} != {b:?}");
1205 }
1206
1207 ok
1208 }
1209
1210 assert_eq!(
1211 LineSegment {
1212 from: point(0.0, 1.0),
1213 to: point(4.0, 1.0)
1214 }
1215 .clipped(&b),
1216 None
1217 );
1218 assert_eq!(
1219 LineSegment {
1220 from: point(0.0, 2.0),
1221 to: point(4.0, 2.0)
1222 }
1223 .clipped(&b),
1224 Some(LineSegment {
1225 from: point(1.0, 2.0),
1226 to: point(3.0, 2.0)
1227 })
1228 );
1229 assert_eq!(
1230 LineSegment {
1231 from: point(0.0, 3.0),
1232 to: point(4.0, 3.0)
1233 }
1234 .clipped(&b),
1235 Some(LineSegment {
1236 from: point(1.0, 3.0),
1237 to: point(3.0, 3.0)
1238 })
1239 );
1240 assert_eq!(
1241 LineSegment {
1242 from: point(0.0, 4.0),
1243 to: point(4.0, 4.0)
1244 }
1245 .clipped(&b),
1246 Some(LineSegment {
1247 from: point(1.0, 4.0),
1248 to: point(3.0, 4.0)
1249 })
1250 );
1251 assert_eq!(
1252 LineSegment {
1253 from: point(0.0, 5.0),
1254 to: point(4.0, 5.0)
1255 }
1256 .clipped(&b),
1257 None
1258 );
1259
1260 assert_eq!(
1261 LineSegment {
1262 from: point(4.0, 1.0),
1263 to: point(0.0, 1.0)
1264 }
1265 .clipped(&b),
1266 None
1267 );
1268 assert_eq!(
1269 LineSegment {
1270 from: point(4.0, 2.0),
1271 to: point(0.0, 2.0)
1272 }
1273 .clipped(&b),
1274 Some(LineSegment {
1275 from: point(3.0, 2.0),
1276 to: point(1.0, 2.0)
1277 })
1278 );
1279 assert_eq!(
1280 LineSegment {
1281 from: point(4.0, 3.0),
1282 to: point(0.0, 3.0)
1283 }
1284 .clipped(&b),
1285 Some(LineSegment {
1286 from: point(3.0, 3.0),
1287 to: point(1.0, 3.0)
1288 })
1289 );
1290 assert_eq!(
1291 LineSegment {
1292 from: point(4.0, 4.0),
1293 to: point(0.0, 4.0)
1294 }
1295 .clipped(&b),
1296 Some(LineSegment {
1297 from: point(3.0, 4.0),
1298 to: point(1.0, 4.0)
1299 })
1300 );
1301 assert_eq!(
1302 LineSegment {
1303 from: point(4.0, 5.0),
1304 to: point(0.0, 5.0)
1305 }
1306 .clipped(&b),
1307 None
1308 );
1309
1310 assert_eq!(
1311 LineSegment {
1312 from: point(0.0, 0.0),
1313 to: point(0.0, 5.0)
1314 }
1315 .clipped(&b),
1316 None
1317 );
1318 assert_eq!(
1319 LineSegment {
1320 from: point(1.0, 0.0),
1321 to: point(1.0, 5.0)
1322 }
1323 .clipped(&b),
1324 Some(LineSegment {
1325 from: point(1.0, 2.0),
1326 to: point(1.0, 4.0)
1327 })
1328 );
1329 assert_eq!(
1330 LineSegment {
1331 from: point(2.0, 0.0),
1332 to: point(2.0, 5.0)
1333 }
1334 .clipped(&b),
1335 Some(LineSegment {
1336 from: point(2.0, 2.0),
1337 to: point(2.0, 4.0)
1338 })
1339 );
1340 assert_eq!(
1341 LineSegment {
1342 from: point(3.0, 0.0),
1343 to: point(3.0, 5.0)
1344 }
1345 .clipped(&b),
1346 Some(LineSegment {
1347 from: point(3.0, 2.0),
1348 to: point(3.0, 4.0)
1349 })
1350 );
1351 assert_eq!(
1352 LineSegment {
1353 from: point(4.0, 0.0),
1354 to: point(4.0, 5.0)
1355 }
1356 .clipped(&b),
1357 None
1358 );
1359
1360 assert_eq!(
1361 LineSegment {
1362 from: point(0.0, 5.0),
1363 to: point(0.0, 0.0)
1364 }
1365 .clipped(&b),
1366 None
1367 );
1368 assert_eq!(
1369 LineSegment {
1370 from: point(1.0, 5.0),
1371 to: point(1.0, 0.0)
1372 }
1373 .clipped(&b),
1374 Some(LineSegment {
1375 from: point(1.0, 4.0),
1376 to: point(1.0, 2.0)
1377 })
1378 );
1379 assert_eq!(
1380 LineSegment {
1381 from: point(2.0, 5.0),
1382 to: point(2.0, 0.0)
1383 }
1384 .clipped(&b),
1385 Some(LineSegment {
1386 from: point(2.0, 4.0),
1387 to: point(2.0, 2.0)
1388 })
1389 );
1390 assert_eq!(
1391 LineSegment {
1392 from: point(3.0, 5.0),
1393 to: point(3.0, 0.0)
1394 }
1395 .clipped(&b),
1396 Some(LineSegment {
1397 from: point(3.0, 4.0),
1398 to: point(3.0, 2.0)
1399 })
1400 );
1401 assert_eq!(
1402 LineSegment {
1403 from: point(4.0, 5.0),
1404 to: point(4.0, 0.0)
1405 }
1406 .clipped(&b),
1407 None
1408 );
1409
1410 assert!(approx_eq(
1411 LineSegment {
1412 from: point(0.0, 2.0),
1413 to: point(4.0, 4.0)
1414 }
1415 .clipped(&b)
1416 .unwrap(),
1417 LineSegment {
1418 from: point(1.0, 2.5),
1419 to: point(3.0, 3.5)
1420 }
1421 ));
1422 assert!(approx_eq(
1423 LineSegment {
1424 from: point(4.0, 4.0),
1425 to: point(0.0, 2.0)
1426 }
1427 .clipped(&b)
1428 .unwrap(),
1429 LineSegment {
1430 from: point(3.0, 3.5),
1431 to: point(1.0, 2.5)
1432 }
1433 ));
1434
1435 let inside = [
1436 LineSegment {
1437 from: point(1.0, 2.0),
1438 to: point(3.0, 4.0),
1439 },
1440 LineSegment {
1441 from: point(1.5, 2.0),
1442 to: point(1.0, 4.0),
1443 },
1444 LineSegment {
1445 from: point(1.0, 3.0),
1446 to: point(2.0, 3.0),
1447 },
1448 ];
1449
1450 for segment in &inside {
1451 assert_eq!(segment.clipped(&b), Some(*segment));
1452 assert_eq!(segment.flip().clipped(&b), Some(segment.flip()));
1453 }
1454
1455 let outside = [
1456 LineSegment {
1457 from: point(2.0, 0.0),
1458 to: point(5.0, 3.0),
1459 },
1460 LineSegment {
1461 from: point(-20.0, 0.0),
1462 to: point(4.0, 8.0),
1463 },
1464 ];
1465
1466 for segment in &outside {
1467 assert_eq!(segment.clipped(&b), None);
1468 assert_eq!(segment.flip().clipped(&b), None);
1469 }
1470}
1471
1472#[test]
1473fn equation() {
1474 let lines = [
1475 Line {
1476 point: point(100.0f64, 20.0),
1477 vector: vector(-1.0, 3.0),
1478 },
1479 Line {
1480 point: point(-30.0, 150.0),
1481 vector: vector(10.0, 2.0),
1482 },
1483 Line {
1484 point: point(50.0, -10.0),
1485 vector: vector(5.0, -1.0),
1486 },
1487 ];
1488
1489 for line in &lines {
1490 let eqn = line.equation();
1491 use euclid::approxeq::ApproxEq;
1492 for t in [-100.0, -50.0, 0.0, 25.0, 325.0] {
1493 let p = line.point + line.vector * t;
1494 assert!(eqn.solve_y_for_x(p.x).unwrap().approx_eq(&p.y));
1495 assert!(eqn.solve_x_for_y(p.y).unwrap().approx_eq(&p.x));
1496 }
1497 }
1498}
1499