diff --git a/crates/fj-kernel/src/algorithms/sweep/edge.rs b/crates/fj-kernel/src/algorithms/sweep/edge.rs index 2f3cce225..a4c09f01e 100644 --- a/crates/fj-kernel/src/algorithms/sweep/edge.rs +++ b/crates/fj-kernel/src/algorithms/sweep/edge.rs @@ -208,58 +208,56 @@ mod tests { let face = (half_edge, Color::default()).sweep([0., 0., 1.], &objects)?; - let expected_face = { - let surface = objects.surfaces.xz_plane(); + let expected_face = + { + let surface = objects.surfaces.xz_plane(); - let bottom = HalfEdge::partial() - .update_as_line_segment_from_points( - surface.clone(), - [[0., 0.], [1., 0.]], - ) - .build(&objects)?; - let side_up = HalfEdge::partial() - .with_surface(Some(surface.clone())) - .with_back_vertex(Some(Vertex::partial().with_surface_form( - Some(bottom.front().surface_form().clone()), - ))) - .with_front_vertex(Some(Vertex::partial().with_surface_form( - Some( + let bottom = HalfEdge::partial() + .update_as_line_segment_from_points( + surface.clone(), + [[0., 0.], [1., 0.]], + ) + .build(&objects)?; + let side_up = HalfEdge::partial() + .with_surface(surface.clone()) + .with_back_vertex(Vertex::partial().with_surface_form( + bottom.front().surface_form().clone(), + )) + .with_front_vertex(Vertex::partial().with_surface_form( SurfaceVertex::partial().with_position(Some([1., 1.])), - ), - ))) - .update_as_line_segment() - .build(&objects)?; - let top = HalfEdge::partial() - .with_surface(Some(surface.clone())) - .with_back_vertex(Some(Vertex::partial().with_surface_form( - Some( + )) + .update_as_line_segment() + .build(&objects)?; + let top = HalfEdge::partial() + .with_surface(surface.clone()) + .with_back_vertex(Vertex::partial().with_surface_form( SurfaceVertex::partial().with_position(Some([0., 1.])), - ), - ))) - .with_front_vertex(Some(Vertex::partial().with_surface_form( - Some(side_up.front().surface_form().clone()), - ))) - .update_as_line_segment() - .build(&objects)? - .reverse(&objects)?; - let side_down = HalfEdge::partial() - .with_surface(Some(surface)) - .with_back_vertex(Some(Vertex::partial().with_surface_form( - Some(bottom.back().surface_form().clone()), - ))) - .with_front_vertex(Some(Vertex::partial().with_surface_form( - Some(top.front().surface_form().clone()), - ))) - .update_as_line_segment() - .build(&objects)? - .reverse(&objects)?; + )) + .with_front_vertex(Vertex::partial().with_surface_form( + side_up.front().surface_form().clone(), + )) + .update_as_line_segment() + .build(&objects)? + .reverse(&objects)?; + let side_down = + HalfEdge::partial() + .with_surface(surface) + .with_back_vertex(Vertex::partial().with_surface_form( + bottom.back().surface_form().clone(), + )) + .with_front_vertex(Vertex::partial().with_surface_form( + top.front().surface_form().clone(), + )) + .update_as_line_segment() + .build(&objects)? + .reverse(&objects)?; - let cycle = objects - .cycles - .insert(Cycle::new([bottom, side_up, top, side_down]))?; + let cycle = objects + .cycles + .insert(Cycle::new([bottom, side_up, top, side_down]))?; - Face::builder(&objects).with_exterior(cycle).build() - }; + Face::builder(&objects).with_exterior(cycle).build() + }; assert_eq!(face, expected_face); Ok(()) diff --git a/crates/fj-kernel/src/algorithms/sweep/vertex.rs b/crates/fj-kernel/src/algorithms/sweep/vertex.rs index f348b561d..e99c493bc 100644 --- a/crates/fj-kernel/src/algorithms/sweep/vertex.rs +++ b/crates/fj-kernel/src/algorithms/sweep/vertex.rs @@ -184,7 +184,7 @@ mod tests { .build(&objects)?; let vertex = Vertex::partial() .with_position(Some([0.])) - .with_curve(Some(curve)) + .with_curve(curve) .build(&objects)?; let half_edge = diff --git a/crates/fj-kernel/src/algorithms/transform/edge.rs b/crates/fj-kernel/src/algorithms/transform/edge.rs index 71c72a8d1..5e96fbc03 100644 --- a/crates/fj-kernel/src/algorithms/transform/edge.rs +++ b/crates/fj-kernel/src/algorithms/transform/edge.rs @@ -25,19 +25,18 @@ impl TransformObject for PartialHalfEdge { Ok(vertex .into_partial() .transform(transform, objects)? - .with_curve(Some(curve.clone()))) + .with_curve(curve.clone())) }, )?; let global_form = self .global_form() .into_partial() .transform(transform, objects)? - .with_curve(curve.global_form()) - .into(); + .with_curve(curve.global_form()); Ok(Self::default() - .with_curve(Some(curve)) - .with_vertices(Some(vertices)) + .with_curve(curve) + .with_vertices(vertices) .with_global_form(global_form)) } } diff --git a/crates/fj-kernel/src/algorithms/transform/vertex.rs b/crates/fj-kernel/src/algorithms/transform/vertex.rs index a1a370621..b9db0f704 100644 --- a/crates/fj-kernel/src/algorithms/transform/vertex.rs +++ b/crates/fj-kernel/src/algorithms/transform/vertex.rs @@ -18,14 +18,13 @@ impl TransformObject for PartialVertex { let surface_form = self .surface_form() .into_partial() - .transform(transform, objects)? - .into(); + .transform(transform, objects)?; // Don't need to transform `self.position`, as that is in curve // coordinates and thus transforming the curve takes care of it. Ok(Self::default() .with_position(self.position()) - .with_curve(Some(curve)) + .with_curve(curve) .with_surface_form(surface_form)) } } diff --git a/crates/fj-kernel/src/builder/cycle.rs b/crates/fj-kernel/src/builder/cycle.rs index 86103d627..a2b5ca081 100644 --- a/crates/fj-kernel/src/builder/cycle.rs +++ b/crates/fj-kernel/src/builder/cycle.rs @@ -74,15 +74,15 @@ impl CycleBuilder for PartialCycle { let [from, to] = [(0., from), (1., to)].map(|(position, surface_form)| { Vertex::partial() - .with_curve(Some(curve.clone())) + .with_curve(curve.clone()) .with_position(Some([position])) - .with_surface_form(Some(surface_form)) + .with_surface_form(surface_form) }); half_edges.push( HalfEdge::partial() - .with_curve(Some(curve)) - .with_vertices(Some([from, to])), + .with_curve(curve) + .with_vertices([from, to]), ); continue; diff --git a/crates/fj-kernel/src/builder/edge.rs b/crates/fj-kernel/src/builder/edge.rs index 65c20f4a0..f85b1bc45 100644 --- a/crates/fj-kernel/src/builder/edge.rs +++ b/crates/fj-kernel/src/builder/edge.rs @@ -75,13 +75,11 @@ impl HalfEdgeBuilder for PartialHalfEdge { let [back, front] = [a_curve, b_curve].map(|point_curve| { Vertex::partial() .with_position(Some(point_curve)) - .with_curve(Some(curve.clone())) - .with_surface_form(Some(surface_vertex.clone())) + .with_curve(curve.clone()) + .with_surface_form(surface_vertex.clone()) }); - Ok(self - .with_curve(Some(curve)) - .with_vertices(Some([back, front]))) + Ok(self.with_curve(curve).with_vertices([back, front])) } fn update_as_line_segment_from_points( @@ -94,11 +92,11 @@ impl HalfEdgeBuilder for PartialHalfEdge { .with_surface(Some(surface.clone())) .with_position(Some(point)); - Vertex::partial().with_surface_form(Some(surface_form)) + Vertex::partial().with_surface_form(surface_form) }); - self.with_surface(Some(surface)) - .with_vertices(Some(vertices)) + self.with_surface(surface) + .with_vertices(vertices) .update_as_line_segment() } @@ -129,7 +127,7 @@ impl HalfEdgeBuilder for PartialHalfEdge { vertex.update_partial(|vertex| { vertex .with_position(Some([position])) - .with_curve(Some(curve.clone())) + .with_curve(curve.clone()) }) }); @@ -170,19 +168,18 @@ impl HalfEdgeBuilder for PartialHalfEdge { vertices.zip_ext(global_forms).map(|(vertex, global_form)| { vertex.update_partial(|vertex| { - vertex.clone().with_surface_form(Some( + vertex.clone().with_surface_form( vertex.surface_form().update_partial( |surface_vertex| { surface_vertex.with_global_form(global_form) }, ), - )) + ) }) }) }; - self.with_curve(Some(curve)) - .with_vertices(Some([back, front])) + self.with_curve(curve).with_vertices([back, front]) } } diff --git a/crates/fj-kernel/src/builder/shell.rs b/crates/fj-kernel/src/builder/shell.rs index 1785af97b..9c6d1629b 100644 --- a/crates/fj-kernel/src/builder/shell.rs +++ b/crates/fj-kernel/src/builder/shell.rs @@ -89,7 +89,7 @@ impl<'a> ShellBuilder<'a> { .zip(&surfaces) .map(|(half_edge, surface)| { HalfEdge::partial() - .with_global_form(Some(half_edge.global_form().clone())) + .with_global_form(half_edge.global_form().clone()) .update_as_line_segment_from_points( surface.clone(), [[Z, Z], [edge_length, Z]], @@ -112,10 +112,10 @@ impl<'a> ShellBuilder<'a> { .with_surface(Some(surface.clone())); HalfEdge::partial() - .with_vertices(Some([ - Vertex::partial().with_surface_form(Some(from)), - Vertex::partial().with_surface_form(Some(to)), - ])) + .with_vertices([ + Vertex::partial().with_surface_form(from), + Vertex::partial().with_surface_form(to), + ]) .update_as_line_segment() .build(self.objects) .unwrap() @@ -148,11 +148,11 @@ impl<'a> ShellBuilder<'a> { )); HalfEdge::partial() - .with_curve(Some(curve)) - .with_vertices(Some([ - Vertex::partial().with_surface_form(Some(from)), - Vertex::partial().with_surface_form(Some(to)), - ])) + .with_curve(curve) + .with_vertices([ + Vertex::partial().with_surface_form(from), + Vertex::partial().with_surface_form(to), + ]) .update_as_line_segment() .build(self.objects) .unwrap() @@ -171,11 +171,11 @@ impl<'a> ShellBuilder<'a> { let from = from.surface_form().clone(); let to = to.surface_form().clone(); - let from = Vertex::partial().with_surface_form(Some(from)); - let to = Vertex::partial().with_surface_form(Some(to)); + let from = Vertex::partial().with_surface_form(from); + let to = Vertex::partial().with_surface_form(to); HalfEdge::partial() - .with_vertices(Some([from, to])) + .with_vertices([from, to]) .update_as_line_segment() .build(self.objects) .unwrap() @@ -246,13 +246,13 @@ impl<'a> ShellBuilder<'a> { .map(|(vertex, surface_form)| { Vertex::partial() .with_position(Some(vertex.position())) - .with_surface_form(Some(surface_form)) + .with_surface_form(surface_form) }); edges.push( HalfEdge::partial() - .with_vertices(Some(vertices)) - .with_global_form(Some(edge.global_form().clone())) + .with_vertices(vertices) + .with_global_form(edge.global_form().clone()) .update_as_line_segment() .build(self.objects) .unwrap(), diff --git a/crates/fj-kernel/src/builder/vertex.rs b/crates/fj-kernel/src/builder/vertex.rs index 56c817738..813268a74 100644 --- a/crates/fj-kernel/src/builder/vertex.rs +++ b/crates/fj-kernel/src/builder/vertex.rs @@ -16,7 +16,7 @@ pub trait VertexBuilder { impl VertexBuilder for PartialVertex { fn infer_surface_form(self) -> Self { - self.with_surface_form(Some(PartialSurfaceVertex::default())) + self.with_surface_form(PartialSurfaceVertex::default()) } } diff --git a/crates/fj-kernel/src/partial/maybe_partial.rs b/crates/fj-kernel/src/partial/maybe_partial.rs index 5e7e7c1da..5b9cee73c 100644 --- a/crates/fj-kernel/src/partial/maybe_partial.rs +++ b/crates/fj-kernel/src/partial/maybe_partial.rs @@ -65,8 +65,8 @@ impl MaybePartial { } /// Merge this `MaybePartial` with another of the same type - pub fn merge_with(self, other: Self) -> Self { - match (self, other) { + pub fn merge_with(self, other: impl Into) -> Self { + match (self, other.into()) { (Self::Full(_), Self::Full(_)) => { panic!("Can't merge two full objects") } diff --git a/crates/fj-kernel/src/partial/objects/cycle.rs b/crates/fj-kernel/src/partial/objects/cycle.rs index 7d2c146a3..bc8479abf 100644 --- a/crates/fj-kernel/src/partial/objects/cycle.rs +++ b/crates/fj-kernel/src/partial/objects/cycle.rs @@ -1,6 +1,8 @@ use crate::{ objects::{Cycle, HalfEdge, Objects, Surface}, - partial::{util::merge_options, MaybePartial}, + partial::{ + util::merge_options, MaybePartial, PartialHalfEdge, PartialVertex, + }, storage::Handle, validate::ValidationError, }; @@ -56,7 +58,7 @@ impl PartialCycle { if let Some(surface) = surface { for half_edge in &mut self.half_edges { *half_edge = half_edge.clone().update_partial(|half_edge| { - half_edge.with_surface(Some(surface.clone())) + half_edge.with_surface(surface.clone()) }); } } @@ -84,63 +86,47 @@ impl PartialCycle { mut self, objects: &Objects, ) -> Result, ValidationError> { - let half_edges = { - let last_vertex = self - .half_edges - .last_mut() - .map(|half_edge| { - let vertex = half_edge.front(); - (half_edge, vertex) - }) - .map(|(half_edge, vertex)| { - let surface_vertex = vertex.surface_form(); - (half_edge, vertex, surface_vertex) - }) - .map(|(half_edge, vertex, surface_vertex)| - -> Result<_, ValidationError> - { - let surface_vertex = surface_vertex.into_full(objects)?; + // To create a cycle, we need to make sure that all its half-edges + // connect to each other. Let's start with all the connections between + // the first and the last half-edge. + let mut previous_vertex = None; + for half_edge in &mut self.half_edges { + let back_vertex = previous_vertex.unwrap_or_default(); + let front_vertex = + half_edge.front().surface_form().into_full(objects)?; - *half_edge = - half_edge.clone().update_partial(|half_edge| { - half_edge.with_front_vertex(Some( - vertex.update_partial(|vertex| { - vertex.with_surface_form(Some( - surface_vertex.clone(), - )) - }), - )) - }); + *half_edge = half_edge.clone().merge_with( + PartialHalfEdge::default() + .with_back_vertex( + PartialVertex::default().with_surface_form(back_vertex), + ) + .with_front_vertex( + PartialVertex::default() + .with_surface_form(front_vertex.clone()), + ), + ); - Ok(surface_vertex) - }) - .transpose()?; + previous_vertex = Some(MaybePartial::from(front_vertex)); + } - let (half_edges, _) = self.half_edges.into_iter().fold( - Ok((Vec::new(), last_vertex)), - |result: Result<_, ValidationError>, half_edge| { - let (mut half_edges, previous_vertex) = result?; + // We're not quite done yet. We need to close the cycle, by connecting + // the last half-edge back around to the first one. + if let Some(half_edge) = self.half_edges.first_mut() { + let back_vertex = previous_vertex.unwrap_or_default(); - let half_edge = half_edge - .update_partial(|half_edge| { - let [back, _] = half_edge.vertices(); - let back = back.update_partial(|partial| { - partial.with_surface_form(previous_vertex) - }); + *half_edge = half_edge.clone().merge_with( + PartialHalfEdge::default().with_back_vertex( + PartialVertex::default().with_surface_form(back_vertex), + ), + ); + } - half_edge.with_back_vertex(Some(back)) - }) - .into_full(objects)?; - - let front = half_edge.front().surface_form().clone(); - half_edges.push(half_edge); - - Ok((half_edges, Some(front))) - }, - )?; - - half_edges - }; + // All connections made! All that's left is to build the half-edges. + let mut half_edges = Vec::new(); + for half_edge in self.half_edges { + let half_edge = half_edge.into_full(objects)?; + half_edges.push(half_edge); + } Ok(objects.cycles.insert(Cycle::new(half_edges))?) } diff --git a/crates/fj-kernel/src/partial/objects/edge.rs b/crates/fj-kernel/src/partial/objects/edge.rs index 2aadf3bb4..7b5ffe3c9 100644 --- a/crates/fj-kernel/src/partial/objects/edge.rs +++ b/crates/fj-kernel/src/partial/objects/edge.rs @@ -47,82 +47,70 @@ impl PartialHalfEdge { } /// Update the partial half-edge with the given surface - pub fn with_surface(mut self, surface: Option>) -> Self { - if let Some(surface) = surface { - self.curve = self.curve.update_partial(|curve| { - curve.with_surface(Some(surface.clone())) - }); + pub fn with_surface(mut self, surface: Handle) -> Self { + self.curve = self + .curve + .update_partial(|curve| curve.with_surface(Some(surface.clone()))); - self.vertices = self.vertices.map(|vertex| { - vertex.update_partial(|vertex| { - let surface_form = vertex.surface_form().update_partial( - |surface_vertex| { - surface_vertex.with_surface(Some(surface.clone())) - }, - ); + self.vertices = self.vertices.map(|vertex| { + vertex.update_partial(|vertex| { + let surface_form = + vertex.surface_form().update_partial(|surface_vertex| { + surface_vertex.with_surface(Some(surface.clone())) + }); + + vertex.with_surface_form(surface_form) + }) + }); - vertex.with_surface_form(Some(surface_form)) - }) - }); - } self } /// Update the partial half-edge with the given curve - pub fn with_curve( - mut self, - curve: Option>>, - ) -> Self { - if let Some(curve) = curve { - self.curve = curve.into(); - } + pub fn with_curve(mut self, curve: impl Into>) -> Self { + self.curve = curve.into(); + self } /// Update the partial half-edge with the given back vertex pub fn with_back_vertex( mut self, - vertex: Option>>, + vertex: impl Into>, ) -> Self { - if let Some(vertex) = vertex { - let [from, _] = &mut self.vertices; - *from = vertex.into(); - } + let [from, _] = &mut self.vertices; + *from = vertex.into(); + self } /// Update the partial half-edge with the given front vertex pub fn with_front_vertex( mut self, - vertex: Option>>, + vertex: impl Into>, ) -> Self { - if let Some(vertex) = vertex { - let [_, to] = &mut self.vertices; - *to = vertex.into(); - } + let [_, to] = &mut self.vertices; + *to = vertex.into(); + self } /// Update the partial half-edge with the given vertices pub fn with_vertices( mut self, - vertices: Option<[impl Into>; 2]>, + vertices: [impl Into>; 2], ) -> Self { - let vertices = vertices.map(|vertices| vertices.map(Into::into)); - if let Some([back, front]) = vertices { - self.vertices = [back, front]; - } + self.vertices = vertices.map(Into::into); self } /// Update the partial half-edge with the given global form pub fn with_global_form( mut self, - global_form: Option>>, + global_form: impl Into>, ) -> Self { - if let Some(global_form) = global_form { - self.global_form = global_form.into(); - } + self.global_form = global_form.into(); + self } @@ -143,7 +131,7 @@ impl PartialHalfEdge { let curve = self.curve.into_full(objects)?; let vertices = self.vertices.try_map_ext(|vertex| { vertex - .update_partial(|vertex| vertex.with_curve(Some(curve.clone()))) + .update_partial(|vertex| vertex.with_curve(curve.clone())) .into_full(objects) })?; diff --git a/crates/fj-kernel/src/partial/objects/vertex.rs b/crates/fj-kernel/src/partial/objects/vertex.rs index b04a67b02..f3cd84539 100644 --- a/crates/fj-kernel/src/partial/objects/vertex.rs +++ b/crates/fj-kernel/src/partial/objects/vertex.rs @@ -46,24 +46,17 @@ impl PartialVertex { } /// Provide a curve for the partial vertex - pub fn with_curve( - mut self, - curve: Option>>, - ) -> Self { - if let Some(curve) = curve { - self.curve = curve.into(); - } + pub fn with_curve(mut self, curve: impl Into>) -> Self { + self.curve = curve.into(); self } /// Provide a surface form for the partial vertex pub fn with_surface_form( mut self, - surface_form: Option>>, + surface_form: impl Into>, ) -> Self { - if let Some(surface_form) = surface_form { - self.surface_form = surface_form.into(); - } + self.surface_form = surface_form.into(); self } diff --git a/crates/fj-kernel/src/validate/edge.rs b/crates/fj-kernel/src/validate/edge.rs index ffc50c29f..2babcdf94 100644 --- a/crates/fj-kernel/src/validate/edge.rs +++ b/crates/fj-kernel/src/validate/edge.rs @@ -217,7 +217,7 @@ mod tests { vertices[1] = vertices[1] .to_partial() // Arranging for an equal but not identical curve here. - .with_curve(Some(valid.curve().to_partial())) + .with_curve(valid.curve().to_partial()) .build(&objects)?; HalfEdge::new(vertices, valid.global_form().clone()) diff --git a/crates/fj-kernel/src/validate/vertex.rs b/crates/fj-kernel/src/validate/vertex.rs index 075c57cf1..3055f88fa 100644 --- a/crates/fj-kernel/src/validate/vertex.rs +++ b/crates/fj-kernel/src/validate/vertex.rs @@ -191,11 +191,11 @@ mod tests { let valid = Vertex::partial() .with_position(Some([0.])) - .with_curve(Some( + .with_curve( Curve::partial() .with_surface(Some(objects.surfaces.xy_plane())) .update_as_u_axis(), - )) + ) .build(&objects)?; let invalid = Vertex::new( valid.position(), @@ -219,11 +219,11 @@ mod tests { let valid = Vertex::partial() .with_position(Some([0.])) - .with_curve(Some( + .with_curve( Curve::partial() .with_surface(Some(objects.surfaces.xy_plane())) .update_as_u_axis(), - )) + ) .build(&objects)?; let invalid = Vertex::new( valid.position(), diff --git a/crates/fj-operations/src/sketch.rs b/crates/fj-operations/src/sketch.rs index 0250d1184..8e838ec2b 100644 --- a/crates/fj-operations/src/sketch.rs +++ b/crates/fj-operations/src/sketch.rs @@ -28,7 +28,7 @@ impl Shape for fj::Sketch { // none need to be added here. let half_edge = HalfEdge::partial() - .with_surface(Some(surface)) + .with_surface(surface) .update_as_circle_from_radius(circle.radius(), objects)? .build(objects)?; let cycle = objects.cycles.insert(Cycle::new([half_edge]))?;