diff --git a/crates/fj-kernel/src/algorithms/triangulate/delaunay.rs b/crates/fj-kernel/src/algorithms/triangulate/delaunay.rs index 7449f7735..c54aa508d 100644 --- a/crates/fj-kernel/src/algorithms/triangulate/delaunay.rs +++ b/crates/fj-kernel/src/algorithms/triangulate/delaunay.rs @@ -18,6 +18,7 @@ pub fn triangulate(points: Vec>>) -> Vec<[Local>; 3]> { *v1.local_form(), *v2.local_form(), ]) + .expect("invalid triangle") .winding_direction(); let triangle = match orientation { diff --git a/crates/fj-math/src/line.rs b/crates/fj-math/src/line.rs index f69ff0374..4c07cac56 100644 --- a/crates/fj-math/src/line.rs +++ b/crates/fj-math/src/line.rs @@ -1,4 +1,4 @@ -use crate::{Point, Vector}; +use crate::{Point, Triangle, Vector}; /// An n-dimensional line, defined by an origin and a direction /// @@ -33,6 +33,33 @@ impl Line { } } + /// Determine if this line is coincident with another line + /// + /// # Implementation Note + /// + /// This method only returns `true`, if the lines are precisely coincident. + /// This will probably not be enough going forward, but it'll do for now. + pub fn is_coincident_with(&self, other: &Self) -> bool { + let other_origin_is_not_on_self = { + let a = other.origin; + let b = self.origin; + let c = self.origin + self.direction; + + // The triangle is valid only, if the three points are not on the + // same line. + Triangle::from_points([a, b, c]).is_some() + }; + + if other_origin_is_not_on_self { + return false; + } + + let d1 = self.direction.normalize(); + let d2 = other.direction.normalize(); + + d1 == d2 || d1 == -d2 + } + /// Create a new instance that is reversed #[must_use] pub fn reverse(mut self) -> Self { @@ -102,6 +129,19 @@ mod tests { use super::Line; + #[test] + fn is_coincident_with() { + let line = Line::from_points([[0., 0.], [1., 0.]]); + + let a = Line::from_points([[0., 0.], [1., 0.]]); + let b = Line::from_points([[0., 0.], [-1., 0.]]); + let c = Line::from_points([[0., 1.], [1., 1.]]); + + assert!(line.is_coincident_with(&a)); + assert!(line.is_coincident_with(&b)); + assert!(!line.is_coincident_with(&c)); + } + #[test] fn convert_point_to_line_coords() { let line = Line { diff --git a/crates/fj-math/src/triangle.rs b/crates/fj-math/src/triangle.rs index 92dc8ec37..f4cd21888 100644 --- a/crates/fj-math/src/triangle.rs +++ b/crates/fj-math/src/triangle.rs @@ -21,7 +21,7 @@ impl Triangle { /// # Panics /// /// Panics, if the points don't form a triangle. - pub fn from_points(points: [impl Into>; 3]) -> Self { + pub fn from_points(points: [impl Into>; 3]) -> Option { let points = points.map(Into::into); let area = { @@ -31,9 +31,9 @@ impl Triangle { // A triangle is not valid if it doesn't span any area if area != Scalar::from(0.0) { - Self { points } + Some(Self { points }) } else { - panic!("Invalid Triangle specified"); + None } } @@ -103,7 +103,7 @@ where P: Into>, { fn from(points: [P; 3]) -> Self { - Self::from_points(points) + Self::from_points(points).expect("invalid triangle") } }