diff --git a/crates/fj-kernel/src/algorithms/transform/curve.rs b/crates/fj-kernel/src/algorithms/transform/curve.rs index a89192b7f..6b46215c5 100644 --- a/crates/fj-kernel/src/algorithms/transform/curve.rs +++ b/crates/fj-kernel/src/algorithms/transform/curve.rs @@ -32,10 +32,7 @@ impl TransformObject for PartialCurve { .surface .map(|surface| surface.transform(transform, objects)) .transpose()?; - let global_form = self - .global_form - .map(|global_form| global_form.transform(transform, objects)) - .transpose()?; + let global_form = self.global_form.transform(transform, objects)?; // Don't need to transform `self.path`, as that's defined in surface // coordinates, and thus transforming `surface` takes care of it. diff --git a/crates/fj-kernel/src/algorithms/transform/edge.rs b/crates/fj-kernel/src/algorithms/transform/edge.rs index 7daf35f31..27d26e8d8 100644 --- a/crates/fj-kernel/src/algorithms/transform/edge.rs +++ b/crates/fj-kernel/src/algorithms/transform/edge.rs @@ -16,11 +16,11 @@ impl TransformObject for PartialHalfEdge { objects: &Objects, ) -> Result { let curve: MaybePartial<_> = self - .curve() + .curve .into_partial() .transform(transform, objects)? .into(); - let vertices = self.vertices().try_map_ext( + let vertices = self.vertices.try_map_ext( |vertex| -> Result<_, ValidationError> { let mut vertex = vertex.into_partial().transform(transform, objects)?; @@ -28,11 +28,11 @@ impl TransformObject for PartialHalfEdge { Ok(vertex) }, )?; - let global_form = self - .global_form() + let mut global_form = self + .global_form .into_partial() - .transform(transform, objects)? - .with_curve(curve.global_form()); + .transform(transform, objects)?; + global_form.curve = curve.global_form(); Ok(Self::default() .with_curve(curve) @@ -47,18 +47,13 @@ impl TransformObject for PartialGlobalEdge { transform: &Transform, objects: &Objects, ) -> Result { - let curve = self.curve().transform(transform, objects)?; - let vertices = self - .vertices() - .map(|vertices| { - vertices.try_map_ext(|vertex| -> Result<_, ValidationError> { - vertex.transform(transform, objects) - }) - }) - .transpose()?; + let curve = self.curve.transform(transform, objects)?; + let vertices = self.vertices.try_map_ext( + |vertex| -> Result<_, ValidationError> { + vertex.transform(transform, objects) + }, + )?; - Ok(Self::default() - .with_curve(Some(curve)) - .with_vertices(vertices)) + Ok(Self { curve, vertices }) } } diff --git a/crates/fj-kernel/src/builder/edge.rs b/crates/fj-kernel/src/builder/edge.rs index 3d276c505..f336ed587 100644 --- a/crates/fj-kernel/src/builder/edge.rs +++ b/crates/fj-kernel/src/builder/edge.rs @@ -5,15 +5,14 @@ use crate::{ insert::Insert, objects::{Curve, Objects, Surface, Vertex, VerticesInNormalizedOrder}, partial::{ - MaybePartial, MergeWith, PartialCurve, PartialGlobalEdge, - PartialGlobalVertex, PartialHalfEdge, PartialSurfaceVertex, - PartialVertex, + MaybePartial, MergeWith, PartialGlobalEdge, PartialHalfEdge, + PartialSurfaceVertex, PartialVertex, }, storage::Handle, validate::ValidationError, }; -use super::{CurveBuilder, GlobalVertexBuilder}; +use super::CurveBuilder; /// Builder API for [`PartialHalfEdge`] pub trait HalfEdgeBuilder: Sized { @@ -52,12 +51,12 @@ pub trait HalfEdgeBuilder: Sized { impl HalfEdgeBuilder for PartialHalfEdge { fn with_back_vertex(self, back: impl Into>) -> Self { - let [_, front] = self.vertices(); + let [_, front] = self.vertices.clone(); self.with_vertices([back.into(), front]) } fn with_front_vertex(self, front: impl Into>) -> Self { - let [back, _] = self.vertices(); + let [back, _] = self.vertices.clone(); self.with_vertices([back, front.into()]) } @@ -66,8 +65,7 @@ impl HalfEdgeBuilder for PartialHalfEdge { radius: impl Into, objects: &Objects, ) -> Result { - let mut curve = self.curve().into_partial(); - curve.global_form = Some(self.extract_global_curve()); + let mut curve = self.curve.clone().into_partial(); curve.update_as_circle_from_radius(radius); let path = curve.path.expect("Expected path that was just created"); @@ -75,17 +73,7 @@ impl HalfEdgeBuilder for PartialHalfEdge { let [a_curve, b_curve] = [Scalar::ZERO, Scalar::TAU].map(|coord| Point::from([coord])); - let global_vertex = self - .global_form() - .vertices() - .map(|[global_form, _]| global_form) - .unwrap_or_else(|| { - PartialGlobalVertex::from_curve_and_position( - curve.clone(), - a_curve, - ) - .into() - }); + let [global_vertex, _] = self.global_form.vertices(); let surface_vertex = PartialSurfaceVertex { position: Some(path.point_from_path_coords(a_curve)), @@ -129,12 +117,12 @@ impl HalfEdgeBuilder for PartialHalfEdge { } fn update_as_line_segment(self) -> Self { - let [from, to] = self.vertices(); + let [from, to] = self.vertices.clone(); let [from_surface, to_surface] = [&from, &to].map(|vertex| vertex.surface_form()); let surface = self - .curve() + .curve .surface() .merge_with(from_surface.surface()) .merge_with(to_surface.surface()) @@ -145,11 +133,8 @@ impl HalfEdgeBuilder for PartialHalfEdge { .expect("Can't infer line segment without surface position") }); - let mut curve = PartialCurve { - surface: Some(surface), - global_form: Some(self.extract_global_curve()), - ..Default::default() - }; + let mut curve = self.curve.clone().into_partial(); + curve.surface = Some(surface); curve.update_as_line_from_points(points); let [back, front] = { @@ -181,19 +166,12 @@ impl HalfEdgeBuilder for PartialHalfEdge { must_switch_order }; - self.global_form() - .vertices() - .map( - |[a, b]| { - if must_switch_order { - [b, a] - } else { - [a, b] - } - }, - ) - .map(|[a, b]| [Some(a), Some(b)]) - .unwrap_or([None, None]) + let [a, b] = self.global_form.vertices(); + if must_switch_order { + [b, a] + } else { + [a, b] + } }; vertices @@ -202,14 +180,12 @@ impl HalfEdgeBuilder for PartialHalfEdge { .collect::<[_; 2]>() .map(|(vertex, global_form)| { vertex.update_partial(|mut vertex| { - vertex.surface_form = vertex - .surface_form - .update_partial(|mut surface_vertex| { - if let Some(global_form) = global_form { - surface_vertex.global_form = global_form; - } - surface_vertex - }); + vertex.surface_form = vertex.surface_form.merge_with( + PartialSurfaceVertex { + global_form, + ..Default::default() + }, + ); vertex }) }) @@ -235,13 +211,14 @@ pub trait GlobalEdgeBuilder { impl GlobalEdgeBuilder for PartialGlobalEdge { fn update_from_curve_and_vertices( - self, + mut self, curve: &Curve, vertices: &[Handle; 2], ) -> Self { - self.with_curve(Some(curve.global_form().clone())) - .with_vertices(Some( - vertices.clone().map(|vertex| vertex.global_form().clone()), - )) + self.curve = curve.global_form().clone().into(); + self.vertices = vertices + .clone() + .map(|vertex| vertex.global_form().clone().into()); + self } } diff --git a/crates/fj-kernel/src/builder/shell.rs b/crates/fj-kernel/src/builder/shell.rs index 838295820..ad575271c 100644 --- a/crates/fj-kernel/src/builder/shell.rs +++ b/crates/fj-kernel/src/builder/shell.rs @@ -161,13 +161,11 @@ impl<'a> ShellBuilder<'a> { }; let curve = PartialCurve { - global_form: Some( - side_up_prev - .curve() - .global_form() - .clone() - .into(), - ), + global_form: side_up_prev + .curve() + .global_form() + .clone() + .into(), ..Default::default() }; diff --git a/crates/fj-kernel/src/partial/maybe_partial.rs b/crates/fj-kernel/src/partial/maybe_partial.rs index cad49c181..dc5c32108 100644 --- a/crates/fj-kernel/src/partial/maybe_partial.rs +++ b/crates/fj-kernel/src/partial/maybe_partial.rs @@ -155,9 +155,9 @@ impl MaybePartial { } /// Access the global form - pub fn global_form(&self) -> Option> { + pub fn global_form(&self) -> MaybePartial { match self { - Self::Full(full) => Some(full.global_form().clone().into()), + Self::Full(full) => full.global_form().clone().into(), Self::Partial(partial) => partial.global_form.clone(), } } @@ -168,17 +168,17 @@ impl MaybePartial { pub fn curve(&self) -> MaybePartial { match self { Self::Full(full) => full.curve().clone().into(), - Self::Partial(partial) => partial.curve(), + Self::Partial(partial) => partial.curve.clone(), } } /// Access the vertices - pub fn vertices(&self) -> Option<[MaybePartial; 2]> { + pub fn vertices(&self) -> [MaybePartial; 2] { match self { - Self::Full(full) => Some( - full.vertices().access_in_normalized_order().map(Into::into), - ), - Self::Partial(partial) => partial.vertices(), + Self::Full(full) => { + full.vertices().access_in_normalized_order().map(Into::into) + } + Self::Partial(partial) => partial.vertices.clone(), } } } @@ -188,7 +188,7 @@ impl MaybePartial { pub fn curve(&self) -> MaybePartial { match self { Self::Full(full) => full.curve().clone().into(), - Self::Partial(partial) => partial.curve(), + Self::Partial(partial) => partial.curve.clone(), } } @@ -197,7 +197,7 @@ impl MaybePartial { match self { Self::Full(full) => full.front().clone().into(), Self::Partial(partial) => { - let [_, front] = &partial.vertices(); + let [_, front] = &partial.vertices; front.clone() } } @@ -207,7 +207,7 @@ impl MaybePartial { pub fn vertices(&self) -> [MaybePartial; 2] { match self { Self::Full(full) => full.vertices().clone().map(Into::into), - Self::Partial(partial) => partial.vertices(), + Self::Partial(partial) => partial.vertices.clone(), } } } diff --git a/crates/fj-kernel/src/partial/objects/curve.rs b/crates/fj-kernel/src/partial/objects/curve.rs index a82a7af2f..0608dbd2e 100644 --- a/crates/fj-kernel/src/partial/objects/curve.rs +++ b/crates/fj-kernel/src/partial/objects/curve.rs @@ -1,7 +1,7 @@ use crate::{ geometry::path::SurfacePath, objects::{Curve, GlobalCurve, Objects, Surface}, - partial::{MaybePartial, MergeWith, Mergeable}, + partial::{MaybePartial, MergeWith}, storage::Handle, validate::ValidationError, }; @@ -18,13 +18,7 @@ pub struct PartialCurve { pub surface: Option>, /// The global form of the [`Curve`] - /// - /// # Implementation Note - /// - /// This can in principle be simplified to just `MaybePartial>, + pub global_form: MaybePartial, } impl PartialCurve { @@ -34,11 +28,7 @@ impl PartialCurve { let surface = self.surface.expect("Can't build `Curve` without surface"); - let global_form = match self.global_form { - Some(global_form) => global_form, - None => objects.global_curves.insert(GlobalCurve)?.into(), - } - .into_full(objects)?; + let global_form = self.global_form.into_full(objects)?; Ok(Curve::new(surface, path, global_form)) } @@ -51,9 +41,7 @@ impl MergeWith for PartialCurve { Self { path: self.path.merge_with(other.path), surface: self.surface.merge_with(other.surface), - global_form: Mergeable(self.global_form) - .merge_with(Mergeable(other.global_form)) - .0, + global_form: self.global_form.merge_with(other.global_form), } } } @@ -63,7 +51,7 @@ impl From<&Curve> for PartialCurve { Self { path: Some(curve.path()), surface: Some(curve.surface().clone()), - global_form: Some(curve.global_form().clone().into()), + global_form: curve.global_form().clone().into(), } } } diff --git a/crates/fj-kernel/src/partial/objects/edge.rs b/crates/fj-kernel/src/partial/objects/edge.rs index cbace6209..6a44d916d 100644 --- a/crates/fj-kernel/src/partial/objects/edge.rs +++ b/crates/fj-kernel/src/partial/objects/edge.rs @@ -6,7 +6,7 @@ use crate::{ Curve, GlobalCurve, GlobalEdge, GlobalVertex, HalfEdge, Objects, Surface, Vertex, }, - partial::{MaybePartial, MergeWith, Mergeable}, + partial::{MaybePartial, MergeWith, PartialCurve, PartialVertex}, storage::Handle, validate::ValidationError, }; @@ -16,36 +16,17 @@ use crate::{ /// See [`crate::partial`] for more information. #[derive(Clone, Debug, Default)] pub struct PartialHalfEdge { - curve: MaybePartial, - vertices: [MaybePartial; 2], - global_form: MaybePartial, -} - -impl PartialHalfEdge { - /// Access the curve that the [`HalfEdge`] is defined in - pub fn curve(&self) -> MaybePartial { - self.curve.clone() - } - - /// Access the vertices that bound this [`HalfEdge`] in the [`Curve`] - pub fn vertices(&self) -> [MaybePartial; 2] { - self.vertices.clone() - } + /// The curve that the [`HalfEdge`] is defined in + pub curve: MaybePartial, - /// Access the global form of the [`HalfEdge`] - pub fn global_form(&self) -> MaybePartial { - self.global_form.clone() - } + /// The vertices that bound the [`HalfEdge`] in the curve + pub vertices: [MaybePartial; 2], - /// Extract the global curve from either the curve or global form - /// - /// If a global curve is available through both, the curve is preferred. - pub fn extract_global_curve(&self) -> MaybePartial { - self.curve - .global_form() - .unwrap_or_else(|| self.global_form.curve()) - } + /// The global form of the [`HalfEdge`] + pub global_form: MaybePartial, +} +impl PartialHalfEdge { /// Update the partial half-edge with the given surface pub fn with_surface(mut self, surface: Handle) -> Self { self.curve = self.curve.update_partial(|mut curve| { @@ -97,13 +78,28 @@ impl PartialHalfEdge { } /// Build a full [`HalfEdge`] from the partial half-edge - pub fn build(self, objects: &Objects) -> Result { - let curve = self.curve.into_full(objects)?; + pub fn build( + mut self, + objects: &Objects, + ) -> Result { + let global_curve = self + .curve + .global_form() + .merge_with(self.global_form.curve()); + + let curve = { + self.curve = self.curve.merge_with(PartialCurve { + global_form: global_curve, + ..Default::default() + }); + + self.curve.into_full(objects)? + }; let vertices = self.vertices.try_map_ext(|vertex| { vertex - .update_partial(|mut vertex| { - vertex.curve = curve.clone().into(); - vertex + .merge_with(PartialVertex { + curve: curve.clone().into(), + ..Default::default() }) .into_full(objects) })?; @@ -149,43 +145,14 @@ impl From<&HalfEdge> for PartialHalfEdge { /// See [`crate::partial`] for more information. #[derive(Clone, Debug, Default)] pub struct PartialGlobalEdge { - curve: MaybePartial, - vertices: Option<[MaybePartial; 2]>, + /// The curve that the [`GlobalEdge`] is defined in + pub curve: MaybePartial, + + /// The vertices that bound the [`GlobalEdge`] in the curve + pub vertices: [MaybePartial; 2], } impl PartialGlobalEdge { - /// Access the curve that the [`GlobalEdge`] is defined in - pub fn curve(&self) -> MaybePartial { - self.curve.clone() - } - - /// Access the vertices that bound the [`GlobalEdge`] in the curve - pub fn vertices(&self) -> Option<[MaybePartial; 2]> { - self.vertices.clone() - } - - /// Update the partial global edge with the given curve - pub fn with_curve( - mut self, - curve: Option>>, - ) -> Self { - if let Some(curve) = curve { - self.curve = curve.into(); - } - self - } - - /// Update the partial global edge with the given vertices - pub fn with_vertices( - mut self, - vertices: Option<[impl Into>; 2]>, - ) -> Self { - if let Some(vertices) = vertices { - self.vertices = Some(vertices.map(Into::into)); - } - self - } - /// Build a full [`GlobalEdge`] from the partial global edge pub fn build( self, @@ -194,7 +161,6 @@ impl PartialGlobalEdge { let curve = self.curve.into_full(objects)?; let vertices = self .vertices - .expect("Can't build `GlobalEdge` without vertices") .try_map_ext(|global_vertex| global_vertex.into_full(objects))?; Ok(GlobalEdge::new(curve, vertices)) @@ -207,9 +173,7 @@ impl MergeWith for PartialGlobalEdge { Self { curve: self.curve.merge_with(other.curve), - vertices: Mergeable(self.vertices) - .merge_with(Mergeable(other.vertices)) - .0, + vertices: self.vertices.merge_with(other.vertices), } } } @@ -218,12 +182,10 @@ impl From<&GlobalEdge> for PartialGlobalEdge { fn from(global_edge: &GlobalEdge) -> Self { Self { curve: global_edge.curve().clone().into(), - vertices: Some( - global_edge - .vertices() - .access_in_normalized_order() - .map(Into::into), - ), + vertices: global_edge + .vertices() + .access_in_normalized_order() + .map(Into::into), } } } diff --git a/crates/fj-kernel/src/validate/cycle.rs b/crates/fj-kernel/src/validate/cycle.rs index b30ddaa9a..413953b54 100644 --- a/crates/fj-kernel/src/validate/cycle.rs +++ b/crates/fj-kernel/src/validate/cycle.rs @@ -91,7 +91,7 @@ mod tests { .collect::>(); let first_half_edge = &mut half_edges[0]; - let [first_vertex, _] = first_half_edge.vertices(); + let [first_vertex, _] = first_half_edge.vertices.clone(); // Sever connection between the last and first half-edge in the // cycle. diff --git a/crates/fj-kernel/src/validate/edge.rs b/crates/fj-kernel/src/validate/edge.rs index 0a294d415..54ee9ae74 100644 --- a/crates/fj-kernel/src/validate/edge.rs +++ b/crates/fj-kernel/src/validate/edge.rs @@ -244,15 +244,11 @@ mod tests { [[0., 0.], [1., 0.]], ) .build(&objects)?; - let invalid = HalfEdge::new( - valid.vertices().clone(), - valid - .global_form() - .to_partial() - .with_curve(Some(objects.global_curves.insert(GlobalCurve)?)) - .build(&objects)? - .insert(&objects)?, - ); + let invalid = HalfEdge::new(valid.vertices().clone(), { + let mut tmp = valid.global_form().to_partial(); + tmp.curve = objects.global_curves.insert(GlobalCurve)?.into(); + tmp.build(&objects)?.insert(&objects)? + }); assert!(valid.validate().is_ok()); assert!(invalid.validate().is_err()); @@ -270,22 +266,16 @@ mod tests { [[0., 0.], [1., 0.]], ) .build(&objects)?; - let invalid = HalfEdge::new( - valid.vertices().clone(), - valid + let invalid = HalfEdge::new(valid.vertices().clone(), { + let mut tmp = valid.global_form().to_partial(); + tmp.vertices = valid .global_form() - .to_partial() - .with_vertices(Some( - valid - .global_form() - .vertices() - .access_in_normalized_order() - // Creating equal but not identical vertices here. - .map(|vertex| vertex.to_partial()), - )) - .build(&objects)? - .insert(&objects)?, - ); + .vertices() + .access_in_normalized_order() + // Creating equal but not identical vertices here. + .map(|vertex| vertex.to_partial().into()); + tmp.build(&objects)?.insert(&objects)? + }); assert!(valid.validate().is_ok()); assert!(invalid.validate().is_err());