diff --git a/crates/fj-kernel/src/algorithms/intersect/curve_edge.rs b/crates/fj-kernel/src/algorithms/intersect/curve_edge.rs index db6e5316a..47746980a 100644 --- a/crates/fj-kernel/src/algorithms/intersect/curve_edge.rs +++ b/crates/fj-kernel/src/algorithms/intersect/curve_edge.rs @@ -88,7 +88,8 @@ mod tests { let surface = Surface::xy_plane(); let curve = Curve::builder(&stores, surface).build_u_axis(); let half_edge = HalfEdge::builder(&stores, surface) - .build_line_segment_from_points([[1., -1.], [1., 1.]]); + .as_line_segment_from_points([[1., -1.], [1., 1.]]) + .build(); let intersection = CurveEdgeIntersection::compute(&curve, &half_edge); @@ -107,7 +108,8 @@ mod tests { let surface = Surface::xy_plane(); let curve = Curve::builder(&stores, surface).build_u_axis(); let half_edge = HalfEdge::builder(&stores, surface) - .build_line_segment_from_points([[-1., -1.], [-1., 1.]]); + .as_line_segment_from_points([[-1., -1.], [-1., 1.]]) + .build(); let intersection = CurveEdgeIntersection::compute(&curve, &half_edge); @@ -126,7 +128,8 @@ mod tests { let surface = Surface::xy_plane(); let curve = Curve::builder(&stores, surface).build_u_axis(); let half_edge = HalfEdge::builder(&stores, surface) - .build_line_segment_from_points([[-1., -1.], [1., -1.]]); + .as_line_segment_from_points([[-1., -1.], [1., -1.]]) + .build(); let intersection = CurveEdgeIntersection::compute(&curve, &half_edge); @@ -140,7 +143,8 @@ mod tests { let surface = Surface::xy_plane(); let curve = Curve::builder(&stores, surface).build_u_axis(); let half_edge = HalfEdge::builder(&stores, surface) - .build_line_segment_from_points([[-1., 0.], [1., 0.]]); + .as_line_segment_from_points([[-1., 0.], [1., 0.]]) + .build(); let intersection = CurveEdgeIntersection::compute(&curve, &half_edge); diff --git a/crates/fj-kernel/src/algorithms/sweep/edge.rs b/crates/fj-kernel/src/algorithms/sweep/edge.rs index bcb5c5eb3..bbb680784 100644 --- a/crates/fj-kernel/src/algorithms/sweep/edge.rs +++ b/crates/fj-kernel/src/algorithms/sweep/edge.rs @@ -192,7 +192,8 @@ mod tests { let stores = Stores::new(); let half_edge = HalfEdge::builder(&stores, Surface::xy_plane()) - .build_line_segment_from_points([[0., 0.], [1., 0.]]); + .as_line_segment_from_points([[0., 0.], [1., 0.]]) + .build(); let face = (half_edge, Color::default()).sweep([0., 0., 1.], &stores); @@ -200,15 +201,19 @@ mod tests { let surface = Surface::xz_plane(); let bottom = HalfEdge::builder(&stores, surface) - .build_line_segment_from_points([[0., 0.], [1., 0.]]); + .as_line_segment_from_points([[0., 0.], [1., 0.]]) + .build(); let top = HalfEdge::builder(&stores, surface) - .build_line_segment_from_points([[0., 1.], [1., 1.]]) + .as_line_segment_from_points([[0., 1.], [1., 1.]]) + .build() .reverse(); let left = HalfEdge::builder(&stores, surface) - .build_line_segment_from_points([[0., 0.], [0., 1.]]) + .as_line_segment_from_points([[0., 0.], [0., 1.]]) + .build() .reverse(); let right = HalfEdge::builder(&stores, surface) - .build_line_segment_from_points([[1., 0.], [1., 1.]]); + .as_line_segment_from_points([[1., 0.], [1., 1.]]) + .build(); let cycle = Cycle::new(surface, [bottom, right, top, left]); diff --git a/crates/fj-kernel/src/algorithms/sweep/face.rs b/crates/fj-kernel/src/algorithms/sweep/face.rs index 36906cfbd..9872e0466 100644 --- a/crates/fj-kernel/src/algorithms/sweep/face.rs +++ b/crates/fj-kernel/src/algorithms/sweep/face.rs @@ -113,7 +113,8 @@ mod tests { let [a, b] = [window[0], window[1]]; let half_edge = HalfEdge::builder(&stores, Surface::xy_plane()) - .build_line_segment_from_points([a, b]); + .as_line_segment_from_points([a, b]) + .build(); (half_edge, Color::default()).sweep(UP, &stores) }); @@ -148,7 +149,8 @@ mod tests { let [a, b] = [window[0], window[1]]; let half_edge = HalfEdge::builder(&stores, Surface::xy_plane()) - .build_line_segment_from_points([a, b]) + .as_line_segment_from_points([a, b]) + .build() .reverse(); (half_edge, Color::default()).sweep(DOWN, &stores) }); diff --git a/crates/fj-kernel/src/algorithms/sweep/vertex.rs b/crates/fj-kernel/src/algorithms/sweep/vertex.rs index 9de2da1a4..2aad1162d 100644 --- a/crates/fj-kernel/src/algorithms/sweep/vertex.rs +++ b/crates/fj-kernel/src/algorithms/sweep/vertex.rs @@ -166,7 +166,8 @@ mod tests { let half_edge = (vertex, surface).sweep([0., 0., 1.], &stores); let expected_half_edge = HalfEdge::builder(&stores, surface) - .build_line_segment_from_points([[0., 0.], [0., 1.]]); + .as_line_segment_from_points([[0., 0.], [0., 1.]]) + .build(); assert_eq!(half_edge, expected_half_edge); } diff --git a/crates/fj-kernel/src/builder/cycle.rs b/crates/fj-kernel/src/builder/cycle.rs index cd67cb684..a31a333f3 100644 --- a/crates/fj-kernel/src/builder/cycle.rs +++ b/crates/fj-kernel/src/builder/cycle.rs @@ -53,7 +53,8 @@ impl<'a> CycleBuilder<'a> { self.half_edges.push( HalfEdge::builder(self.stores, self.surface) - .build_line_segment_from_points(points), + .as_line_segment_from_points(points) + .build(), ); } @@ -74,7 +75,8 @@ impl<'a> CycleBuilder<'a> { [last, first].map(|vertex| vertex.surface_form().position()); self.half_edges.push( HalfEdge::builder(self.stores, self.surface) - .build_line_segment_from_points(vertices), + .as_line_segment_from_points(vertices) + .build(), ); } diff --git a/crates/fj-kernel/src/builder/edge.rs b/crates/fj-kernel/src/builder/edge.rs index c2c6899f4..707b8965c 100644 --- a/crates/fj-kernel/src/builder/edge.rs +++ b/crates/fj-kernel/src/builder/edge.rs @@ -9,23 +9,50 @@ use crate::{ stores::Stores, }; -/// API for building an [`HalfEdge`] +/// API for building a [`HalfEdge`] /// /// Also see [`HalfEdge::builder`]. pub struct HalfEdgeBuilder<'a> { /// The stores that the created objects are put in pub stores: &'a Stores, - /// The surface that the [`HalfEdge`] is defined in + /// The surface that the [`HalfEdge`]'s [`Curve`] is defined in pub surface: Surface, + + /// The curve that the [`HalfEdge`] is defined in + pub curve: Option, + + /// The vertices that bound this [`HalfEdge`] in the [`Curve`] + pub vertices: Option<[Vertex; 2]>, + + /// The global form of the [`HalfEdge`] + /// + /// Can be provided to the builder, if available, or computed by one of the + /// build methods. + pub global_form: Option, } impl<'a> HalfEdgeBuilder<'a> { - /// Build a circle from the given radius - pub fn build_circle_from_radius( - self, - radius: impl Into, - ) -> HalfEdge { + /// Build the [`HalfEdge`] with the given curve + pub fn with_curve(mut self, curve: Curve) -> Self { + self.curve = Some(curve); + self + } + + /// Build the [`HalfEdge`] with the given vertices + pub fn with_vertices(mut self, vertices: [Vertex; 2]) -> Self { + self.vertices = Some(vertices); + self + } + + /// Build the [`HalfEdge`] with the provided global form + pub fn with_global_form(mut self, global_form: GlobalEdge) -> Self { + self.global_form = Some(global_form); + self + } + + /// Build the [`HalfEdge`] as a circle from the given radius + pub fn as_circle_from_radius(mut self, radius: impl Into) -> Self { let curve = Curve::builder(self.stores, self.surface) .build_circle_from_radius(radius); @@ -57,17 +84,17 @@ impl<'a> HalfEdgeBuilder<'a> { ) }; - let global_form = GlobalEdge::builder() - .build_from_curve_and_vertices(&curve, &vertices); + self.curve = Some(curve); + self.vertices = Some(vertices); - HalfEdge::new(curve, vertices, global_form) + self } - /// Build a line segment from two points - pub fn build_line_segment_from_points( - self, + /// Build the [`HalfEdge`] as a line segment from the given points + pub fn as_line_segment_from_points( + mut self, points: [impl Into>; 2], - ) -> HalfEdge { + ) -> Self { let points = points.map(Into::into); let global_vertices = points.map(|position| { @@ -124,8 +151,23 @@ impl<'a> HalfEdgeBuilder<'a> { ] }; - let global_form = GlobalEdge::builder() - .build_from_curve_and_vertices(&curve, &vertices); + self.curve = Some(curve); + self.vertices = Some(vertices); + + self + } + + /// Finish building the [`HalfEdge`] + pub fn build(self) -> HalfEdge { + let curve = self.curve.expect("Can't build `HalfEdge` without curve"); + let vertices = self + .vertices + .expect("Can't build `HalfEdge` without vertices"); + + let global_form = self.global_form.unwrap_or_else(|| { + GlobalEdge::builder() + .build_from_curve_and_vertices(&curve, &vertices) + }); HalfEdge::new(curve, vertices, global_form) } diff --git a/crates/fj-kernel/src/builder/vertex.rs b/crates/fj-kernel/src/builder/vertex.rs index 88a0dc193..50587c19c 100644 --- a/crates/fj-kernel/src/builder/vertex.rs +++ b/crates/fj-kernel/src/builder/vertex.rs @@ -38,7 +38,7 @@ impl VertexBuilder { self } - /// Build a vertex from a curve position + /// Finish building the [`Vertex`] pub fn build(self) -> Vertex { let surface_form = self.surface_form.unwrap_or_else(|| { SurfaceVertexBuilder { diff --git a/crates/fj-kernel/src/iter.rs b/crates/fj-kernel/src/iter.rs index 288a85cd7..70902efa0 100644 --- a/crates/fj-kernel/src/iter.rs +++ b/crates/fj-kernel/src/iter.rs @@ -462,7 +462,8 @@ mod tests { let stores = Stores::new(); let object = HalfEdge::builder(&stores, Surface::xy_plane()) - .build_line_segment_from_points([[0., 0.], [1., 0.]]); + .as_line_segment_from_points([[0., 0.], [1., 0.]]) + .build(); assert_eq!(1, object.curve_iter().count()); assert_eq!(0, object.cycle_iter().count()); diff --git a/crates/fj-kernel/src/objects/edge.rs b/crates/fj-kernel/src/objects/edge.rs index ee955d787..b435d5584 100644 --- a/crates/fj-kernel/src/objects/edge.rs +++ b/crates/fj-kernel/src/objects/edge.rs @@ -18,7 +18,13 @@ pub struct HalfEdge { impl HalfEdge { /// Build a `HalfEdge` using [`HalfEdgeBuilder`] pub fn builder(stores: &Stores, surface: Surface) -> HalfEdgeBuilder { - HalfEdgeBuilder { stores, surface } + HalfEdgeBuilder { + stores, + surface, + curve: None, + vertices: None, + global_form: None, + } } /// Create a new instance of `HalfEdge` diff --git a/crates/fj-operations/src/sketch.rs b/crates/fj-operations/src/sketch.rs index 1995f1f8e..eab95e706 100644 --- a/crates/fj-operations/src/sketch.rs +++ b/crates/fj-operations/src/sketch.rs @@ -27,7 +27,8 @@ impl Shape for fj::Sketch { // none need to be added here. let half_edge = HalfEdge::builder(stores, surface) - .build_circle_from_radius(circle.radius()); + .as_circle_from_radius(circle.radius()) + .build(); let cycle = Cycle::new(surface, [half_edge]); Face::from_exterior(cycle).with_color(Color(self.color()))