diff --git a/crates/fj-core/src/geometry/curve.rs b/crates/fj-core/src/geometry/curve.rs index 9b5100581..3d036ff68 100644 --- a/crates/fj-core/src/geometry/curve.rs +++ b/crates/fj-core/src/geometry/curve.rs @@ -2,7 +2,11 @@ use std::collections::BTreeMap; use fj_math::{Circle, Line, Point}; -use crate::{storage::Handle, topology::Surface}; +use crate::{ + algorithms::approx::{PathApproxParams, Tolerance}, + storage::Handle, + topology::Surface, +}; use super::Path; @@ -68,18 +72,54 @@ pub struct LocalCurveGeom { pub trait CurveGeom2 { /// # Access the origin of the curve fn origin(&self) -> Point; + + /// # Compute a line segment to approximate the curve at this point + /// + /// If the curve requires no approximation (meaning it is a line), then per + /// convention, a degenerate line segment is returned, that collapses to the + /// provided point. + fn line_segment_at( + &self, + point: impl Into>, + tolerance: impl Into, + ) -> [Point; 2]; } impl CurveGeom2 for Circle { fn origin(&self) -> Point { self.center() + self.a() } + + fn line_segment_at( + &self, + point: impl Into>, + tolerance: impl Into, + ) -> [Point; 2] { + let point = point.into(); + let params = PathApproxParams::for_circle(self, tolerance); + + [point.t - params.increment(), point.t + params.increment()] + .map(|point_circle| self.point_from_circle_coords([point_circle])) + } } impl CurveGeom2 for Line { fn origin(&self) -> Point { self.origin() } + + fn line_segment_at( + &self, + point: impl Into>, + _: impl Into, + ) -> [Point; 2] { + let point = point.into(); + + // Collapse line segment into a point, as per documentation. + let point = self.origin() + self.direction() * point.t; + + [point, point] + } } // This implementation is temporary, to ease the transition towards a curve @@ -91,4 +131,15 @@ impl CurveGeom2 for Path { Self::Line(line) => line.origin(), } } + + fn line_segment_at( + &self, + point: impl Into>, + tolerance: impl Into, + ) -> [Point; 2] { + match self { + Self::Circle(circle) => circle.line_segment_at(point, tolerance), + Self::Line(line) => line.line_segment_at(point, tolerance), + } + } } diff --git a/crates/fj-core/src/geometry/surface.rs b/crates/fj-core/src/geometry/surface.rs index 40e5da5a5..7f564444b 100644 --- a/crates/fj-core/src/geometry/surface.rs +++ b/crates/fj-core/src/geometry/surface.rs @@ -2,7 +2,7 @@ use fj_math::{Point, Scalar, Transform, Triangle, Vector}; -use crate::algorithms::approx::{PathApproxParams, Tolerance}; +use crate::algorithms::approx::Tolerance; use super::{CurveGeom2, Path}; @@ -67,23 +67,10 @@ impl SurfaceGeom { let line_segment = match &self.u { Path::Circle(circle) => { - let params = PathApproxParams::for_circle(circle, tolerance); - - [ - point_surface.u - params.increment(), - point_surface.u + params.increment(), - ] - .map(|point_circle| { - circle.point_from_circle_coords([point_circle]) - }) + circle.line_segment_at([point_surface.u], tolerance) } Path::Line(line) => { - // We don't need to approximate a line. So instead of creating a - // line segment to represent the line at this point, we just - // need this single point. - let point = line.origin() + line.direction() * point_surface.u; - - [point, point] + line.line_segment_at([point_surface.u], tolerance) } };