diff --git a/crates/fj-kernel/src/algorithms/mod.rs b/crates/fj-kernel/src/algorithms/mod.rs index 402d5ab9f..08319f8a7 100644 --- a/crates/fj-kernel/src/algorithms/mod.rs +++ b/crates/fj-kernel/src/algorithms/mod.rs @@ -10,6 +10,7 @@ mod transform; mod triangulate; pub mod intersection; +pub mod ray_cast; pub use self::{ approx::{CycleApprox, FaceApprox, InvalidTolerance, Tolerance}, diff --git a/crates/fj-kernel/src/algorithms/triangulate/ray.rs b/crates/fj-kernel/src/algorithms/ray_cast.rs similarity index 62% rename from crates/fj-kernel/src/algorithms/triangulate/ray.rs rename to crates/fj-kernel/src/algorithms/ray_cast.rs index e46cbb05c..89d9e6f51 100644 --- a/crates/fj-kernel/src/algorithms/triangulate/ray.rs +++ b/crates/fj-kernel/src/algorithms/ray_cast.rs @@ -1,11 +1,22 @@ +//! Ray casting + use fj_math::{Point, Segment}; -pub struct HorizontalRayToTheRight { - pub origin: Point<2>, +/// A horizontal ray that goes to the right +/// +/// For in-kernel use, we don't need anything more flexible, and being exactly +/// horizontal simplifies some calculations. +pub struct HorizontalRayToTheRight { + /// The point where the ray originates + pub origin: Point, } -impl HorizontalRayToTheRight { - pub fn hits_segment(&self, segment: impl Into>) -> Option { +impl HorizontalRayToTheRight<2> { + /// Determine whether the ray hits the given line segment + pub fn hits_segment( + &self, + segment: impl Into>, + ) -> Option { let [a, b] = segment.into().points(); let [lower, upper] = if a.v <= b.v { [a, b] } else { [b, a] }; let right = if a.u > b.u { a } else { b }; @@ -26,7 +37,7 @@ impl HorizontalRayToTheRight { return None; } - return Some(Hit::Parallel); + return Some(RaySegmentHit::Parallel); } let pa = robust::Coord { @@ -46,22 +57,22 @@ impl HorizontalRayToTheRight { // ray starts on the line or left of it if self.origin.v == upper.v { - return Some(Hit::UpperVertex); + return Some(RaySegmentHit::UpperVertex); } if self.origin.v == lower.v { - return Some(Hit::LowerVertex); + return Some(RaySegmentHit::LowerVertex); } - return Some(Hit::Segment); + return Some(RaySegmentHit::Segment); } None } } -impl

From

for HorizontalRayToTheRight +impl From

for HorizontalRayToTheRight where - P: Into>, + P: Into>, { fn from(point: P) -> Self { Self { @@ -70,19 +81,25 @@ where } } +/// A hit between a ray and a line segment #[derive(Clone, Copy, Debug, Eq, PartialEq)] -pub enum Hit { +pub enum RaySegmentHit { + /// The ray hit the segment itself Segment, + /// The ray hit the lower vertex of the segment LowerVertex, + + /// The ray hit the upper vertex of the segment UpperVertex, + /// The ray hit the whole segment, as it is parallel to the ray Parallel, } #[cfg(test)] mod tests { - use super::{Hit, HorizontalRayToTheRight}; + use super::{HorizontalRayToTheRight, RaySegmentHit}; #[test] fn hits_segment_right() { @@ -94,7 +111,10 @@ mod tests { assert!(ray.hits_segment(below).is_none()); assert!(ray.hits_segment(above).is_none()); - assert!(matches!(ray.hits_segment(same_level), Some(Hit::Segment))); + assert!(matches!( + ray.hits_segment(same_level), + Some(RaySegmentHit::Segment) + )); } #[test] @@ -116,14 +136,17 @@ mod tests { let hit_lower = [[0., 2.], [2., 1.]]; assert!(ray.hits_segment(no_hit).is_none()); - assert!(matches!(ray.hits_segment(hit_segment), Some(Hit::Segment))); + assert!(matches!( + ray.hits_segment(hit_segment), + Some(RaySegmentHit::Segment) + )); assert!(matches!( ray.hits_segment(hit_upper), - Some(Hit::UpperVertex), + Some(RaySegmentHit::UpperVertex), )); assert!(matches!( ray.hits_segment(hit_lower), - Some(Hit::LowerVertex), + Some(RaySegmentHit::LowerVertex), )); } @@ -135,14 +158,17 @@ mod tests { let hit_upper = [[0., 0.], [1., 1.]]; let hit_lower = [[1., 1.], [2., 2.]]; - assert!(matches!(ray.hits_segment(hit_segment), Some(Hit::Segment))); + assert!(matches!( + ray.hits_segment(hit_segment), + Some(RaySegmentHit::Segment) + )); assert!(matches!( ray.hits_segment(hit_upper), - Some(Hit::UpperVertex), + Some(RaySegmentHit::UpperVertex), )); assert!(matches!( ray.hits_segment(hit_lower), - Some(Hit::LowerVertex), + Some(RaySegmentHit::LowerVertex), )); } @@ -155,7 +181,13 @@ mod tests { let right = [[3., 0.], [4., 0.]]; assert!(ray.hits_segment(left).is_none()); - assert!(matches!(ray.hits_segment(overlapping), Some(Hit::Parallel))); - assert!(matches!(ray.hits_segment(right), Some(Hit::Parallel))); + assert!(matches!( + ray.hits_segment(overlapping), + Some(RaySegmentHit::Parallel) + )); + assert!(matches!( + ray.hits_segment(right), + Some(RaySegmentHit::Parallel) + )); } } diff --git a/crates/fj-kernel/src/algorithms/triangulate/mod.rs b/crates/fj-kernel/src/algorithms/triangulate/mod.rs index 689c19992..27ddb01e8 100644 --- a/crates/fj-kernel/src/algorithms/triangulate/mod.rs +++ b/crates/fj-kernel/src/algorithms/triangulate/mod.rs @@ -1,6 +1,5 @@ mod delaunay; mod polygon; -mod ray; use fj_interop::{debug::DebugInfo, mesh::Mesh}; use fj_math::Point; diff --git a/crates/fj-kernel/src/algorithms/triangulate/polygon.rs b/crates/fj-kernel/src/algorithms/triangulate/polygon.rs index f813a7a13..eac7d93e8 100644 --- a/crates/fj-kernel/src/algorithms/triangulate/polygon.rs +++ b/crates/fj-kernel/src/algorithms/triangulate/polygon.rs @@ -1,9 +1,10 @@ use fj_interop::debug::{DebugInfo, TriangleEdgeCheck}; use fj_math::{Point, PolyChain, Segment}; -use crate::objects::Surface; - -use super::ray::{Hit, HorizontalRayToTheRight}; +use crate::{ + algorithms::ray_cast::{HorizontalRayToTheRight, RaySegmentHit}, + objects::Surface, +}; pub struct Polygon { surface: Surface, @@ -103,7 +104,7 @@ impl Polygon { } } - // We haven't rules out that the triangle is a polygon hole. Since we + // We haven't ruled out that the triangle is a polygon hole. Since we // checked all its edges, this means we now know for certain that is is. if might_be_hole { return false; @@ -162,12 +163,18 @@ impl Polygon { let hit = ray.hits_segment(edge); let count_hit = match (hit, previous_hit) { - (Some(Hit::Segment), _) => { + (Some(RaySegmentHit::Segment), _) => { // We're hitting a segment right-on. Clear case. true } - (Some(Hit::UpperVertex), Some(Hit::LowerVertex)) - | (Some(Hit::LowerVertex), Some(Hit::UpperVertex)) => { + ( + Some(RaySegmentHit::UpperVertex), + Some(RaySegmentHit::LowerVertex), + ) + | ( + Some(RaySegmentHit::LowerVertex), + Some(RaySegmentHit::UpperVertex), + ) => { // If we're hitting a vertex, only count it if we've hit // the other kind of vertex right before. // @@ -183,7 +190,7 @@ impl Polygon { // passing through anything. true } - (Some(Hit::Parallel), _) => { + (Some(RaySegmentHit::Parallel), _) => { // A parallel edge must be completely ignored. Its // presence won't change anything, so we can treat it as // if it wasn't there, and its neighbors were connected