diff --git a/crates/fj-kernel/src/builder/curve.rs b/crates/fj-kernel/src/builder/curve.rs index c094c14a5..acc790cf1 100644 --- a/crates/fj-kernel/src/builder/curve.rs +++ b/crates/fj-kernel/src/builder/curve.rs @@ -38,6 +38,14 @@ pub trait CurveBuilder { &mut self, points: [impl Into>; 2], ) -> SurfacePath; + + /// Update partial curve to be a line, from provided points and line coords + /// + /// Returns the updated path. + fn update_as_line_from_points_with_line_coords( + &mut self, + points: [(impl Into>, impl Into>); 2], + ) -> SurfacePath; } impl CurveBuilder for PartialCurve { @@ -82,4 +90,13 @@ impl CurveBuilder for PartialCurve { self.path = Some(path.into()); path } + + fn update_as_line_from_points_with_line_coords( + &mut self, + points: [(impl Into>, impl Into>); 2], + ) -> SurfacePath { + let path = SurfacePath::from_points_with_line_coords(points); + self.path = Some(path.into()); + path + } } diff --git a/crates/fj-kernel/src/builder/edge.rs b/crates/fj-kernel/src/builder/edge.rs index 3f608935f..247addb01 100644 --- a/crates/fj-kernel/src/builder/edge.rs +++ b/crates/fj-kernel/src/builder/edge.rs @@ -150,6 +150,7 @@ impl HalfEdgeBuilder for PartialHalfEdge { } fn update_as_line_segment(&mut self) { + let boundary = self.vertices.each_ref_ext().map(|vertex| vertex.0); let points_surface = self.vertices.each_ref_ext().map(|vertex| { vertex .1 @@ -158,13 +159,23 @@ impl HalfEdgeBuilder for PartialHalfEdge { .expect("Can't infer line segment without surface position") }); - self.curve - .write() - .update_as_line_from_points(points_surface); - - for (vertex, position) in self.vertices.each_mut_ext().zip_ext([0., 1.]) - { - vertex.0 = Some([position].into()); + if let [Some(start), Some(end)] = boundary { + let boundary = [start, end]; + self.curve + .write() + .update_as_line_from_points_with_line_coords( + boundary.zip_ext(points_surface), + ); + } else { + self.curve + .write() + .update_as_line_from_points(points_surface); + + for (vertex, position) in + self.vertices.each_mut_ext().zip_ext([0., 1.]) + { + vertex.0 = Some([position].into()); + } } self.infer_global_form(); diff --git a/crates/fj-kernel/src/geometry/path.rs b/crates/fj-kernel/src/geometry/path.rs index 01fefdf2a..f84b143b2 100644 --- a/crates/fj-kernel/src/geometry/path.rs +++ b/crates/fj-kernel/src/geometry/path.rs @@ -58,6 +58,13 @@ impl SurfacePath { (Self::Line(line), coords) } + /// Create a line from two points that include line coordinates + pub fn from_points_with_line_coords( + points: [(impl Into>, impl Into>); 2], + ) -> Self { + Self::Line(Line::from_points_with_line_coords(points)) + } + /// Convert a point on the path into surface coordinates pub fn point_from_path_coords( &self, diff --git a/crates/fj-math/src/line.rs b/crates/fj-math/src/line.rs index 900006f58..c2a6c513f 100644 --- a/crates/fj-math/src/line.rs +++ b/crates/fj-math/src/line.rs @@ -181,6 +181,30 @@ mod tests { use super::Line; + #[test] + fn from_points_with_line_coords() { + let line = Line::from_points_with_line_coords([ + ([0.], [0., 0.]), + ([1.], [1., 0.]), + ]); + assert_eq!(line.origin(), Point::from([0., 0.])); + assert_eq!(line.direction(), Vector::from([1., 0.])); + + let line = Line::from_points_with_line_coords([ + ([1.], [0., 1.]), + ([0.], [1., 1.]), + ]); + assert_eq!(line.origin(), Point::from([1., 1.])); + assert_eq!(line.direction(), Vector::from([-1., 0.])); + + let line = Line::from_points_with_line_coords([ + ([-1.], [0., 2.]), + ([0.], [1., 2.]), + ]); + assert_eq!(line.origin(), Point::from([1., 2.])); + assert_eq!(line.direction(), Vector::from([1., 0.])); + } + #[test] fn is_coincident_with() { let (line, _) = Line::from_points([[0., 0.], [1., 0.]]);