diff --git a/crates/fj-kernel/src/algorithms/sweep/edge.rs b/crates/fj-kernel/src/algorithms/sweep/edge.rs index 3d1489d24..574ead631 100644 --- a/crates/fj-kernel/src/algorithms/sweep/edge.rs +++ b/crates/fj-kernel/src/algorithms/sweep/edge.rs @@ -200,7 +200,7 @@ mod tests { builder::HalfEdgeBuilder, insert::Insert, objects::{Cycle, Face, HalfEdge, Objects}, - partial::{HasPartial, PartialSurfaceVertex, PartialVertex}, + partial::{HasPartial, PartialSurfaceVertex, PartialVertex, Replace}, }; #[test] @@ -228,26 +228,34 @@ mod tests { ) .build(&objects)? .insert(&objects)?; - let side_up = HalfEdge::partial() - .with_surface(surface.clone()) - .with_back_vertex(PartialVertex { - surface_form: bottom.front().surface_form().clone().into(), - ..Default::default() - }) - .with_front_vertex(PartialVertex { - surface_form: PartialSurfaceVertex { - position: Some([1., 1.].into()), + let side_up = { + let mut side_up = HalfEdge::partial(); + side_up.replace(surface.clone()); + side_up + .with_back_vertex(PartialVertex { + surface_form: bottom + .front() + .surface_form() + .clone() + .into(), ..Default::default() - } - .into(), - ..Default::default() - }) - .update_as_line_segment() - .build(&objects)? - .insert(&objects)?; - let top = HalfEdge::partial() - .with_surface(surface.clone()) - .with_back_vertex(PartialVertex { + }) + .with_front_vertex(PartialVertex { + surface_form: PartialSurfaceVertex { + position: Some([1., 1.].into()), + ..Default::default() + } + .into(), + ..Default::default() + }) + .update_as_line_segment() + .build(&objects)? + .insert(&objects)? + }; + let top = { + let mut top = HalfEdge::partial(); + top.replace(surface.clone()); + top.with_back_vertex(PartialVertex { surface_form: PartialSurfaceVertex { position: Some([0., 1.].into()), ..Default::default() @@ -262,21 +270,29 @@ mod tests { .update_as_line_segment() .build(&objects)? .insert(&objects)? - .reverse(&objects)?; - let side_down = HalfEdge::partial() - .with_surface(surface) - .with_back_vertex(PartialVertex { - surface_form: bottom.back().surface_form().clone().into(), - ..Default::default() - }) - .with_front_vertex(PartialVertex { - surface_form: top.front().surface_form().clone().into(), - ..Default::default() - }) - .update_as_line_segment() - .build(&objects)? - .insert(&objects)? - .reverse(&objects)?; + .reverse(&objects)? + }; + let side_down = { + let mut side_down = HalfEdge::partial(); + side_down.replace(surface); + side_down + .with_back_vertex(PartialVertex { + surface_form: bottom + .back() + .surface_form() + .clone() + .into(), + ..Default::default() + }) + .with_front_vertex(PartialVertex { + surface_form: top.front().surface_form().clone().into(), + ..Default::default() + }) + .update_as_line_segment() + .build(&objects)? + .insert(&objects)? + .reverse(&objects)? + }; let cycle = objects .cycles diff --git a/crates/fj-kernel/src/builder/edge.rs b/crates/fj-kernel/src/builder/edge.rs index f336ed587..ad24ac9b2 100644 --- a/crates/fj-kernel/src/builder/edge.rs +++ b/crates/fj-kernel/src/builder/edge.rs @@ -6,7 +6,7 @@ use crate::{ objects::{Curve, Objects, Surface, Vertex, VerticesInNormalizedOrder}, partial::{ MaybePartial, MergeWith, PartialGlobalEdge, PartialHalfEdge, - PartialSurfaceVertex, PartialVertex, + PartialSurfaceVertex, PartialVertex, Replace, }, storage::Handle, validate::ValidationError, @@ -94,7 +94,7 @@ impl HalfEdgeBuilder for PartialHalfEdge { } fn update_as_line_segment_from_points( - self, + mut self, surface: Handle, points: [impl Into>; 2], ) -> Self { @@ -111,9 +111,8 @@ impl HalfEdgeBuilder for PartialHalfEdge { } }); - self.with_surface(surface) - .with_vertices(vertices) - .update_as_line_segment() + self.replace(surface); + self.with_vertices(vertices).update_as_line_segment() } fn update_as_line_segment(self) -> Self { diff --git a/crates/fj-kernel/src/partial/maybe_partial.rs b/crates/fj-kernel/src/partial/maybe_partial.rs index dc5c32108..3c1b71c69 100644 --- a/crates/fj-kernel/src/partial/maybe_partial.rs +++ b/crates/fj-kernel/src/partial/maybe_partial.rs @@ -2,6 +2,7 @@ use fj_math::Point; use crate::{ geometry::{path::SurfacePath, surface::SurfaceGeometry}, + get::Get, insert::Insert, objects::{ Curve, GlobalCurve, GlobalEdge, GlobalVertex, HalfEdge, Objects, @@ -11,7 +12,7 @@ use crate::{ validate::{Validate, ValidationError}, }; -use super::{HasPartial, MergeWith, Partial}; +use super::{HasPartial, MergeWith, Partial, Replace}; /// Can be used everywhere either a partial or full objects are accepted /// @@ -125,6 +126,29 @@ where } } +impl Replace for MaybePartial +where + T: HasPartial + Get, + T::Partial: Replace, +{ + fn replace(&mut self, object: Handle) -> &mut Self { + match self { + Self::Full(full) => { + if full.get().id() != object.id() { + let mut partial = full.to_partial(); + partial.replace(object); + *self = Self::Partial(partial); + } + } + Self::Partial(partial) => { + partial.replace(object); + } + } + + self + } +} + impl From> for MaybePartial where T: HasPartial, diff --git a/crates/fj-kernel/src/partial/mod.rs b/crates/fj-kernel/src/partial/mod.rs index 19289522b..d9b89d44b 100644 --- a/crates/fj-kernel/src/partial/mod.rs +++ b/crates/fj-kernel/src/partial/mod.rs @@ -37,6 +37,7 @@ mod maybe_partial; mod merge; mod objects; +mod replace; mod traits; pub use self::{ @@ -50,5 +51,6 @@ pub use self::{ surface::PartialSurface, vertex::{PartialGlobalVertex, PartialSurfaceVertex, PartialVertex}, }, + replace::Replace, traits::{HasPartial, Partial}, }; diff --git a/crates/fj-kernel/src/partial/objects/curve.rs b/crates/fj-kernel/src/partial/objects/curve.rs index 0608dbd2e..a1d4cea00 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}, + partial::{MaybePartial, MergeWith, Replace}, storage::Handle, validate::ValidationError, }; @@ -46,6 +46,13 @@ impl MergeWith for PartialCurve { } } +impl Replace for PartialCurve { + fn replace(&mut self, surface: Handle) -> &mut Self { + self.surface = Some(surface); + self + } +} + impl From<&Curve> for PartialCurve { fn from(curve: &Curve) -> Self { Self { diff --git a/crates/fj-kernel/src/partial/objects/cycle.rs b/crates/fj-kernel/src/partial/objects/cycle.rs index eedf39ff8..e3fd458a3 100644 --- a/crates/fj-kernel/src/partial/objects/cycle.rs +++ b/crates/fj-kernel/src/partial/objects/cycle.rs @@ -1,7 +1,9 @@ use crate::{ builder::HalfEdgeBuilder, objects::{Cycle, HalfEdge, Objects, Surface}, - partial::{MaybePartial, MergeWith, PartialHalfEdge, PartialVertex}, + partial::{ + MaybePartial, MergeWith, PartialHalfEdge, PartialVertex, Replace, + }, storage::Handle, validate::ValidationError, }; @@ -56,9 +58,11 @@ impl PartialCycle { pub fn with_surface(mut self, surface: Option>) -> Self { 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(surface.clone()) - }); + *half_edge = + half_edge.clone().update_partial(|mut half_edge| { + half_edge.replace(surface.clone()); + half_edge + }); } } self diff --git a/crates/fj-kernel/src/partial/objects/edge.rs b/crates/fj-kernel/src/partial/objects/edge.rs index 6a44d916d..50633d4be 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, PartialCurve, PartialVertex}, + partial::{MaybePartial, MergeWith, PartialCurve, PartialVertex, Replace}, storage::Handle, validate::ValidationError, }; @@ -27,30 +27,6 @@ pub struct PartialHalfEdge { } 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| { - curve.surface = Some(surface.clone()); - curve - }); - - self.vertices = self.vertices.map(|vertex| { - vertex.update_partial(|mut vertex| { - let surface_form = vertex.surface_form.clone().update_partial( - |mut surface_vertex| { - surface_vertex.surface = Some(surface.clone()); - surface_vertex - }, - ); - - vertex.surface_form = surface_form; - vertex - }) - }); - - self - } - /// Update the partial half-edge with the given curve pub fn with_curve(mut self, curve: impl Into>) -> Self { self.curve = curve.into(); @@ -127,6 +103,18 @@ impl MergeWith for PartialHalfEdge { } } +impl Replace for PartialHalfEdge { + fn replace(&mut self, surface: Handle) -> &mut Self { + self.curve.replace(surface.clone()); + + for vertex in &mut self.vertices { + vertex.replace(surface.clone()); + } + + self + } +} + impl From<&HalfEdge> for PartialHalfEdge { fn from(half_edge: &HalfEdge) -> Self { let [back_vertex, front_vertex] = diff --git a/crates/fj-kernel/src/partial/objects/vertex.rs b/crates/fj-kernel/src/partial/objects/vertex.rs index 75b6c7539..418917287 100644 --- a/crates/fj-kernel/src/partial/objects/vertex.rs +++ b/crates/fj-kernel/src/partial/objects/vertex.rs @@ -3,7 +3,7 @@ use fj_math::Point; use crate::{ builder::GlobalVertexBuilder, objects::{Curve, GlobalVertex, Objects, Surface, SurfaceVertex, Vertex}, - partial::{MaybePartial, MergeWith}, + partial::{MaybePartial, MergeWith, Replace}, storage::Handle, validate::ValidationError, }; @@ -67,6 +67,13 @@ impl MergeWith for PartialVertex { } } +impl Replace for PartialVertex { + fn replace(&mut self, surface: Handle) -> &mut Self { + self.surface_form.replace(surface); + self + } +} + impl From<&Vertex> for PartialVertex { fn from(vertex: &Vertex) -> Self { Self { @@ -129,6 +136,13 @@ impl MergeWith for PartialSurfaceVertex { } } +impl Replace for PartialSurfaceVertex { + fn replace(&mut self, surface: Handle) -> &mut Self { + self.surface = Some(surface); + self + } +} + impl From<&SurfaceVertex> for PartialSurfaceVertex { fn from(surface_vertex: &SurfaceVertex) -> Self { Self { diff --git a/crates/fj-kernel/src/partial/replace.rs b/crates/fj-kernel/src/partial/replace.rs new file mode 100644 index 000000000..180729979 --- /dev/null +++ b/crates/fj-kernel/src/partial/replace.rs @@ -0,0 +1,20 @@ +use crate::storage::Handle; + +/// Recursively replace a (partial) object referenced by another partial object +pub trait Replace { + /// Recursively replace the referenced object + fn replace(&mut self, object: Handle) -> &mut Self; +} + +impl Replace for [R; N] +where + R: Replace, +{ + fn replace(&mut self, object: Handle) -> &mut Self { + for item in self.iter_mut() { + item.replace(object.clone()); + } + + self + } +} diff --git a/crates/fj-operations/src/sketch.rs b/crates/fj-operations/src/sketch.rs index 90e596d2f..377c79f7c 100644 --- a/crates/fj-operations/src/sketch.rs +++ b/crates/fj-operations/src/sketch.rs @@ -5,7 +5,7 @@ use fj_kernel::{ builder::{FaceBuilder, HalfEdgeBuilder}, insert::Insert, objects::{Cycle, Face, HalfEdge, Objects, Sketch}, - partial::HasPartial, + partial::{HasPartial, Replace}, validate::ValidationError, }; use fj_math::{Aabb, Point}; @@ -27,11 +27,14 @@ impl Shape for fj::Sketch { // Circles have just a single round edge with no vertices. So // none need to be added here. - let half_edge = HalfEdge::partial() - .with_surface(surface) - .update_as_circle_from_radius(circle.radius(), objects)? - .build(objects)? - .insert(objects)?; + let half_edge = { + let mut half_edge = HalfEdge::partial(); + half_edge.replace(surface); + half_edge + .update_as_circle_from_radius(circle.radius(), objects)? + .build(objects)? + .insert(objects)? + }; let cycle = objects.cycles.insert(Cycle::new([half_edge]))?; Face::partial()