aboutsummaryrefslogtreecommitdiff
path: root/src/math/line_segment.rs
diff options
context:
space:
mode:
authorArne Dußin2020-12-21 01:22:15 +0100
committerArne Dußin2020-12-21 21:15:55 +0100
commitd7e9c3cc46d616c2fcd1a6e9f73adbb79c6570b4 (patch)
treee5633f4d3b18472922c943d759e9f58722ba4405 /src/math/line_segment.rs
parent48f321a80970ebeb8374072b1d2e0a4d297aa348 (diff)
downloadgraf_karto-d7e9c3cc46d616c2fcd1a6e9f73adbb79c6570b4.tar.gz
graf_karto-d7e9c3cc46d616c2fcd1a6e9f73adbb79c6570b4.zip
Add previously missing docs where appropriate
Diffstat (limited to 'src/math/line_segment.rs')
-rw-r--r--src/math/line_segment.rs51
1 files changed, 49 insertions, 2 deletions
diff --git a/src/math/line_segment.rs b/src/math/line_segment.rs
index b496787..204cf0c 100644
--- a/src/math/line_segment.rs
+++ b/src/math/line_segment.rs
@@ -1,3 +1,6 @@
+//! A line segment is like a line, but with a start and an end, with the line only being between
+//! those two.
+
use super::{Rect, Surface, TripletOrientation, Vec2};
use alga::general::{ClosedDiv, ClosedMul, ClosedSub};
use nalgebra::{RealField, Scalar};
@@ -5,6 +8,7 @@ use num_traits::Zero;
use serde::{Deserialize, Serialize};
use std::cmp::Ordering;
+#[allow(missing_docs)]
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct LineSegment<T: Scalar + Copy> {
pub start: Vec2<T>,
@@ -12,6 +16,7 @@ pub struct LineSegment<T: Scalar + Copy> {
}
impl<T: Scalar + Copy> LineSegment<T> {
+ /// Create a new line segment from `start` to `end`
pub fn new(start: Vec2<T>, end: Vec2<T>) -> Self {
Self { start, end }
}
@@ -92,6 +97,9 @@ impl<T: Scalar + Copy> LineSegment<T> {
false
}
+ /// Try to find the the point where the two line segments intersect. If they do not intersect,
+ /// `None` is returned. If the lines are parallel and intersect (at least part of a line is on
+ /// a part of the other line), inside that region is returned.
pub fn intersection(line_a: &LineSegment<T>, line_b: &LineSegment<T>) -> Option<Vec2<T>>
where
T: ClosedSub + ClosedMul + ClosedDiv + Zero + RealField,
@@ -104,10 +112,26 @@ impl<T: Scalar + Copy> LineSegment<T> {
let dby = line_b.start.y - line_b.end.y;
// Calculate determinant to see, if the lines are parallel or not
- // TODO: Collinearity check?
let d = (dax * dby) - (day * dbx);
if d == T::zero() {
- None
+ // The two line segments are parallel, check if one may be on the other.
+ if super::triplet_orientation(line_a.start, line_a.end, line_b.start) == TripletOrientation::Collinear
+ && super::triplet_orientation(line_a.start, line_a.end, line_b.end) == TripletOrientation::Collinear
+ {
+ if line_a.contains_collinear(line_b.start) {
+ Some(line_b.start)
+ } else if line_a.contains_collinear(line_b.end) {
+ Some(line_b.end)
+ } else if line_b.contains_collinear(line_a.start) {
+ Some(line_a.start)
+ } else if line_b.contains_collinear(line_a.end) {
+ Some(line_a.end)
+ } else {
+ None
+ }
+ } else {
+ None
+ }
} else {
let ad = (line_a.start.x * line_a.end.y) - (line_a.start.y * line_a.end.x);
let bd = (line_b.start.x * line_b.end.y) - (line_b.start.y * line_b.end.x);
@@ -190,4 +214,27 @@ mod test {
assert!(!segment.contains_collinear(Vec2::new(3., 3.)));
assert!(!segment.contains_collinear(Vec2::new(-1., 0.)));
}
+
+ #[test]
+ fn line_intersection() {
+ let segment_a = LineSegment::new(Vec2::new(-1., -1.), Vec2::new(1., 1.));
+ let segment_b = LineSegment::new(Vec2::new(1., -1.), Vec2::new(-1., 1.));
+ let segment_c = LineSegment::new(Vec2::new(1., -1.), Vec2::new(2., 2.));
+
+ assert!(LineSegment::intersect(&segment_a, &segment_b));
+ assert!(LineSegment::intersect(&segment_b, &segment_c));
+ assert!(!LineSegment::intersect(&segment_a, &segment_c));
+ assert!(LineSegment::intersect(&segment_a, &segment_a));
+
+ assert_eq!(
+ LineSegment::intersection(&segment_a, &segment_b),
+ Some(Vec2::new(0., 0.))
+ );
+ assert_eq!(
+ LineSegment::intersection(&segment_b, &segment_c),
+ Some(Vec2::new(1., -1.))
+ );
+ assert_eq!(LineSegment::intersection(&segment_a, &segment_c), None);
+ assert!(LineSegment::intersection(&segment_a, &segment_a).is_some());
+ }
}