diff --git a/crates/fj-kernel/src/algorithms/approx/curve.rs b/crates/fj-kernel/src/algorithms/approx/curve.rs index fc6e15e19..eb32b1010 100644 --- a/crates/fj-kernel/src/algorithms/approx/curve.rs +++ b/crates/fj-kernel/src/algorithms/approx/curve.rs @@ -203,7 +203,7 @@ mod tests { builder::{CurveBuilder, SurfaceBuilder}, geometry::path::GlobalPath, insert::Insert, - partial2::{Partial, PartialCurve, PartialObject, PartialSurface}, + partial::{Partial, PartialCurve, PartialObject, PartialSurface}, services::Services, }; diff --git a/crates/fj-kernel/src/algorithms/intersect/curve_edge.rs b/crates/fj-kernel/src/algorithms/intersect/curve_edge.rs index 80fe5905c..d59f5ae66 100644 --- a/crates/fj-kernel/src/algorithms/intersect/curve_edge.rs +++ b/crates/fj-kernel/src/algorithms/intersect/curve_edge.rs @@ -80,8 +80,10 @@ mod tests { use crate::{ builder::{CurveBuilder, HalfEdgeBuilder}, objects::Vertex, - partial::PartialHalfEdge, - partial2::{Partial, PartialCurve, PartialGlobalEdge, PartialObject}, + partial::{ + Partial, PartialCurve, PartialGlobalEdge, PartialHalfEdge, + PartialObject, + }, services::Services, }; diff --git a/crates/fj-kernel/src/algorithms/intersect/curve_face.rs b/crates/fj-kernel/src/algorithms/intersect/curve_face.rs index 547b5441e..a702b6035 100644 --- a/crates/fj-kernel/src/algorithms/intersect/curve_face.rs +++ b/crates/fj-kernel/src/algorithms/intersect/curve_face.rs @@ -151,9 +151,7 @@ where mod tests { use crate::{ builder::{CurveBuilder, FaceBuilder}, - objects::Face, - partial::HasPartial, - partial2::{Partial, PartialCurve, PartialObject}, + partial::{Partial, PartialCurve, PartialFace, PartialObject}, services::Services, }; @@ -187,7 +185,7 @@ mod tests { [ 1., -1.], ]; - let face = Face::partial() + let face = PartialFace::default() .with_exterior_polygon_from_points(surface.clone(), exterior) .with_interior_polygon_from_points(surface, interior) .build(&mut services.objects); diff --git a/crates/fj-kernel/src/algorithms/intersect/face_face.rs b/crates/fj-kernel/src/algorithms/intersect/face_face.rs index 16ed60176..247eb0b1b 100644 --- a/crates/fj-kernel/src/algorithms/intersect/face_face.rs +++ b/crates/fj-kernel/src/algorithms/intersect/face_face.rs @@ -71,9 +71,7 @@ mod tests { algorithms::intersect::CurveFaceIntersection, builder::{CurveBuilder, FaceBuilder}, insert::Insert, - objects::Face, - partial::HasPartial, - partial2::{Partial, PartialCurve, PartialObject}, + partial::{Partial, PartialCurve, PartialFace, PartialObject}, services::Services, }; @@ -95,7 +93,7 @@ mod tests { services.objects.surfaces.xz_plane(), ] .map(|surface| { - Face::partial() + PartialFace::default() .with_exterior_polygon_from_points(surface, points) .build(&mut services.objects) }); @@ -122,7 +120,7 @@ mod tests { services.objects.surfaces.xz_plane(), ]; let [a, b] = surfaces.clone().map(|surface| { - Face::partial() + PartialFace::default() .with_exterior_polygon_from_points(surface, points) .build(&mut services.objects) }); diff --git a/crates/fj-kernel/src/algorithms/intersect/face_point.rs b/crates/fj-kernel/src/algorithms/intersect/face_point.rs index 021f18ae4..9b91005b8 100644 --- a/crates/fj-kernel/src/algorithms/intersect/face_point.rs +++ b/crates/fj-kernel/src/algorithms/intersect/face_point.rs @@ -139,8 +139,7 @@ mod tests { builder::FaceBuilder, insert::Insert, iter::ObjectIters, - objects::Face, - partial::HasPartial, + partial::{PartialFace, PartialObject}, services::Services, }; @@ -149,7 +148,7 @@ mod tests { let mut services = Services::new(); let surface = services.objects.surfaces.xy_plane(); - let face = Face::partial() + let face = PartialFace::default() .with_exterior_polygon_from_points( surface, [[0., 0.], [1., 1.], [0., 2.]], @@ -167,7 +166,7 @@ mod tests { let mut services = Services::new(); let surface = services.objects.surfaces.xy_plane(); - let face = Face::partial() + let face = PartialFace::default() .with_exterior_polygon_from_points( surface, [[0., 0.], [2., 1.], [0., 2.]], @@ -188,7 +187,7 @@ mod tests { let mut services = Services::new(); let surface = services.objects.surfaces.xy_plane(); - let face = Face::partial() + let face = PartialFace::default() .with_exterior_polygon_from_points( surface, [[4., 2.], [0., 4.], [0., 0.]], @@ -209,7 +208,7 @@ mod tests { let mut services = Services::new(); let surface = services.objects.surfaces.xy_plane(); - let face = Face::partial() + let face = PartialFace::default() .with_exterior_polygon_from_points( surface, [[0., 0.], [2., 1.], [3., 0.], [3., 4.]], @@ -230,7 +229,7 @@ mod tests { let mut services = Services::new(); let surface = services.objects.surfaces.xy_plane(); - let face = Face::partial() + let face = PartialFace::default() .with_exterior_polygon_from_points( surface, [[0., 0.], [2., 1.], [3., 1.], [0., 2.]], @@ -251,7 +250,7 @@ mod tests { let mut services = Services::new(); let surface = services.objects.surfaces.xy_plane(); - let face = Face::partial() + let face = PartialFace::default() .with_exterior_polygon_from_points( surface, [[0., 0.], [2., 1.], [3., 1.], [4., 0.], [4., 5.]], @@ -272,7 +271,7 @@ mod tests { let mut services = Services::new(); let surface = services.objects.surfaces.xy_plane(); - let face = Face::partial() + let face = PartialFace::default() .with_exterior_polygon_from_points( surface, [[0., 0.], [2., 0.], [0., 1.]], @@ -302,7 +301,7 @@ mod tests { let mut services = Services::new(); let surface = services.objects.surfaces.xy_plane(); - let face = Face::partial() + let face = PartialFace::default() .with_exterior_polygon_from_points( surface, [[0., 0.], [1., 0.], [0., 1.]], diff --git a/crates/fj-kernel/src/algorithms/intersect/ray_face.rs b/crates/fj-kernel/src/algorithms/intersect/ray_face.rs index bcb140734..3c4ef18e0 100644 --- a/crates/fj-kernel/src/algorithms/intersect/ray_face.rs +++ b/crates/fj-kernel/src/algorithms/intersect/ray_face.rs @@ -155,8 +155,7 @@ mod tests { builder::FaceBuilder, insert::Insert, iter::ObjectIters, - objects::Face, - partial::HasPartial, + partial::{PartialFace, PartialObject}, services::Services, }; @@ -167,7 +166,7 @@ mod tests { let ray = HorizontalRayToTheRight::from([0., 0., 0.]); let surface = services.objects.surfaces.yz_plane(); - let face = Face::partial() + let face = PartialFace::default() .with_exterior_polygon_from_points( surface, [[-1., -1.], [1., -1.], [1., 1.], [-1., 1.]], @@ -186,7 +185,7 @@ mod tests { let ray = HorizontalRayToTheRight::from([0., 0., 0.]); let surface = services.objects.surfaces.yz_plane(); - let face = Face::partial() + let face = PartialFace::default() .with_exterior_polygon_from_points( surface, [[-1., -1.], [1., -1.], [1., 1.], [-1., 1.]], @@ -208,7 +207,7 @@ mod tests { let ray = HorizontalRayToTheRight::from([0., 0., 0.]); let surface = services.objects.surfaces.yz_plane(); - let face = Face::partial() + let face = PartialFace::default() .with_exterior_polygon_from_points( surface, [[-1., -1.], [1., -1.], [1., 1.], [-1., 1.]], @@ -227,7 +226,7 @@ mod tests { let ray = HorizontalRayToTheRight::from([0., 0., 0.]); let surface = services.objects.surfaces.yz_plane(); - let face = Face::partial() + let face = PartialFace::default() .with_exterior_polygon_from_points( surface, [[-1., -1.], [1., -1.], [1., 1.], [-1., 1.]], @@ -257,7 +256,7 @@ mod tests { let ray = HorizontalRayToTheRight::from([0., 0., 0.]); let surface = services.objects.surfaces.yz_plane(); - let face = Face::partial() + let face = PartialFace::default() .with_exterior_polygon_from_points( surface, [[-1., -1.], [1., -1.], [1., 1.], [-1., 1.]], @@ -285,7 +284,7 @@ mod tests { let ray = HorizontalRayToTheRight::from([0., 0., 0.]); let surface = services.objects.surfaces.xy_plane(); - let face = Face::partial() + let face = PartialFace::default() .with_exterior_polygon_from_points( surface, [[-1., -1.], [1., -1.], [1., 1.], [-1., 1.]], @@ -306,7 +305,7 @@ mod tests { let ray = HorizontalRayToTheRight::from([0., 0., 0.]); let surface = services.objects.surfaces.xy_plane(); - let face = Face::partial() + let face = PartialFace::default() .with_exterior_polygon_from_points( surface, [[-1., -1.], [1., -1.], [1., 1.], [-1., 1.]], diff --git a/crates/fj-kernel/src/algorithms/intersect/surface_surface.rs b/crates/fj-kernel/src/algorithms/intersect/surface_surface.rs index 41c39e5e4..8b03efdbc 100644 --- a/crates/fj-kernel/src/algorithms/intersect/surface_surface.rs +++ b/crates/fj-kernel/src/algorithms/intersect/surface_surface.rs @@ -92,7 +92,7 @@ mod tests { algorithms::transform::TransformObject, builder::CurveBuilder, insert::Insert, - partial2::{Partial, PartialCurve, PartialObject}, + partial::{Partial, PartialCurve, PartialObject}, services::Services, }; diff --git a/crates/fj-kernel/src/algorithms/reverse/face.rs b/crates/fj-kernel/src/algorithms/reverse/face.rs index 9672ebca8..caed07c55 100644 --- a/crates/fj-kernel/src/algorithms/reverse/face.rs +++ b/crates/fj-kernel/src/algorithms/reverse/face.rs @@ -1,7 +1,7 @@ use crate::{ insert::Insert, objects::{Face, Objects}, - partial::HasPartial, + partial::{FullToPartialCache, Partial, PartialFace, PartialObject}, services::Service, storage::Handle, }; @@ -10,17 +10,24 @@ use super::Reverse; impl Reverse for Handle { fn reverse(self, objects: &mut Service) -> Self { - let exterior = self.exterior().clone().reverse(objects); + let mut cache = FullToPartialCache::default(); + + let exterior = Partial::from_full( + self.exterior().clone().reverse(objects), + &mut cache, + ); let interiors = self .interiors() - .map(|cycle| cycle.clone().reverse(objects)) + .map(|cycle| { + Partial::from_full(cycle.clone().reverse(objects), &mut cache) + }) .collect::>(); - Face::partial() - .with_exterior(exterior) - .with_interiors(interiors) - .with_color(self.color()) - .build(objects) - .insert(objects) + let face = PartialFace { + exterior, + interiors, + color: Some(self.color()), + }; + face.build(objects).insert(objects) } } diff --git a/crates/fj-kernel/src/algorithms/sweep/curve.rs b/crates/fj-kernel/src/algorithms/sweep/curve.rs index 7a5b0e437..3a4ba6cba 100644 --- a/crates/fj-kernel/src/algorithms/sweep/curve.rs +++ b/crates/fj-kernel/src/algorithms/sweep/curve.rs @@ -5,7 +5,7 @@ use crate::{ geometry::path::{GlobalPath, SurfacePath}, insert::Insert, objects::{Curve, Objects, Surface}, - partial2::{PartialObject, PartialSurface}, + partial::{PartialObject, PartialSurface}, services::Service, storage::Handle, }; diff --git a/crates/fj-kernel/src/algorithms/sweep/edge.rs b/crates/fj-kernel/src/algorithms/sweep/edge.rs index b0328664e..7ef4f6f63 100644 --- a/crates/fj-kernel/src/algorithms/sweep/edge.rs +++ b/crates/fj-kernel/src/algorithms/sweep/edge.rs @@ -10,7 +10,7 @@ use crate::{ Curve, Cycle, Face, GlobalEdge, HalfEdge, Objects, SurfaceVertex, Vertex, }, - partial::HasPartial, + partial::{Partial, PartialFace, PartialObject}, services::Service, storage::Handle, }; @@ -174,11 +174,12 @@ impl Sweep for (Handle, Color) { Cycle::new(edges).insert(objects) }; - Face::partial() - .with_exterior(cycle) - .with_color(color) - .build(objects) - .insert(objects) + let face = PartialFace { + exterior: Partial::from_full_entry_point(cycle), + color: Some(color), + ..Default::default() + }; + face.build(objects).insert(objects) } } @@ -193,10 +194,10 @@ mod tests { algorithms::{reverse::Reverse, sweep::Sweep}, builder::HalfEdgeBuilder, insert::Insert, - objects::{Cycle, Face, Vertex}, - partial::{HasPartial, PartialHalfEdge}, - partial2::{ - Partial, PartialCurve, PartialGlobalEdge, PartialSurfaceVertex, + objects::{Cycle, Vertex}, + partial::{ + Partial, PartialCurve, PartialFace, PartialGlobalEdge, + PartialHalfEdge, PartialObject, PartialSurfaceVertex, PartialVertex, }, services::Services, @@ -418,9 +419,11 @@ mod tests { let cycle = Cycle::new([bottom, side_up, top, side_down]) .insert(&mut services.objects); - Face::partial() - .with_exterior(cycle) - .build(&mut services.objects) + let face = PartialFace { + exterior: Partial::from_full_entry_point(cycle), + ..Default::default() + }; + face.build(&mut services.objects) .insert(&mut services.objects) }; diff --git a/crates/fj-kernel/src/algorithms/sweep/face.rs b/crates/fj-kernel/src/algorithms/sweep/face.rs index 4df8213fb..688a24d37 100644 --- a/crates/fj-kernel/src/algorithms/sweep/face.rs +++ b/crates/fj-kernel/src/algorithms/sweep/face.rs @@ -91,9 +91,11 @@ mod tests { algorithms::{reverse::Reverse, transform::TransformObject}, builder::{FaceBuilder, HalfEdgeBuilder}, insert::Insert, - objects::{Face, Sketch, Vertex}, - partial::{HasPartial, PartialHalfEdge}, - partial2::{Partial, PartialGlobalEdge}, + objects::{Sketch, Vertex}, + partial::{ + Partial, PartialFace, PartialGlobalEdge, PartialHalfEdge, + PartialObject, + }, services::Services, }; @@ -118,12 +120,12 @@ mod tests { .build(&mut services.objects) .sweep(UP, &mut services.objects); - let bottom = Face::partial() + let bottom = PartialFace::default() .with_exterior_polygon_from_points(surface.clone(), TRIANGLE) .build(&mut services.objects) .insert(&mut services.objects) .reverse(&mut services.objects); - let top = Face::partial() + let top = PartialFace::default() .with_exterior_polygon_from_points( surface.translate(UP, &mut services.objects), TRIANGLE, @@ -186,7 +188,7 @@ mod tests { .build(&mut services.objects) .sweep(DOWN, &mut services.objects); - let bottom = Face::partial() + let bottom = PartialFace::default() .with_exterior_polygon_from_points( surface.clone().translate(DOWN, &mut services.objects), TRIANGLE, @@ -194,7 +196,7 @@ mod tests { .build(&mut services.objects) .insert(&mut services.objects) .reverse(&mut services.objects); - let top = Face::partial() + let top = PartialFace::default() .with_exterior_polygon_from_points(surface, TRIANGLE) .build(&mut services.objects) .insert(&mut services.objects); diff --git a/crates/fj-kernel/src/algorithms/sweep/vertex.rs b/crates/fj-kernel/src/algorithms/sweep/vertex.rs index 6219ea8e9..ae67900a2 100644 --- a/crates/fj-kernel/src/algorithms/sweep/vertex.rs +++ b/crates/fj-kernel/src/algorithms/sweep/vertex.rs @@ -167,10 +167,9 @@ mod tests { builder::{CurveBuilder, HalfEdgeBuilder}, insert::Insert, objects::Vertex, - partial::PartialHalfEdge, - partial2::{ - Partial, PartialCurve, PartialGlobalEdge, PartialObject, - PartialSurfaceVertex, PartialVertex, + partial::{ + Partial, PartialCurve, PartialGlobalEdge, PartialHalfEdge, + PartialObject, PartialSurfaceVertex, PartialVertex, }, services::Services, }; diff --git a/crates/fj-kernel/src/algorithms/triangulate/mod.rs b/crates/fj-kernel/src/algorithms/triangulate/mod.rs index 3e83522f9..3805207ee 100644 --- a/crates/fj-kernel/src/algorithms/triangulate/mod.rs +++ b/crates/fj-kernel/src/algorithms/triangulate/mod.rs @@ -80,7 +80,7 @@ mod tests { builder::FaceBuilder, insert::Insert, objects::Face, - partial::HasPartial, + partial::{PartialFace, PartialObject}, services::Services, storage::Handle, }; @@ -97,7 +97,7 @@ mod tests { let d = [0., 1.]; let surface = services.objects.surfaces.xy_plane(); - let face = Face::partial() + let face = PartialFace::default() .with_exterior_polygon_from_points(surface, [a, b, c, d]) .build(&mut services.objects) .insert(&mut services.objects); @@ -132,7 +132,7 @@ mod tests { let h = [3., 1.]; let surface = services.objects.surfaces.xy_plane(); - let face = Face::partial() + let face = PartialFace::default() .with_exterior_polygon_from_points(surface.clone(), [a, b, c, d]) .with_interior_polygon_from_points(surface.clone(), [e, f, g, h]) .build(&mut services.objects) @@ -190,7 +190,7 @@ mod tests { let e = [0.0, 1.0]; let surface = services.objects.surfaces.xy_plane(); - let face = Face::partial() + let face = PartialFace::default() .with_exterior_polygon_from_points(surface.clone(), [a, b, c, d, e]) .build(&mut services.objects) .insert(&mut services.objects); diff --git a/crates/fj-kernel/src/builder/curve.rs b/crates/fj-kernel/src/builder/curve.rs index e4154888f..85d71a63c 100644 --- a/crates/fj-kernel/src/builder/curve.rs +++ b/crates/fj-kernel/src/builder/curve.rs @@ -1,6 +1,6 @@ use fj_math::{Point, Scalar, Vector}; -use crate::{geometry::path::SurfacePath, partial2::PartialCurve}; +use crate::{geometry::path::SurfacePath, partial::PartialCurve}; /// Builder API for [`PartialCurve`] pub trait CurveBuilder { diff --git a/crates/fj-kernel/src/builder/cycle.rs b/crates/fj-kernel/src/builder/cycle.rs index 52be104d6..c43a83c91 100644 --- a/crates/fj-kernel/src/builder/cycle.rs +++ b/crates/fj-kernel/src/builder/cycle.rs @@ -3,10 +3,9 @@ use fj_math::Point; use crate::{ objects::{Curve, Surface, SurfaceVertex, Vertex}, - partial::{PartialCycle, PartialHalfEdge}, - partial2::{ - Partial, PartialCurve, PartialGlobalEdge, PartialSurfaceVertex, - PartialVertex, + partial::{ + Partial, PartialCurve, PartialCycle, PartialGlobalEdge, + PartialHalfEdge, PartialSurfaceVertex, PartialVertex, }, storage::Handle, }; @@ -36,14 +35,14 @@ pub trait CycleBuilder { impl CycleBuilder for PartialCycle { fn with_poly_chain( - self, + mut self, vertices: impl IntoIterator, ) -> Self { let vertices = vertices.into_iter(); let mut previous: Option> = - self.half_edges().last().map(|half_edge| { - let [_, last] = half_edge.vertices(); + self.half_edges.last().map(|half_edge| { + let [_, last] = &half_edge.read().vertices; let last = last.read(); last.surface_form.clone() }); @@ -89,13 +88,13 @@ impl CycleBuilder for PartialCycle { vertex.read().surface_form.read().global_form.clone() }); - half_edges.push(PartialHalfEdge { + half_edges.push(Partial::from_partial(PartialHalfEdge { vertices, global_form: Partial::from_partial(PartialGlobalEdge { curve: curve.read().global_form.clone(), vertices: global_vertices, }), - }); + })); continue; } @@ -103,7 +102,8 @@ impl CycleBuilder for PartialCycle { previous = Some(vertex_next); } - self.with_half_edges(half_edges) + self.half_edges.extend(half_edges); + self } fn with_poly_chain_from_points( @@ -120,12 +120,13 @@ impl CycleBuilder for PartialCycle { })) } - fn close_with_line_segment(self) -> Self { - let first = self.half_edges().next(); - let last = self.half_edges().last(); + fn close_with_line_segment(mut self) -> Self { + let first = self.half_edges.first(); + let last = self.half_edges.last(); - let vertices = [first, last] - .map(|option| option.map(|half_edge| half_edge.vertices())); + let vertices = [first, last].map(|option| { + option.map(|half_edge| half_edge.read().vertices.clone()) + }); let [Some([first, _]), Some([_, last])] = vertices else { return self; @@ -150,15 +151,18 @@ impl CycleBuilder for PartialCycle { vertex.read().surface_form.read().global_form.clone() }); - let half_edge = PartialHalfEdge { - vertices, - global_form: Partial::from_partial(PartialGlobalEdge { - curve, - vertices: global_vertices, - }), - } - .update_as_line_segment(); + let half_edge = Partial::from_partial( + PartialHalfEdge { + vertices, + global_form: Partial::from_partial(PartialGlobalEdge { + curve, + vertices: global_vertices, + }), + } + .update_as_line_segment(), + ); - self.with_half_edges(Some(half_edge)) + self.half_edges.push(half_edge); + self } } diff --git a/crates/fj-kernel/src/builder/edge.rs b/crates/fj-kernel/src/builder/edge.rs index b1d635da8..3efb4613e 100644 --- a/crates/fj-kernel/src/builder/edge.rs +++ b/crates/fj-kernel/src/builder/edge.rs @@ -3,8 +3,7 @@ use fj_math::{Point, Scalar}; use crate::{ objects::{Curve, Surface, Vertex}, - partial::PartialHalfEdge, - partial2::{Partial, PartialGlobalEdge}, + partial::{Partial, PartialGlobalEdge, PartialHalfEdge}, storage::Handle, }; diff --git a/crates/fj-kernel/src/builder/face.rs b/crates/fj-kernel/src/builder/face.rs index e3f1c7065..2eb68d7c5 100644 --- a/crates/fj-kernel/src/builder/face.rs +++ b/crates/fj-kernel/src/builder/face.rs @@ -1,8 +1,8 @@ use fj_math::Point; use crate::{ - objects::{Cycle, Surface}, - partial::{HasPartial, PartialFace}, + objects::Surface, + partial::{Partial, PartialCycle, PartialFace}, storage::Handle, }; @@ -27,24 +27,28 @@ pub trait FaceBuilder { impl FaceBuilder for PartialFace { fn with_exterior_polygon_from_points( - self, + mut self, surface: Handle, points: impl IntoIterator>>, ) -> Self { - self.with_exterior( - Cycle::partial() + self.exterior = Partial::from_partial( + PartialCycle::default() .with_poly_chain_from_points(surface, points) .close_with_line_segment(), - ) + ); + self } fn with_interior_polygon_from_points( - self, + mut self, surface: Handle, points: impl IntoIterator>>, ) -> Self { - self.with_interiors([Cycle::partial() - .with_poly_chain_from_points(surface, points) - .close_with_line_segment()]) + self.interiors = vec![Partial::from_partial( + PartialCycle::default() + .with_poly_chain_from_points(surface, points) + .close_with_line_segment(), + )]; + self } } diff --git a/crates/fj-kernel/src/builder/shell.rs b/crates/fj-kernel/src/builder/shell.rs index 0172ccd71..2f1dc1818 100644 --- a/crates/fj-kernel/src/builder/shell.rs +++ b/crates/fj-kernel/src/builder/shell.rs @@ -8,11 +8,11 @@ use crate::{ algorithms::transform::TransformObject, builder::{FaceBuilder, HalfEdgeBuilder, SurfaceBuilder}, insert::Insert, - objects::{Cycle, Face, FaceSet, Objects, Shell, Vertex}, - partial::{HasPartial, PartialHalfEdge}, - partial2::{ - Partial, PartialCurve, PartialGlobalEdge, PartialObject, - PartialSurface, PartialSurfaceVertex, PartialVertex, + objects::{Face, FaceSet, HalfEdge, Objects, Shell, Vertex}, + partial::{ + Partial, PartialCurve, PartialCycle, PartialFace, PartialGlobalEdge, + PartialHalfEdge, PartialObject, PartialSurface, PartialSurfaceVertex, + PartialVertex, }, services::Service, storage::Handle, @@ -52,7 +52,7 @@ impl ShellBuilder { let surface = objects.surfaces.xy_plane().translate([Z, Z, -h], objects); - Face::partial() + PartialFace::default() .with_exterior_polygon_from_points( surface, [[-h, -h], [h, -h], [h, h], [-h, h]], @@ -89,39 +89,41 @@ impl ShellBuilder { .read() .clone(); - PartialHalfEdge { - vertices: global_edge.vertices.clone().map( - |global_vertex| { - Partial::from_partial(PartialVertex { - curve: Partial::from_partial( - PartialCurve { - global_form: global_edge - .curve - .clone(), - ..Default::default() - }, - ), - surface_form: Partial::from_partial( - PartialSurfaceVertex { - global_form: global_vertex, - ..Default::default() - }, - ), - ..Default::default() - }) - }, + Partial::from_partial( + PartialHalfEdge { + vertices: global_edge.vertices.clone().map( + |global_vertex| { + Partial::from_partial(PartialVertex { + curve: Partial::from_partial( + PartialCurve { + global_form: global_edge + .curve + .clone(), + ..Default::default() + }, + ), + surface_form: Partial::from_partial( + PartialSurfaceVertex { + global_form: global_vertex, + ..Default::default() + }, + ), + ..Default::default() + }) + }, + ), + global_form: Partial::from_partial( + PartialGlobalEdge { + curve: global_edge.curve, + vertices: global_edge.vertices, + }, + ), + } + .update_as_line_segment_from_points( + Partial::from_full_entry_point(surface.clone()), + [[Z, Z], [edge_length, Z]], ), - global_form: Partial::from_partial(PartialGlobalEdge { - curve: global_edge.curve, - vertices: global_edge.vertices, - }), - } - .update_as_line_segment_from_points( - Partial::from_full_entry_point(surface.clone()), - [[Z, Z], [edge_length, Z]], ) - .build(objects) - .insert(objects) }) .collect::>(); @@ -129,12 +131,14 @@ impl ShellBuilder { .clone() .into_iter() .zip(&surfaces) - .map(|(bottom, surface)| { - let [_, from] = bottom.vertices(); + .map(|(bottom, surface): (Partial, _)| { + let [_, from] = &bottom.read().vertices; - let from = from.surface_form().clone(); + let from = from.read().surface_form.clone(); let to = PartialSurfaceVertex { - position: Some(from.position() + [Z, edge_length]), + position: Some( + from.read().position.unwrap() + [Z, edge_length], + ), surface: Partial::from_full_entry_point( surface.clone(), ), @@ -144,12 +148,10 @@ impl ShellBuilder { let vertices = [ PartialVertex { curve: Partial::from_partial(PartialCurve { - surface: Partial::from_full_entry_point( - from.surface().clone(), - ), + surface: from.read().surface.clone(), ..Default::default() }), - surface_form: Partial::from_full_entry_point(from), + surface_form: from.clone(), ..Default::default() }, PartialVertex { @@ -177,16 +179,18 @@ impl ShellBuilder { .clone() }); - PartialHalfEdge { - vertices, - global_form: Partial::from_partial(PartialGlobalEdge { - curve: global_curve, - vertices: global_vertices, - }), - } - .update_as_line_segment() - .build(objects) - .insert(objects) + Partial::from_partial( + PartialHalfEdge { + vertices, + global_form: Partial::from_partial( + PartialGlobalEdge { + curve: global_curve, + vertices: global_vertices, + }, + ), + } + .update_as_line_segment(), + ) }) .collect::>(); @@ -199,75 +203,90 @@ impl ShellBuilder { .into_iter() .zip(sides_up_prev) .zip(&surfaces) - .map(|((bottom, side_up_prev), surface)| { - let [_, from] = side_up_prev.vertices(); - let [to, _] = bottom.vertices(); - - let to = to.surface_form().clone(); - let from = PartialSurfaceVertex { - position: Some(to.position() + [Z, edge_length]), - surface: Partial::from_full_entry_point( - surface.clone(), - ), - global_form: Partial::from_full_entry_point( - from.global_form().clone(), - ), - }; - - let curve = PartialCurve { - global_form: Partial::from_full_entry_point( - side_up_prev.curve().global_form().clone(), - ), - ..Default::default() - }; - - let vertices = [ - PartialVertex { - curve: Partial::from_partial(PartialCurve { - surface: from.surface.clone(), - ..curve.clone() - }), - surface_form: Partial::from_partial(from), - ..Default::default() - }, - PartialVertex { - curve: Partial::from_partial(PartialCurve { - surface: Partial::from_full_entry_point( - to.surface().clone(), - ), - ..curve.clone() - }), - surface_form: Partial::from_full_entry_point( - to, + .map( + |((bottom, side_up_prev), surface): ( + (_, Partial), + _, + )| { + let [_, from] = + side_up_prev.read().vertices.clone(); + let [to, _] = bottom.read().vertices.clone(); + + let to = to.read().surface_form.clone(); + let from = PartialSurfaceVertex { + position: Some( + to.read().position.unwrap() + + [Z, edge_length], ), - ..Default::default() - }, - ] - .map(Partial::::from_partial); - - let global_vertices = - vertices.each_ref_ext().map(|vertex| { - vertex + surface: Partial::from_full_entry_point( + surface.clone(), + ), + global_form: from .read() .surface_form .read() .global_form - .clone() - }); + .clone(), + }; - PartialHalfEdge { - vertices, - global_form: Partial::from_partial( - PartialGlobalEdge { - vertices: global_vertices, - curve: curve.global_form, + let curve = PartialCurve { + global_form: side_up_prev + .read() + .curve() + .read() + .global_form + .clone(), + ..Default::default() + }; + + let vertices = [ + PartialVertex { + curve: Partial::from_partial( + PartialCurve { + surface: from.surface.clone(), + ..curve.clone() + }, + ), + surface_form: Partial::from_partial(from), + ..Default::default() }, - ), - } - .update_as_line_segment() - .build(objects) - .insert(objects) - }) + PartialVertex { + curve: Partial::from_partial( + PartialCurve { + surface: to.read().surface.clone(), + ..curve.clone() + }, + ), + surface_form: to.clone(), + ..Default::default() + }, + ] + .map(Partial::::from_partial); + + let global_vertices = + vertices.each_ref_ext().map(|vertex| { + vertex + .read() + .surface_form + .read() + .global_form + .clone() + }); + + Partial::from_partial( + PartialHalfEdge { + vertices, + global_form: Partial::from_partial( + PartialGlobalEdge { + vertices: global_vertices, + curve: curve.global_form, + }, + ), + } + .update_as_line_segment(), + ) + }, + ) .collect::>() }; @@ -275,31 +294,27 @@ impl ShellBuilder { .clone() .into_iter() .zip(sides_down.clone()) - .map(|(side_up, side_down)| { - let [_, from] = side_up.vertices(); - let [to, _] = side_down.vertices(); + .map(|(side_up, side_down): (_, Partial)| { + let [_, from] = side_up.read().vertices.clone(); + let [to, _] = side_down.read().vertices.clone(); - let from = from.surface_form().clone(); - let to = to.surface_form().clone(); + let from = from.read().surface_form.clone(); + let to = to.read().surface_form.clone(); let from = PartialVertex { curve: Partial::from_partial(PartialCurve { - surface: Partial::from_full_entry_point( - from.surface().clone(), - ), + surface: from.read().surface.clone(), ..Default::default() }), - surface_form: Partial::from_full_entry_point(from), + surface_form: from.clone(), ..Default::default() }; let to = PartialVertex { curve: Partial::from_partial(PartialCurve { - surface: Partial::from_full_entry_point( - to.surface().clone(), - ), + surface: to.read().surface.clone(), ..Default::default() }), - surface_form: Partial::from_full_entry_point(to), + surface_form: to.clone(), ..Default::default() }; @@ -319,16 +334,18 @@ impl ShellBuilder { .clone() }); - PartialHalfEdge { - vertices, - global_form: Partial::from_partial(PartialGlobalEdge { - curve: global_curve, - vertices: global_vertices, - }), - } - .update_as_line_segment() - .build(objects) - .insert(objects) + Partial::from_partial( + PartialHalfEdge { + vertices, + global_form: Partial::from_partial( + PartialGlobalEdge { + curve: global_curve, + vertices: global_vertices, + }, + ), + } + .update_as_line_segment(), + ) }) .collect::>(); @@ -338,15 +355,14 @@ impl ShellBuilder { .zip(tops.clone()) .zip(sides_down) .map(|(((bottom, side_up), top), side_down)| { - let cycle = Cycle::partial() - .with_half_edges([bottom, side_up, top, side_down]) - .build(objects) - .insert(objects); + let mut cycle = PartialCycle::default(); + cycle.half_edges.extend([bottom, side_up, top, side_down]); - Face::partial() - .with_exterior(cycle) - .build(objects) - .insert(objects) + let face = PartialFace { + exterior: Partial::from_partial(cycle), + ..Default::default() + }; + face.build(objects).insert(objects) }) .collect::>(); @@ -371,16 +387,20 @@ impl ShellBuilder { .zip(half_edges) .collect::<[_; 4]>() .map(|(point, edge)| { - let vertex = edge.back(); + let [vertex, _] = edge.read().vertices.clone(); + let global_vertex = vertex + .read() + .surface_form + .read() + .global_form + .clone(); PartialSurfaceVertex { position: Some(point.into()), surface: Partial::from_full_entry_point( surface.clone(), ), - global_form: Partial::from_full_entry_point( - vertex.global_form().clone(), - ), + global_form: global_vertex, } .build(objects) .insert(objects) @@ -395,26 +415,27 @@ impl ShellBuilder { .array_windows_ext() .zip(top_edges) { - let global_edge = - Partial::from_full_entry_point(edge.global_form().clone()) - .read() - .clone(); + let global_edge = edge.read().global_form.clone(); let vertices = edge - .vertices() + .read() + .vertices .each_ref_ext() .into_iter_fixed() .zip(surface_vertices.clone()) .collect::<[_; 2]>() .map(|(vertex, surface_form)| PartialVertex { - position: Some(vertex.position()), + position: vertex.read().position, curve: Partial::from_partial(PartialCurve { surface: Partial::from_full_entry_point( surface_form.surface().clone(), ), - global_form: Partial::from_full_entry_point( - vertex.curve().global_form().clone(), - ), + global_form: vertex + .read() + .curve + .read() + .global_form + .clone(), ..Default::default() }), surface_form: Partial::from_full_entry_point( @@ -422,24 +443,23 @@ impl ShellBuilder { ), }); - edges.push( + edges.push(Partial::from_partial( PartialHalfEdge { vertices: vertices.map(Partial::from_partial), global_form: Partial::from_partial(PartialGlobalEdge { - curve: global_edge.curve, - vertices: global_edge.vertices, + curve: global_edge.read().curve.clone(), + vertices: global_edge.read().vertices.clone(), }), } - .update_as_line_segment() - .build(objects) - .insert(objects), - ); + .update_as_line_segment(), + )); } - Face::partial() - .with_exterior(Cycle::new(edges).insert(objects)) - .build(objects) - .insert(objects) + let face = PartialFace { + exterior: Partial::from_partial(PartialCycle::new(edges)), + ..Default::default() + }; + face.build(objects).insert(objects) }; self.faces.extend([bottom]); diff --git a/crates/fj-kernel/src/builder/sketch.rs b/crates/fj-kernel/src/builder/sketch.rs index f80593ddf..3f94b6692 100644 --- a/crates/fj-kernel/src/builder/sketch.rs +++ b/crates/fj-kernel/src/builder/sketch.rs @@ -3,7 +3,7 @@ use fj_math::Point; use crate::{ insert::Insert, objects::{Face, FaceSet, Objects, Sketch, Surface}, - partial::HasPartial, + partial::{PartialFace, PartialObject}, services::Service, storage::Handle, }; @@ -35,7 +35,7 @@ impl SketchBuilder { points: impl IntoIterator>>, objects: &mut Service, ) -> Self { - self.faces.extend([Face::partial() + self.faces.extend([PartialFace::default() .with_exterior_polygon_from_points(surface, points) .build(objects) .insert(objects)]); diff --git a/crates/fj-kernel/src/builder/surface.rs b/crates/fj-kernel/src/builder/surface.rs index 03f1c52e5..cc1d57728 100644 --- a/crates/fj-kernel/src/builder/surface.rs +++ b/crates/fj-kernel/src/builder/surface.rs @@ -2,7 +2,7 @@ use fj_math::{Line, Point, Vector}; use crate::{ geometry::{path::GlobalPath, surface::SurfaceGeometry}, - partial2::PartialSurface, + partial::PartialSurface, }; /// Builder API for [`PartialSurface`] diff --git a/crates/fj-kernel/src/builder/vertex.rs b/crates/fj-kernel/src/builder/vertex.rs index 445d504ad..2d12dd6d0 100644 --- a/crates/fj-kernel/src/builder/vertex.rs +++ b/crates/fj-kernel/src/builder/vertex.rs @@ -3,7 +3,7 @@ use fj_math::Point; use crate::{ geometry::surface::SurfaceGeometry, objects::Curve, - partial2::{ + partial::{ Partial, PartialGlobalVertex, PartialSurfaceVertex, PartialVertex, }, }; diff --git a/crates/fj-kernel/src/get.rs b/crates/fj-kernel/src/get.rs deleted file mode 100644 index 43b41c2b0..000000000 --- a/crates/fj-kernel/src/get.rs +++ /dev/null @@ -1,15 +0,0 @@ -//! Infrastructure for abstracting over accessing referenced objects - -use crate::storage::Handle; - -/// Access a single referenced object -/// -/// Object types implement this trait for the objects they reference. It can be -/// used by other generic infrastructure to abstract over object access. -/// -/// This trait is specifically intended to access single objects, like *the* -/// curve that a vertex references, not *a* half-edge that a cycle references. -pub trait Get { - /// Access the referenced object - fn get(&self) -> Handle; -} diff --git a/crates/fj-kernel/src/iter.rs b/crates/fj-kernel/src/iter.rs index ed457cbb4..6ec8de881 100644 --- a/crates/fj-kernel/src/iter.rs +++ b/crates/fj-kernel/src/iter.rs @@ -367,11 +367,13 @@ mod tests { builder::{CurveBuilder, CycleBuilder, FaceBuilder, HalfEdgeBuilder}, insert::Insert, objects::{ - Cycle, Face, GlobalCurve, GlobalVertex, Objects, Shell, Sketch, - Solid, SurfaceVertex, Vertex, + GlobalCurve, GlobalVertex, Objects, Shell, Sketch, Solid, + SurfaceVertex, Vertex, + }, + partial::{ + Partial, PartialCurve, PartialCycle, PartialFace, + PartialGlobalEdge, PartialHalfEdge, PartialObject, }, - partial::{HasPartial, PartialHalfEdge}, - partial2::{Partial, PartialCurve, PartialGlobalEdge, PartialObject}, services::Services, }; @@ -409,7 +411,7 @@ mod tests { let mut services = Services::new(); let surface = services.objects.surfaces.xy_plane(); - let object = Cycle::partial() + let object = PartialCycle::default() .with_poly_chain_from_points( surface, [[0., 0.], [1., 0.], [0., 1.]], @@ -436,7 +438,7 @@ mod tests { let mut services = Services::new(); let surface = services.objects.surfaces.xy_plane(); - let object = Face::partial() + let object = PartialFace::default() .with_exterior_polygon_from_points( surface, [[0., 0.], [1., 0.], [0., 1.]], @@ -568,7 +570,7 @@ mod tests { let mut services = Services::new(); let surface = services.objects.surfaces.xy_plane(); - let face = Face::partial() + let face = PartialFace::default() .with_exterior_polygon_from_points( surface, [[0., 0.], [1., 0.], [0., 1.]], diff --git a/crates/fj-kernel/src/lib.rs b/crates/fj-kernel/src/lib.rs index 3f0642370..0a1b20ea8 100644 --- a/crates/fj-kernel/src/lib.rs +++ b/crates/fj-kernel/src/lib.rs @@ -95,12 +95,10 @@ pub mod algorithms; pub mod builder; pub mod geometry; -pub mod get; pub mod insert; pub mod iter; pub mod objects; pub mod partial; -pub mod partial2; pub mod services; pub mod storage; pub mod validate; diff --git a/crates/fj-kernel/src/objects/full/curve.rs b/crates/fj-kernel/src/objects/full/curve.rs index 2b71f9f2f..2db17d3fc 100644 --- a/crates/fj-kernel/src/objects/full/curve.rs +++ b/crates/fj-kernel/src/objects/full/curve.rs @@ -1,6 +1,5 @@ use crate::{ geometry::path::SurfacePath, - get::Get, objects::Surface, storage::{Handle, HandleWrapper}, }; @@ -43,18 +42,6 @@ impl Curve { } } -impl Get for Curve { - fn get(&self) -> Handle { - self.surface().clone() - } -} - -impl Get for Curve { - fn get(&self) -> Handle { - self.global_form().clone() - } -} - /// A curve, defined in global (3D) coordinates #[derive(Clone, Copy, Debug)] pub struct GlobalCurve; diff --git a/crates/fj-kernel/src/objects/full/edge.rs b/crates/fj-kernel/src/objects/full/edge.rs index d7e640dd8..e45c5176d 100644 --- a/crates/fj-kernel/src/objects/full/edge.rs +++ b/crates/fj-kernel/src/objects/full/edge.rs @@ -1,7 +1,6 @@ use std::fmt; use crate::{ - get::Get, objects::{Curve, GlobalCurve, GlobalVertex, Surface, Vertex}, storage::{Handle, HandleWrapper}, }; @@ -59,18 +58,6 @@ impl HalfEdge { } } -impl Get for HalfEdge { - fn get(&self) -> Handle { - self.global_form().clone() - } -} - -impl Get for HalfEdge { - fn get(&self) -> Handle { - self.global_form().curve().clone() - } -} - impl fmt::Display for HalfEdge { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let [a, b] = self.vertices().clone().map(|vertex| vertex.position()); @@ -125,12 +112,6 @@ impl GlobalEdge { } } -impl Get for GlobalEdge { - fn get(&self) -> Handle { - self.curve().clone() - } -} - /// The vertices of a [`GlobalEdge`] /// /// Since [`GlobalEdge`] is the single global representation of an edge in @@ -171,8 +152,7 @@ mod tests { use crate::{ builder::HalfEdgeBuilder, objects::Vertex, - partial::PartialHalfEdge, - partial2::{Partial, PartialGlobalEdge}, + partial::{Partial, PartialGlobalEdge, PartialHalfEdge, PartialObject}, services::Services, }; diff --git a/crates/fj-kernel/src/objects/full/vertex.rs b/crates/fj-kernel/src/objects/full/vertex.rs index 3c812e8e9..35c005cca 100644 --- a/crates/fj-kernel/src/objects/full/vertex.rs +++ b/crates/fj-kernel/src/objects/full/vertex.rs @@ -1,8 +1,7 @@ use fj_math::Point; use crate::{ - get::Get, - objects::{Curve, GlobalCurve, Surface}, + objects::{Curve, Surface}, storage::Handle, }; @@ -55,36 +54,6 @@ impl Vertex { } } -impl Get for Vertex { - fn get(&self) -> Handle { - self.curve().clone() - } -} - -impl Get for Vertex { - fn get(&self) -> Handle { - self.surface_form().clone() - } -} - -impl Get for Vertex { - fn get(&self) -> Handle { - self.curve().surface().clone() - } -} - -impl Get for Vertex { - fn get(&self) -> Handle { - self.curve().global_form().clone() - } -} - -impl Get for Vertex { - fn get(&self) -> Handle { - self.surface_form().global_form().clone() - } -} - /// A vertex, defined in surface (2D) coordinates #[derive(Clone, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)] pub struct SurfaceVertex { @@ -124,18 +93,6 @@ impl SurfaceVertex { } } -impl Get for SurfaceVertex { - fn get(&self) -> Handle { - self.surface().clone() - } -} - -impl Get for SurfaceVertex { - fn get(&self) -> Handle { - self.global_form().clone() - } -} - /// A vertex, defined in global (3D) coordinates /// /// This struct exists to distinguish between vertices and points at the type diff --git a/crates/fj-kernel/src/partial/maybe_partial.rs b/crates/fj-kernel/src/partial/maybe_partial.rs deleted file mode 100644 index 6cbfcedb6..000000000 --- a/crates/fj-kernel/src/partial/maybe_partial.rs +++ /dev/null @@ -1,152 +0,0 @@ -use crate::{ - get::Get, - insert::Insert, - objects::Objects, - services::Service, - storage::Handle, - validate::{Validate, ValidationError}, -}; - -use super::{HasPartial, MergeWith, Partial, Replace}; - -/// Can be used everywhere either a partial or full objects are accepted -/// -/// Some convenience methods are available for specific instances of -/// `MaybePartial` (like, `MaybePartial`, or `MaybePartial`). -/// -/// # Implementation Note -/// -/// The set of available convenience methods is far from complete. Please feel -/// free to just add more, if you need them. -#[derive(Clone, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)] -pub enum MaybePartial { - /// A full object - Full(Handle), - - /// A partial object - Partial(T::Partial), -} - -impl MaybePartial { - /// Indicate whether this is a full object - pub fn is_full(&self) -> bool { - if let Self::Full(_) = self { - return true; - } - - false - } - - /// Indicate whether this is a partial object - pub fn is_partial(&self) -> bool { - if let Self::Partial(_) = self { - return true; - } - - false - } - - /// If this is a partial object, update it - /// - /// This is useful whenever a partial object can infer something about its - /// parts from other parts, and wants to update what was inferred, in case - /// it *can* be updated. - pub fn update_partial( - self, - f: impl FnOnce(T::Partial) -> T::Partial, - ) -> Self { - match self { - Self::Partial(partial) => Self::Partial(f(partial)), - _ => self, - } - } - - /// Return or build a full object - /// - /// If this already is a full object, it is returned. If this is a partial - /// object, the full object is built from it, using [`Partial::build`]. - pub fn into_full(self, objects: &mut Service) -> Handle - where - T: Insert, - ValidationError: From<::Error>, - { - match self { - Self::Partial(partial) => partial.build(objects).insert(objects), - Self::Full(full) => full, - } - } - - /// Return or convert a partial object - /// - /// If this already is a partial object, is is returned. If this is a full - /// object, it is converted into a partial object using - /// [`HasPartial::to_partial`]. - pub fn into_partial(self) -> T::Partial { - match self { - Self::Partial(partial) => partial, - Self::Full(full) => full.to_partial(), - } - } -} - -impl Default for MaybePartial -where - T: HasPartial, - T::Partial: Default, -{ - fn default() -> Self { - Self::Partial(T::Partial::default()) - } -} - -impl MergeWith for MaybePartial -where - T: HasPartial, - T::Partial: MergeWith, -{ - fn merge_with(self, other: impl Into) -> Self { - match (self, other.into()) { - (Self::Full(a), Self::Full(b)) => Self::Full(a.merge_with(b)), - (Self::Full(full), Self::Partial(_)) - | (Self::Partial(_), Self::Full(full)) => Self::Full(full), - (Self::Partial(a), Self::Partial(b)) => { - Self::Partial(a.merge_with(b)) - } - } - } -} - -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, -{ - fn from(full: Handle) -> Self { - Self::Full(full) - } -} - -// Unfortunately, we can't add a blanket implementation from `T::Partial` for -// `MaybePartial`, as that would conflict. diff --git a/crates/fj-kernel/src/partial/merge.rs b/crates/fj-kernel/src/partial/merge.rs deleted file mode 100644 index f41a59812..000000000 --- a/crates/fj-kernel/src/partial/merge.rs +++ /dev/null @@ -1,107 +0,0 @@ -use iter_fixed::IntoIteratorFixed; - -use crate::storage::Handle; - -/// Trait for merging partial objects -/// -/// Implemented for all partial objects themselves, and also some related types -/// that partial objects usually contain. -pub trait MergeWith: Sized { - /// Merge this object with another - /// - /// # Panics - /// - /// Merging two objects that cannot be merged is considered a programmer - /// error and will result in a panic. - fn merge_with(self, other: impl Into) -> Self; -} - -/// Wrapper struct that indicates that the contents can be merged -/// -/// Used in connection with [`MergeWith`] to select one implementation over -/// another. -pub struct Mergeable(pub T); - -impl MergeWith for [T; N] -where - T: MergeWith, -{ - fn merge_with(self, other: impl Into) -> Self { - self.into_iter_fixed() - .zip(other.into()) - .collect::<[_; N]>() - .map(|(a, b)| a.merge_with(b)) - } -} - -impl MergeWith for Option -where - T: PartialEq, -{ - fn merge_with(self, other: impl Into) -> Self { - let other = other.into(); - - if self == other { - return self; - } - - // We know that `self != other`, or we wouldn't have made it here. - assert!( - self.is_none() || other.is_none(), - "Can't merge two `Option`s that are both `Some`" - ); - - self.xor(other) - } -} - -// We wouldn't need to use `Mergeable` here, if we had `specialization`: -// https://doc.rust-lang.org/nightly/unstable-book/language-features/specialization.html -// -// Or maybe `min_specialization`: -// https://doc.rust-lang.org/nightly/unstable-book/language-features/min-specialization.html -impl MergeWith for Mergeable> -where - T: MergeWith, -{ - fn merge_with(self, other: impl Into) -> Self { - let merged = match (self.0, other.into().0) { - (Some(a), Some(b)) => Some(a.merge_with(b)), - (a, b) => a.xor(b), - }; - - Self(merged) - } -} - -impl MergeWith for Vec { - fn merge_with(self, other: impl Into) -> Self { - let other = other.into(); - - match (self.is_empty(), other.is_empty()) { - (true, true) => { - panic!("Can't merge `PartialHalfEdge`, if both have half-edges") - } - (true, false) => other, - (false, true) => self, - (false, false) => self, // doesn't matter which we use - } - } -} - -impl MergeWith for Mergeable> { - fn merge_with(mut self, other: impl Into) -> Self { - self.0.extend(other.into().0); - self - } -} - -impl MergeWith for Handle { - fn merge_with(self, other: impl Into) -> Self { - if self.id() == other.into().id() { - return self; - } - - panic!("Can't merge two distinct objects") - } -} diff --git a/crates/fj-kernel/src/partial/mod.rs b/crates/fj-kernel/src/partial/mod.rs index a623b36ba..9ca5d0cc5 100644 --- a/crates/fj-kernel/src/partial/mod.rs +++ b/crates/fj-kernel/src/partial/mod.rs @@ -1,49 +1,31 @@ -//! API for dealing with partially defined objects +//! Partially defined objects //! -//! This module contains types that represent objects that only have some of -//! their data and referenced objects defined. This is useful in the following -//! situations: -//! -//! - Sometimes parts of an object can be inferred. For example, when building a -//! half-edge that is a line segment, it is enough to provide only two partial -//! vertices with only their surface coordinates defined. The rest can be -//! inferred. -//! - Sometimes you need to build an object, but parts of it already exist. For -//! example, a new half-edge might share a vertex with an existing half-edge. -//! In such a case you can use the partial object to provide the existing -//! vertex, then provide or infer other parts as appropriate. -//! - When transforming an object, parts of it might already be transformed. For -//! example, when transforming a half-edge, each of its vertices references -//! the same curve as the half-edge does. The partial object API can be used -//! to avoid transforming the same object multiple times. -//! -//! This module contains two groups of types: -//! -//! - Structs that represent partial objects. For example [`PartialHalfEdge`] is -//! the partial variant of [`HalfEdge`]. -//! - Infrastructure for abstracting over partial objects. See [`Partial`], -//! [`HasPartial`], and [`MaybePartial`]. -//! -//! [`HalfEdge`]: crate::objects::HalfEdge +//! This module contains types that mirror the full object types from +//! [`crate::objects`], only the types from this module can be defined only +//! partially, with the non-defined parts being inferred when a full object is +//! constructed. //! //! # Implementation Note //! -//! This API grew out of the [builder API][crate::builder] and is still -//! incomplete. Eventually, it should replace the builder API completely -//! ([#1147]). -//! -//! [#1147]: https://github.com/hannobraun/Fornjot/issues/1147 +//! This API was created as a replacement for the [original partial object +//! API][crate::partial]. This is still a work in progress. -mod maybe_partial; -mod merge; mod objects; -mod replace; mod traits; +mod wrapper; pub use self::{ - maybe_partial::MaybePartial, - merge::{MergeWith, Mergeable}, - objects::{cycle::PartialCycle, edge::PartialHalfEdge, face::PartialFace}, - replace::Replace, - traits::{HasPartial, Partial}, + objects::{ + curve::{PartialCurve, PartialGlobalCurve}, + cycle::PartialCycle, + edge::{PartialGlobalEdge, PartialHalfEdge}, + face::PartialFace, + shell::PartialShell, + sketch::PartialSketch, + solid::PartialSolid, + surface::PartialSurface, + vertex::{PartialGlobalVertex, PartialSurfaceVertex, PartialVertex}, + }, + traits::{HasPartial, PartialObject}, + wrapper::{FullToPartialCache, Partial}, }; diff --git a/crates/fj-kernel/src/partial2/objects/curve.rs b/crates/fj-kernel/src/partial/objects/curve.rs similarity index 97% rename from crates/fj-kernel/src/partial2/objects/curve.rs rename to crates/fj-kernel/src/partial/objects/curve.rs index d6029ddbd..54fa9d7e1 100644 --- a/crates/fj-kernel/src/partial2/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}, - partial2::{FullToPartialCache, Partial, PartialObject}, + partial::{FullToPartialCache, Partial, PartialObject}, services::Service, }; diff --git a/crates/fj-kernel/src/partial/objects/cycle.rs b/crates/fj-kernel/src/partial/objects/cycle.rs index 9b0441e86..2c21d79f6 100644 --- a/crates/fj-kernel/src/partial/objects/cycle.rs +++ b/crates/fj-kernel/src/partial/objects/cycle.rs @@ -1,90 +1,55 @@ use crate::{ objects::{Cycle, HalfEdge, Objects, Surface}, - partial::{MaybePartial, MergeWith}, - partial2::Partial, + partial::{FullToPartialCache, Partial, PartialObject}, services::Service, }; /// A partial [`Cycle`] -/// -/// See [`crate::partial`] for more information. -#[derive(Clone, Debug, Default)] +#[derive(Clone, Debug)] pub struct PartialCycle { - half_edges: Vec>, + /// The half-edges that make up the cycle + pub half_edges: Vec>, } impl PartialCycle { - /// Access the half-edges that make up the [`Cycle`] - pub fn half_edges(&self) -> impl Iterator> { - self.half_edges.clone().into_iter() + /// Construct an instance of `PartialCycle` + pub fn new(half_edges: Vec>) -> Self { + Self { half_edges } } - /// Access the surface that the [`Cycle`]'s [`HalfEdge`]s are defined in + /// Access the surface of the [`Cycle`] pub fn surface(&self) -> Option> { self.half_edges .first() - .map(|half_edge| half_edge.curve().read().surface.clone()) + .map(|half_edge| half_edge.read().curve().read().surface.clone()) } +} - /// Add the provided half-edges to the partial cycle - /// - /// This will merge all the surfaces of the added half-edges. All added - /// half-edges will end up with the same merged surface. - /// - /// # Panics - /// - /// Panics, if the surfaces can't be merged. - pub fn with_half_edges( - mut self, - half_edges: impl IntoIterator>>, - ) -> Self { - let half_edges = half_edges.into_iter().map(Into::into); - - for half_edge in half_edges { - self.half_edges.push(half_edge); - } - - self +impl PartialObject for PartialCycle { + type Full = Cycle; + + fn from_full(cycle: &Self::Full, cache: &mut FullToPartialCache) -> Self { + Self::new( + cycle + .half_edges() + .cloned() + .map(|half_edge| Partial::from_full(half_edge, cache)) + .collect(), + ) } - /// Build a full [`Cycle`] from the partial cycle - pub fn build(self, objects: &mut Service) -> Cycle { - 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); - } + fn build(self, objects: &mut Service) -> Self::Full { + let half_edges = self + .half_edges + .into_iter() + .map(|half_edge| half_edge.build(objects)); Cycle::new(half_edges) } } -impl MergeWith for PartialCycle { - fn merge_with(self, other: impl Into) -> Self { - let other = other.into(); - - Self { - half_edges: self.half_edges.merge_with(other.half_edges), - } - } -} - -impl From<&Cycle> for PartialCycle { - fn from(cycle: &Cycle) -> Self { - Self { - half_edges: cycle.half_edges().cloned().map(Into::into).collect(), - } - } -} - -impl MaybePartial { - /// Access the surface - pub fn surface(&self) -> Option> { - match self { - Self::Full(full) => { - Some(Partial::from_full_entry_point(full.surface().clone())) - } - Self::Partial(partial) => partial.surface(), - } +impl Default for PartialCycle { + fn default() -> Self { + Self::new(Vec::new()) } } diff --git a/crates/fj-kernel/src/partial/objects/edge.rs b/crates/fj-kernel/src/partial/objects/edge.rs index c0bb12ed8..22b9bd22c 100644 --- a/crates/fj-kernel/src/partial/objects/edge.rs +++ b/crates/fj-kernel/src/partial/objects/edge.rs @@ -1,31 +1,86 @@ +use fj_interop::ext::ArrayExt; + use crate::{ - objects::{Curve, GlobalEdge, HalfEdge, Objects, Vertex}, - partial::{MaybePartial, MergeWith}, - partial2::Partial, + objects::{ + Curve, GlobalCurve, GlobalEdge, GlobalVertex, HalfEdge, Objects, Vertex, + }, + partial::{FullToPartialCache, Partial, PartialObject, PartialVertex}, services::Service, }; /// A partial [`HalfEdge`] -/// -/// See [`crate::partial`] for more information. -#[derive(Clone, Debug, Default)] +#[derive(Clone, Debug)] pub struct PartialHalfEdge { - /// The vertices that bound the [`HalfEdge`] in the curve + /// The vertices that bound the half-edge on the curve pub vertices: [Partial; 2], - /// The global form of the [`HalfEdge`] + /// The global form of the half-edge pub global_form: Partial, } impl PartialHalfEdge { - /// Access the partial half-edge's curve + /// Construct an instance of `PartialHalfEdge` + pub fn new( + vertices: [Option>; 2], + global_form: Option>, + ) -> Self { + let curve = Partial::::new(); + + let vertices = vertices.map(|vertex| { + vertex.unwrap_or_else(|| { + Partial::from_partial(PartialVertex::new( + None, + Some(curve.clone()), + None, + )) + }) + }); + + let global_curve = curve.read().global_form.clone(); + let global_vertices = + vertices.each_ref_ext().map(|vertex: &Partial| { + let surface_vertex = vertex.read().surface_form.clone(); + let global_vertex = surface_vertex.read().global_form.clone(); + Some(global_vertex) + }); + + let global_form = global_form.unwrap_or_else(|| { + Partial::from_partial(PartialGlobalEdge::new( + Some(global_curve), + global_vertices, + )) + }); + + Self { + vertices, + global_form, + } + } + + /// Access the curve the partial edge is defined on pub fn curve(&self) -> Partial { - let [a, _] = &self.vertices; - a.read().curve.clone() + let [vertex, _] = &self.vertices; + vertex.read().curve.clone() } +} + +impl PartialObject for PartialHalfEdge { + type Full = HalfEdge; - /// Build a full [`HalfEdge`] from the partial half-edge - pub fn build(self, objects: &mut Service) -> HalfEdge { + fn from_full( + half_edge: &Self::Full, + cache: &mut FullToPartialCache, + ) -> Self { + Self::new( + half_edge + .vertices() + .clone() + .map(|vertex| Some(Partial::from_full(vertex, cache))), + Some(Partial::from_full(half_edge.global_form().clone(), cache)), + ) + } + + fn build(self, objects: &mut Service) -> Self::Full { let vertices = self.vertices.map(|vertex| vertex.build(objects)); let global_form = self.global_form.build(objects); @@ -33,62 +88,61 @@ impl PartialHalfEdge { } } -impl MergeWith for PartialHalfEdge { - fn merge_with(self, _: impl Into) -> Self { - Self { - vertices: self.vertices, - global_form: self.global_form, - } +impl Default for PartialHalfEdge { + fn default() -> Self { + Self::new([None, None], None) } } -impl From<&HalfEdge> for PartialHalfEdge { - fn from(half_edge: &HalfEdge) -> Self { - let [back_vertex, front_vertex] = half_edge - .vertices() - .clone() - .map(Partial::from_full_entry_point); +/// A partial [`GlobalEdge`] +#[derive(Clone, Debug)] +pub struct PartialGlobalEdge { + /// The curve that defines the edge's geometry + pub curve: Partial, - Self { - vertices: [back_vertex, front_vertex], - global_form: Partial::from_full_entry_point( - half_edge.global_form().clone(), - ), - } + /// The vertices that bound the edge on the curve + pub vertices: [Partial; 2], +} + +impl PartialGlobalEdge { + /// Construct an instance of `PartialGlobalEdge` + pub fn new( + curve: Option>, + vertices: [Option>; 2], + ) -> Self { + let curve = curve.unwrap_or_default(); + let vertices = vertices.map(Option::unwrap_or_default); + + Self { curve, vertices } } } -impl MaybePartial { - /// Access the curve - pub fn curve(&self) -> Partial { - match self { - Self::Full(full) => { - Partial::from_full_entry_point(full.curve().clone()) - } - Self::Partial(partial) => partial.curve(), - } +impl PartialObject for PartialGlobalEdge { + type Full = GlobalEdge; + + fn from_full( + global_edge: &Self::Full, + cache: &mut FullToPartialCache, + ) -> Self { + Self::new( + Some(Partial::from_full(global_edge.curve().clone(), cache)), + global_edge + .vertices() + .access_in_normalized_order() + .map(|vertex| Some(Partial::from_full(vertex, cache))), + ) } - /// Access the front vertex - pub fn front(&self) -> Partial { - match self { - Self::Full(full) => { - Partial::from_full_entry_point(full.front().clone()) - } - Self::Partial(partial) => { - let [_, front] = &partial.vertices; - front.clone() - } - } + fn build(self, objects: &mut Service) -> Self::Full { + let curve = self.curve.build(objects); + let vertices = self.vertices.map(|vertex| vertex.build(objects)); + + GlobalEdge::new(curve, vertices) } +} - /// Access the vertices - pub fn vertices(&self) -> [Partial; 2] { - match self { - Self::Full(full) => { - full.vertices().clone().map(Partial::from_full_entry_point) - } - Self::Partial(partial) => partial.vertices.clone(), - } +impl Default for PartialGlobalEdge { + fn default() -> Self { + Self::new(None, [None, None]) } } diff --git a/crates/fj-kernel/src/partial/objects/face.rs b/crates/fj-kernel/src/partial/objects/face.rs index 7d81eb242..28de124da 100644 --- a/crates/fj-kernel/src/partial/objects/face.rs +++ b/crates/fj-kernel/src/partial/objects/face.rs @@ -1,102 +1,68 @@ use fj_interop::mesh::Color; use crate::{ - objects::{Cycle, Face, Objects, Surface}, - partial::{MaybePartial, MergeWith, Mergeable}, - partial2::Partial, + objects::{Cycle, Face, Objects}, + partial::{FullToPartialCache, Partial, PartialObject}, services::Service, }; /// A partial [`Face`] -/// -/// See [`crate::partial`] for more information. -#[derive(Clone, Debug, Default)] +#[derive(Clone, Debug)] pub struct PartialFace { - exterior: MaybePartial, - interiors: Vec>, - color: Option, -} - -impl PartialFace { - /// Access th surface that the [`Face`] is defined in - pub fn surface(&self) -> Option> { - self.exterior.surface() - } - - /// Access the [`Face`]'s exterior cycle - pub fn exterior(&self) -> MaybePartial { - self.exterior.clone() - } + /// The cycle that bounds the face on the outside + pub exterior: Partial, - /// Access the [`Face`]'s interior cycles - pub fn interiors(&self) -> impl Iterator> + '_ { - self.interiors.iter().cloned() - } + /// The cycles that bound the face on the inside + /// + /// Each of these cycles defines a hole in the face. + pub interiors: Vec>, - /// Access the color of the [`Face`] - pub fn color(&self) -> Option { - self.color - } + /// The color of the face + pub color: Option, +} - /// Build the [`Face`] with the provided exterior - pub fn with_exterior( - mut self, - exterior: impl Into>, +impl PartialFace { + /// Construct an instance of `PartialFace` + pub fn new( + exterior: Option>, + interiors: Vec>, + color: Option, ) -> Self { - self.exterior = exterior.into(); - self - } + let exterior = exterior.unwrap_or_default(); - /// Build the [`Face`] with the provided interior polygons - pub fn with_interiors( - mut self, - interiors: impl IntoIterator>>, - ) -> Self { - let interiors = interiors.into_iter().map(Into::into); - self.interiors.extend(interiors); - self + Self { + exterior, + interiors, + color, + } } +} - /// Build the [`Face`] with the provided color - pub fn with_color(mut self, color: Color) -> Self { - self.color = Some(color); - self +impl PartialObject for PartialFace { + type Full = Face; + + fn from_full(face: &Self::Full, cache: &mut FullToPartialCache) -> Self { + Self::new( + Some(Partial::from_full(face.exterior().clone(), cache)), + face.interiors() + .map(|cycle| Partial::from_full(cycle.clone(), cache)) + .collect(), + Some(face.color()), + ) } - /// Construct a polygon from a list of points - pub fn build(self, objects: &mut Service) -> Face { - let exterior = self.exterior.into_full(objects); - let interiors = self - .interiors - .into_iter() - .map(|cycle| cycle.into_full(objects)) - .collect::>(); + fn build(self, objects: &mut Service) -> Self::Full { + let exterior = self.exterior.build(objects); + let interiors = + self.interiors.into_iter().map(|cycle| cycle.build(objects)); let color = self.color.unwrap_or_default(); Face::new(exterior, interiors, color) } } -impl MergeWith for PartialFace { - fn merge_with(self, other: impl Into) -> Self { - let other = other.into(); - - Self { - exterior: self.exterior.merge_with(other.exterior), - interiors: Mergeable(self.interiors) - .merge_with(Mergeable(other.interiors)) - .0, - color: self.color.merge_with(other.color), - } - } -} - -impl From<&Face> for PartialFace { - fn from(face: &Face) -> Self { - Self { - exterior: face.exterior().clone().into(), - interiors: face.interiors().cloned().map(Into::into).collect(), - color: Some(face.color()), - } +impl Default for PartialFace { + fn default() -> Self { + Self::new(None, Vec::new(), None) } } diff --git a/crates/fj-kernel/src/partial/objects/mod.rs b/crates/fj-kernel/src/partial/objects/mod.rs index 9a372e62b..1c2e5d303 100644 --- a/crates/fj-kernel/src/partial/objects/mod.rs +++ b/crates/fj-kernel/src/partial/objects/mod.rs @@ -1,43 +1,9 @@ +pub mod curve; pub mod cycle; pub mod edge; pub mod face; - -use crate::{ - objects::{Cycle, Face, HalfEdge, Objects}, - services::Service, -}; - -use super::{ - HasPartial, MaybePartial, Partial, PartialCycle, PartialFace, - PartialHalfEdge, -}; - -macro_rules! impl_traits { - ($($full:ty, $partial:ty;)*) => { - $( - impl HasPartial for $full { - type Partial = $partial; - } - - impl Partial for $partial { - type Full = $full; - - fn build(self, objects: &mut Service) -> Self::Full { - self.build(objects) - } - } - - impl From<$partial> for MaybePartial<$full> { - fn from(partial: $partial) -> Self { - Self::Partial(partial) - } - } - )* - }; -} - -impl_traits!( - Cycle, PartialCycle; - Face, PartialFace; - HalfEdge, PartialHalfEdge; -); +pub mod shell; +pub mod sketch; +pub mod solid; +pub mod surface; +pub mod vertex; diff --git a/crates/fj-kernel/src/partial2/objects/shell.rs b/crates/fj-kernel/src/partial/objects/shell.rs similarity index 94% rename from crates/fj-kernel/src/partial2/objects/shell.rs rename to crates/fj-kernel/src/partial/objects/shell.rs index 6d2751825..e13275690 100644 --- a/crates/fj-kernel/src/partial2/objects/shell.rs +++ b/crates/fj-kernel/src/partial/objects/shell.rs @@ -1,6 +1,6 @@ use crate::{ objects::{Face, Objects, Shell}, - partial2::{FullToPartialCache, Partial, PartialObject}, + partial::{FullToPartialCache, Partial, PartialObject}, services::Service, }; diff --git a/crates/fj-kernel/src/partial2/objects/sketch.rs b/crates/fj-kernel/src/partial/objects/sketch.rs similarity index 94% rename from crates/fj-kernel/src/partial2/objects/sketch.rs rename to crates/fj-kernel/src/partial/objects/sketch.rs index f7a2f25e6..c0b239b3a 100644 --- a/crates/fj-kernel/src/partial2/objects/sketch.rs +++ b/crates/fj-kernel/src/partial/objects/sketch.rs @@ -1,6 +1,6 @@ use crate::{ objects::{Face, Objects, Sketch}, - partial2::{FullToPartialCache, Partial, PartialObject}, + partial::{FullToPartialCache, Partial, PartialObject}, services::Service, }; diff --git a/crates/fj-kernel/src/partial2/objects/solid.rs b/crates/fj-kernel/src/partial/objects/solid.rs similarity index 94% rename from crates/fj-kernel/src/partial2/objects/solid.rs rename to crates/fj-kernel/src/partial/objects/solid.rs index 4d81b098e..557c15b80 100644 --- a/crates/fj-kernel/src/partial2/objects/solid.rs +++ b/crates/fj-kernel/src/partial/objects/solid.rs @@ -1,6 +1,6 @@ use crate::{ objects::{Objects, Shell, Solid}, - partial2::{FullToPartialCache, Partial, PartialObject}, + partial::{FullToPartialCache, Partial, PartialObject}, services::Service, }; diff --git a/crates/fj-kernel/src/partial2/objects/surface.rs b/crates/fj-kernel/src/partial/objects/surface.rs similarity index 94% rename from crates/fj-kernel/src/partial2/objects/surface.rs rename to crates/fj-kernel/src/partial/objects/surface.rs index 547967786..96ad6edf7 100644 --- a/crates/fj-kernel/src/partial2/objects/surface.rs +++ b/crates/fj-kernel/src/partial/objects/surface.rs @@ -1,7 +1,7 @@ use crate::{ geometry::surface::SurfaceGeometry, objects::{Objects, Surface}, - partial2::{FullToPartialCache, PartialObject}, + partial::{FullToPartialCache, PartialObject}, services::Service, }; diff --git a/crates/fj-kernel/src/partial2/objects/vertex.rs b/crates/fj-kernel/src/partial/objects/vertex.rs similarity index 98% rename from crates/fj-kernel/src/partial2/objects/vertex.rs rename to crates/fj-kernel/src/partial/objects/vertex.rs index e8bb7a667..eb4ece440 100644 --- a/crates/fj-kernel/src/partial2/objects/vertex.rs +++ b/crates/fj-kernel/src/partial/objects/vertex.rs @@ -3,7 +3,7 @@ use fj_math::Point; use crate::{ builder::SurfaceVertexBuilder, objects::{Curve, GlobalVertex, Objects, Surface, SurfaceVertex, Vertex}, - partial2::{FullToPartialCache, Partial, PartialCurve, PartialObject}, + partial::{FullToPartialCache, Partial, PartialCurve, PartialObject}, services::Service, }; diff --git a/crates/fj-kernel/src/partial/replace.rs b/crates/fj-kernel/src/partial/replace.rs deleted file mode 100644 index 180729979..000000000 --- a/crates/fj-kernel/src/partial/replace.rs +++ /dev/null @@ -1,20 +0,0 @@ -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-kernel/src/partial/traits.rs b/crates/fj-kernel/src/partial/traits.rs index 920b13aab..6b155e9d5 100644 --- a/crates/fj-kernel/src/partial/traits.rs +++ b/crates/fj-kernel/src/partial/traits.rs @@ -1,67 +1,49 @@ +use std::fmt::Debug; + use crate::{objects::Objects, services::Service}; -/// Implemented for objects that a partial object type exists for +use super::FullToPartialCache; + +/// Implemented for objects that a partial object variant exists for pub trait HasPartial { /// The type representing the partial variant of this object - type Partial: Partial; - - /// Create an empty partial variant of this object - /// - /// This function exists just for convenience, and will just return a - /// [`Default`] version of the partial object. - fn partial() -> Self::Partial { - Self::Partial::default() - } - - /// Convert this object into its partial variant - /// - /// All fields of the partial variant are set from this object. This is - /// useful when creating a new object that needs to share parts of an - /// existing one. - fn to_partial(&self) -> Self::Partial { - self.into() - } + type Partial: PartialObject; } /// Implemented for partial objects -/// -/// The API for partial objects follows a specific style: -/// -/// - Partial objects are structs with fields that mirror the fields of the full -/// object structs, but all fields are optional. -/// - Partial object structs have `with_*` methods to provide values for each of -/// their fields. -/// - Values provided to `with_*` are usually wrapped in an `Option`, and only a -/// `Some(...)` value has any effect. This is a trade-off that makes most use -/// cases slightly more verbose, while significantly simplifying more complex -/// use cases. -/// - Partial object structs may have other methods with prefixes like `as_*`, -/// `from_*`, or similar, if one or more of their fields can be initialized by -/// providing alternative data. -/// - Partial object structs have a `build` method to build a full object. -/// - All `with_*`, `as_*`, and `build` methods can be chained, to provide a -/// convenient API. -/// -/// # Implementation Note -/// -/// It would be nicer to require an [`Into`] bound instead of [`From`] (see -/// documentation of those types for more information). Unfortunately, this -/// doesn't seem to be possible without a `where` clause on `HasPartial`, which -/// significantly reduces the convenience of using that trait, as the `where` -/// clause needs to be repeated everywhere `HasPartial` is specialized as a -/// bound. -pub trait Partial: Default + for<'a> From<&'a Self::Full> { - /// The type representing the full variant of this object - type Full; +pub trait PartialObject: Clone + Debug + Default { + /// The type representing the full object + type Full: HasPartial; - /// Build a full object from this partial one - /// - /// Implementations of this method will typically try to infer any missing - /// parts of the partial object, but this is not possible in all cases. In - /// such cases, implementations of this method may panic. - /// - /// Calling `build` on a partial object that can't infer its missing parts - /// is considered a programmer error, hence why this method doesn't return a - /// [`Result`]. + /// Construct a partial object from a full one + fn from_full(full: &Self::Full, cache: &mut FullToPartialCache) -> Self; + + /// Build a full object from the partial object fn build(self, objects: &mut Service) -> Self::Full; } + +macro_rules! impl_trait { + ($($full:ident, $partial:ident;)*) => { + $( + impl HasPartial for crate::objects::$full { + type Partial = super::$partial; + } + )* + }; +} + +impl_trait!( + Curve, PartialCurve; + Cycle, PartialCycle; + Face, PartialFace; + GlobalCurve, PartialGlobalCurve; + GlobalEdge, PartialGlobalEdge; + GlobalVertex, PartialGlobalVertex; + HalfEdge, PartialHalfEdge; + Shell, PartialShell; + Sketch, PartialSketch; + Solid, PartialSolid; + Surface, PartialSurface; + SurfaceVertex, PartialSurfaceVertex; + Vertex, PartialVertex; +); diff --git a/crates/fj-kernel/src/partial2/wrapper.rs b/crates/fj-kernel/src/partial/wrapper.rs similarity index 99% rename from crates/fj-kernel/src/partial2/wrapper.rs rename to crates/fj-kernel/src/partial/wrapper.rs index c9a69cdb4..46c9dbf8b 100644 --- a/crates/fj-kernel/src/partial2/wrapper.rs +++ b/crates/fj-kernel/src/partial/wrapper.rs @@ -12,7 +12,7 @@ use type_map::TypeMap; use crate::{ insert::Insert, objects::Objects, - partial2::traits::PartialObject, + partial::traits::PartialObject, services::Service, storage::{Handle, ObjectId}, }; diff --git a/crates/fj-kernel/src/partial2/mod.rs b/crates/fj-kernel/src/partial2/mod.rs deleted file mode 100644 index 9ca5d0cc5..000000000 --- a/crates/fj-kernel/src/partial2/mod.rs +++ /dev/null @@ -1,31 +0,0 @@ -//! Partially defined objects -//! -//! This module contains types that mirror the full object types from -//! [`crate::objects`], only the types from this module can be defined only -//! partially, with the non-defined parts being inferred when a full object is -//! constructed. -//! -//! # Implementation Note -//! -//! This API was created as a replacement for the [original partial object -//! API][crate::partial]. This is still a work in progress. - -mod objects; -mod traits; -mod wrapper; - -pub use self::{ - objects::{ - curve::{PartialCurve, PartialGlobalCurve}, - cycle::PartialCycle, - edge::{PartialGlobalEdge, PartialHalfEdge}, - face::PartialFace, - shell::PartialShell, - sketch::PartialSketch, - solid::PartialSolid, - surface::PartialSurface, - vertex::{PartialGlobalVertex, PartialSurfaceVertex, PartialVertex}, - }, - traits::{HasPartial, PartialObject}, - wrapper::{FullToPartialCache, Partial}, -}; diff --git a/crates/fj-kernel/src/partial2/objects/cycle.rs b/crates/fj-kernel/src/partial2/objects/cycle.rs deleted file mode 100644 index e3b9a5de8..000000000 --- a/crates/fj-kernel/src/partial2/objects/cycle.rs +++ /dev/null @@ -1,48 +0,0 @@ -use crate::{ - objects::{Cycle, HalfEdge, Objects}, - partial2::{FullToPartialCache, Partial, PartialObject}, - services::Service, -}; - -/// A partial [`Cycle`] -#[derive(Clone, Debug)] -pub struct PartialCycle { - /// The half-edges that make up the cycle - pub half_edges: Vec>, -} - -impl PartialCycle { - /// Construct an instance of `PartialCycle` - pub fn new(half_edges: Vec>) -> Self { - Self { half_edges } - } -} - -impl PartialObject for PartialCycle { - type Full = Cycle; - - fn from_full(cycle: &Self::Full, cache: &mut FullToPartialCache) -> Self { - Self::new( - cycle - .half_edges() - .cloned() - .map(|half_edge| Partial::from_full(half_edge, cache)) - .collect(), - ) - } - - fn build(self, objects: &mut Service) -> Self::Full { - let half_edges = self - .half_edges - .into_iter() - .map(|half_edge| half_edge.build(objects)); - - Cycle::new(half_edges) - } -} - -impl Default for PartialCycle { - fn default() -> Self { - Self::new(Vec::new()) - } -} diff --git a/crates/fj-kernel/src/partial2/objects/edge.rs b/crates/fj-kernel/src/partial2/objects/edge.rs deleted file mode 100644 index be089448d..000000000 --- a/crates/fj-kernel/src/partial2/objects/edge.rs +++ /dev/null @@ -1,142 +0,0 @@ -use fj_interop::ext::ArrayExt; - -use crate::{ - objects::{ - Curve, GlobalCurve, GlobalEdge, GlobalVertex, HalfEdge, Objects, Vertex, - }, - partial2::{FullToPartialCache, Partial, PartialObject, PartialVertex}, - services::Service, -}; - -/// A partial [`HalfEdge`] -#[derive(Clone, Debug)] -pub struct PartialHalfEdge { - /// The vertices that bound the half-edge on the curve - pub vertices: [Partial; 2], - - /// The global form of the half-edge - pub global_form: Partial, -} - -impl PartialHalfEdge { - /// Construct an instance of `PartialHalfEdge` - pub fn new( - vertices: [Option>; 2], - global_form: Option>, - ) -> Self { - let curve = Partial::::new(); - - let vertices = vertices.map(|vertex| { - vertex.unwrap_or_else(|| { - Partial::from_partial(PartialVertex::new( - None, - Some(curve.clone()), - None, - )) - }) - }); - - let global_curve = curve.read().global_form.clone(); - let global_vertices = - vertices.each_ref_ext().map(|vertex: &Partial| { - let surface_vertex = vertex.read().surface_form.clone(); - let global_vertex = surface_vertex.read().global_form.clone(); - Some(global_vertex) - }); - - let global_form = global_form.unwrap_or_else(|| { - Partial::from_partial(PartialGlobalEdge::new( - Some(global_curve), - global_vertices, - )) - }); - - Self { - vertices, - global_form, - } - } -} - -impl PartialObject for PartialHalfEdge { - type Full = HalfEdge; - - fn from_full( - half_edge: &Self::Full, - cache: &mut FullToPartialCache, - ) -> Self { - Self::new( - half_edge - .vertices() - .clone() - .map(|vertex| Some(Partial::from_full(vertex, cache))), - Some(Partial::from_full(half_edge.global_form().clone(), cache)), - ) - } - - fn build(self, objects: &mut Service) -> Self::Full { - let vertices = self.vertices.map(|vertex| vertex.build(objects)); - let global_form = self.global_form.build(objects); - - HalfEdge::new(vertices, global_form) - } -} - -impl Default for PartialHalfEdge { - fn default() -> Self { - Self::new([None, None], None) - } -} - -/// A partial [`GlobalEdge`] -#[derive(Clone, Debug)] -pub struct PartialGlobalEdge { - /// The curve that defines the edge's geometry - pub curve: Partial, - - /// The vertices that bound the edge on the curve - pub vertices: [Partial; 2], -} - -impl PartialGlobalEdge { - /// Construct an instance of `PartialGlobalEdge` - pub fn new( - curve: Option>, - vertices: [Option>; 2], - ) -> Self { - let curve = curve.unwrap_or_default(); - let vertices = vertices.map(Option::unwrap_or_default); - - Self { curve, vertices } - } -} - -impl PartialObject for PartialGlobalEdge { - type Full = GlobalEdge; - - fn from_full( - global_edge: &Self::Full, - cache: &mut FullToPartialCache, - ) -> Self { - Self::new( - Some(Partial::from_full(global_edge.curve().clone(), cache)), - global_edge - .vertices() - .access_in_normalized_order() - .map(|vertex| Some(Partial::from_full(vertex, cache))), - ) - } - - fn build(self, objects: &mut Service) -> Self::Full { - let curve = self.curve.build(objects); - let vertices = self.vertices.map(|vertex| vertex.build(objects)); - - GlobalEdge::new(curve, vertices) - } -} - -impl Default for PartialGlobalEdge { - fn default() -> Self { - Self::new(None, [None, None]) - } -} diff --git a/crates/fj-kernel/src/partial2/objects/face.rs b/crates/fj-kernel/src/partial2/objects/face.rs deleted file mode 100644 index b202bba95..000000000 --- a/crates/fj-kernel/src/partial2/objects/face.rs +++ /dev/null @@ -1,68 +0,0 @@ -use fj_interop::mesh::Color; - -use crate::{ - objects::{Cycle, Face, Objects}, - partial2::{FullToPartialCache, Partial, PartialObject}, - services::Service, -}; - -/// A partial [`Face`] -#[derive(Clone, Debug)] -pub struct PartialFace { - /// The cycle that bounds the face on the outside - pub exterior: Partial, - - /// The cycles that bound the face on the inside - /// - /// Each of these cycles defines a hole in the face. - pub interiors: Vec>, - - /// The color of the face - pub color: Option, -} - -impl PartialFace { - /// Construct an instance of `PartialFace` - pub fn new( - exterior: Option>, - interiors: Vec>, - color: Option, - ) -> Self { - let exterior = exterior.unwrap_or_default(); - - Self { - exterior, - interiors, - color, - } - } -} - -impl PartialObject for PartialFace { - type Full = Face; - - fn from_full(face: &Self::Full, cache: &mut FullToPartialCache) -> Self { - Self::new( - Some(Partial::from_full(face.exterior().clone(), cache)), - face.interiors() - .map(|cycle| Partial::from_full(cycle.clone(), cache)) - .collect(), - Some(face.color()), - ) - } - - fn build(self, objects: &mut Service) -> Self::Full { - let exterior = self.exterior.build(objects); - let interiors = - self.interiors.into_iter().map(|cycle| cycle.build(objects)); - let color = self.color.unwrap_or_default(); - - Face::new(exterior, interiors, color) - } -} - -impl Default for PartialFace { - fn default() -> Self { - Self::new(None, Vec::new(), None) - } -} diff --git a/crates/fj-kernel/src/partial2/objects/mod.rs b/crates/fj-kernel/src/partial2/objects/mod.rs deleted file mode 100644 index 1c2e5d303..000000000 --- a/crates/fj-kernel/src/partial2/objects/mod.rs +++ /dev/null @@ -1,9 +0,0 @@ -pub mod curve; -pub mod cycle; -pub mod edge; -pub mod face; -pub mod shell; -pub mod sketch; -pub mod solid; -pub mod surface; -pub mod vertex; diff --git a/crates/fj-kernel/src/partial2/traits.rs b/crates/fj-kernel/src/partial2/traits.rs deleted file mode 100644 index 6b155e9d5..000000000 --- a/crates/fj-kernel/src/partial2/traits.rs +++ /dev/null @@ -1,49 +0,0 @@ -use std::fmt::Debug; - -use crate::{objects::Objects, services::Service}; - -use super::FullToPartialCache; - -/// Implemented for objects that a partial object variant exists for -pub trait HasPartial { - /// The type representing the partial variant of this object - type Partial: PartialObject; -} - -/// Implemented for partial objects -pub trait PartialObject: Clone + Debug + Default { - /// The type representing the full object - type Full: HasPartial; - - /// Construct a partial object from a full one - fn from_full(full: &Self::Full, cache: &mut FullToPartialCache) -> Self; - - /// Build a full object from the partial object - fn build(self, objects: &mut Service) -> Self::Full; -} - -macro_rules! impl_trait { - ($($full:ident, $partial:ident;)*) => { - $( - impl HasPartial for crate::objects::$full { - type Partial = super::$partial; - } - )* - }; -} - -impl_trait!( - Curve, PartialCurve; - Cycle, PartialCycle; - Face, PartialFace; - GlobalCurve, PartialGlobalCurve; - GlobalEdge, PartialGlobalEdge; - GlobalVertex, PartialGlobalVertex; - HalfEdge, PartialHalfEdge; - Shell, PartialShell; - Sketch, PartialSketch; - Solid, PartialSolid; - Surface, PartialSurface; - SurfaceVertex, PartialSurfaceVertex; - Vertex, PartialVertex; -); diff --git a/crates/fj-kernel/src/validate/cycle.rs b/crates/fj-kernel/src/validate/cycle.rs index afcd1f375..82cf04de6 100644 --- a/crates/fj-kernel/src/validate/cycle.rs +++ b/crates/fj-kernel/src/validate/cycle.rs @@ -66,8 +66,10 @@ impl CycleValidationError { #[cfg(test)] mod tests { use crate::{ - builder::CycleBuilder, insert::Insert, objects::Cycle, - partial::HasPartial, partial2::Partial, services::Services, + builder::CycleBuilder, + objects::Cycle, + partial::{Partial, PartialCycle, PartialObject}, + services::Services, validate::Validate, }; @@ -75,7 +77,7 @@ mod tests { fn cycle_half_edge_connections() { let mut services = Services::new(); - let valid = Cycle::partial() + let valid = PartialCycle::default() .with_poly_chain_from_points( services.objects.surfaces.xy_plane(), [[0., 0.], [1., 0.], [0., 1.]], @@ -85,23 +87,25 @@ mod tests { let invalid = { let mut half_edges = valid .half_edges() - .map(|half_edge| half_edge.to_partial()) + .map(|half_edge| { + Partial::from_full_entry_point(half_edge.clone()) + }) .collect::>(); // Sever connection between the last and first half-edge in the // cycle. - let first_half_edge = half_edges.first_mut().unwrap(); - let [first_vertex, _] = &mut first_half_edge.vertices; - let surface_vertex = Partial::from_partial( - first_vertex.read().surface_form.read().clone(), - ); - first_vertex.write().surface_form = surface_vertex; - - let half_edges = half_edges.into_iter().map(|half_edge| { - half_edge - .build(&mut services.objects) - .insert(&mut services.objects) - }); + { + let first_half_edge = half_edges.first_mut().unwrap(); + let [first_vertex, _] = &mut first_half_edge.write().vertices; + let surface_vertex = Partial::from_partial( + first_vertex.read().surface_form.read().clone(), + ); + first_vertex.write().surface_form = surface_vertex; + } + + let half_edges = half_edges + .into_iter() + .map(|half_edge| half_edge.build(&mut services.objects)); Cycle::new(half_edges) }; diff --git a/crates/fj-kernel/src/validate/edge.rs b/crates/fj-kernel/src/validate/edge.rs index 019eeee1a..8008fd674 100644 --- a/crates/fj-kernel/src/validate/edge.rs +++ b/crates/fj-kernel/src/validate/edge.rs @@ -206,10 +206,9 @@ mod tests { builder::HalfEdgeBuilder, insert::Insert, objects::{GlobalCurve, HalfEdge, Vertex}, - partial::PartialHalfEdge, - partial2::{ - Partial, PartialGlobalEdge, PartialObject, PartialSurfaceVertex, - PartialVertex, + partial::{ + Partial, PartialGlobalEdge, PartialHalfEdge, PartialObject, + PartialSurfaceVertex, PartialVertex, }, services::Services, validate::Validate, diff --git a/crates/fj-kernel/src/validate/face.rs b/crates/fj-kernel/src/validate/face.rs index 67208e1ea..80795932b 100644 --- a/crates/fj-kernel/src/validate/face.rs +++ b/crates/fj-kernel/src/validate/face.rs @@ -107,8 +107,8 @@ mod tests { algorithms::reverse::Reverse, builder::{CycleBuilder, FaceBuilder}, insert::Insert, - objects::{Cycle, Face}, - partial::HasPartial, + objects::Face, + partial::{PartialCycle, PartialFace, PartialObject}, services::Services, validate::Validate, }; @@ -119,7 +119,7 @@ mod tests { let surface = services.objects.surfaces.xy_plane(); - let valid = Face::partial() + let valid = PartialFace::default() .with_exterior_polygon_from_points( surface.clone(), [[0., 0.], [3., 0.], [0., 3.]], @@ -130,7 +130,7 @@ mod tests { ) .build(&mut services.objects); let invalid = { - let interiors = [Cycle::partial() + let interiors = [PartialCycle::default() .with_poly_chain_from_points( services.objects.surfaces.xz_plane(), [[1., 1.], [1., 2.], [2., 1.]], @@ -152,7 +152,7 @@ mod tests { let surface = services.objects.surfaces.xy_plane(); - let valid = Face::partial() + let valid = PartialFace::default() .with_exterior_polygon_from_points( surface.clone(), [[0., 0.], [3., 0.], [0., 3.]], diff --git a/crates/fj-kernel/src/validate/vertex.rs b/crates/fj-kernel/src/validate/vertex.rs index baf9a884a..bfa1cc5bc 100644 --- a/crates/fj-kernel/src/validate/vertex.rs +++ b/crates/fj-kernel/src/validate/vertex.rs @@ -183,7 +183,7 @@ mod tests { builder::{CurveBuilder, SurfaceVertexBuilder}, insert::Insert, objects::{GlobalVertex, SurfaceVertex, Vertex}, - partial2::{ + partial::{ Partial, PartialCurve, PartialObject, PartialSurfaceVertex, PartialVertex, }, diff --git a/crates/fj-operations/src/difference_2d.rs b/crates/fj-operations/src/difference_2d.rs index 41e43a8af..a3ac475d3 100644 --- a/crates/fj-operations/src/difference_2d.rs +++ b/crates/fj-operations/src/difference_2d.rs @@ -5,8 +5,8 @@ use fj_kernel::{ algorithms::reverse::Reverse, insert::Insert, iter::ObjectIters, - objects::{Face, Objects, Sketch}, - partial::HasPartial, + objects::{Objects, Sketch}, + partial::{Partial, PartialFace, PartialObject}, services::Service, }; use fj_math::Aabb; @@ -48,7 +48,9 @@ impl Shape for fj::Difference2d { exteriors.push(face.exterior().clone()); for cycle in face.interiors() { - interiors.push(cycle.clone().reverse(objects)); + interiors.push(Partial::from_full_entry_point( + cycle.clone().reverse(objects), + )); } } @@ -59,7 +61,9 @@ impl Shape for fj::Difference2d { "Trying to subtract faces with different surfaces.", ); - interiors.push(face.exterior().clone().reverse(objects)); + interiors.push(Partial::from_full_entry_point( + face.exterior().clone().reverse(objects), + )); } // Faces only support one exterior, while the code here comes from @@ -79,14 +83,12 @@ impl Shape for fj::Difference2d { "Can't construct face with multiple exteriors" ); - faces.push( - Face::partial() - .with_exterior(exterior) - .with_interiors(interiors) - .with_color(Color(self.color())) - .build(objects) - .insert(objects), - ); + let face = PartialFace { + exterior: Partial::from_full_entry_point(exterior), + interiors, + color: Some(Color(self.color())), + }; + faces.push(face.build(objects).insert(objects)); } let difference = Sketch::builder().with_faces(faces).build(objects); diff --git a/crates/fj-operations/src/sketch.rs b/crates/fj-operations/src/sketch.rs index 1c14c94fc..e92e3addf 100644 --- a/crates/fj-operations/src/sketch.rs +++ b/crates/fj-operations/src/sketch.rs @@ -4,11 +4,10 @@ use fj_interop::{debug::DebugInfo, ext::ArrayExt, mesh::Color}; use fj_kernel::{ builder::{FaceBuilder, HalfEdgeBuilder}, insert::Insert, - objects::{Cycle, Face, Objects, Sketch, Vertex}, - partial::{HasPartial, PartialHalfEdge}, - partial2::{ - Partial, PartialCurve, PartialGlobalEdge, PartialSurfaceVertex, - PartialVertex, + objects::{Objects, Sketch, Vertex}, + partial::{ + Partial, PartialCurve, PartialCycle, PartialFace, PartialGlobalEdge, + PartialHalfEdge, PartialObject, PartialSurfaceVertex, PartialVertex, }, services::Service, }; @@ -67,18 +66,19 @@ impl Shape for fj::Sketch { vertices: global_vertices, }), }; - half_edge - .update_as_circle_from_radius(circle.radius()) - .build(objects) - .insert(objects) + Partial::from_partial( + half_edge.update_as_circle_from_radius(circle.radius()), + ) }; - let cycle = Cycle::new([half_edge]).insert(objects); + let cycle = + Partial::from_partial(PartialCycle::new(vec![half_edge])); - Face::partial() - .with_exterior(cycle) - .with_color(Color(self.color())) - .build(objects) - .insert(objects) + let face = PartialFace { + exterior: cycle, + color: Some(Color(self.color())), + ..Default::default() + }; + face.build(objects).insert(objects) } fj::Chain::PolyChain(poly_chain) => { let points = poly_chain @@ -87,11 +87,11 @@ impl Shape for fj::Sketch { .map(|fj::SketchSegment::LineTo { point }| point) .map(Point::from); - Face::partial() - .with_exterior_polygon_from_points(surface, points) - .with_color(Color(self.color())) - .build(objects) - .insert(objects) + let mut face = PartialFace::default() + .with_exterior_polygon_from_points(surface, points); + face.color = Some(Color(self.color())); + + face.build(objects).insert(objects) } };