diff --git a/crates/fj-kernel/src/algorithms/approx/curve.rs b/crates/fj-kernel/src/algorithms/approx/curve.rs index ae1c6b4d7..b8597a00c 100644 --- a/crates/fj-kernel/src/algorithms/approx/curve.rs +++ b/crates/fj-kernel/src/algorithms/approx/curve.rs @@ -13,13 +13,13 @@ use std::collections::BTreeMap; use crate::{ geometry::path::{GlobalPath, SurfacePath}, - objects::{Curve, GlobalCurve}, + objects::{Curve, GlobalCurve, Surface}, storage::{Handle, ObjectId}, }; use super::{path::RangeOnPath, Approx, ApproxPoint, Tolerance}; -impl Approx for (&Handle, RangeOnPath) { +impl Approx for (&Handle, &Surface, RangeOnPath) { type Approximation = CurveApprox; type Cache = CurveCache; @@ -28,13 +28,14 @@ impl Approx for (&Handle, RangeOnPath) { tolerance: impl Into, cache: &mut Self::Cache, ) -> Self::Approximation { - let (curve, range) = self; + let (curve, surface, range) = self; let global_curve = curve.global_form().clone(); let global_curve_approx = match cache.get(global_curve.clone(), range) { Some(approx) => approx, None => { - let approx = approx_global_curve(curve, range, tolerance); + let approx = + approx_global_curve(curve, surface, range, tolerance); cache.insert(global_curve, range, approx) } }; @@ -53,6 +54,7 @@ impl Approx for (&Handle, RangeOnPath) { fn approx_global_curve( curve: &Curve, + surface: &Surface, range: RangeOnPath, tolerance: impl Into, ) -> GlobalCurveApprox { @@ -62,7 +64,7 @@ fn approx_global_curve( // This will probably all be unified eventually, as `SurfacePath` and // `GlobalPath` grow APIs that are better suited to implementing this code // in a more abstract way. - let points = match (curve.path(), curve.surface().geometry().u) { + let points = match (curve.path(), surface.geometry().u) { (SurfacePath::Circle(_), GlobalPath::Circle(_)) => { todo!( "Approximating a circle on a curved surface not supported yet." @@ -88,8 +90,7 @@ fn approx_global_curve( // surface point available, so it needs to be computed // later anyway, in the general case. - let point_global = curve - .surface() + let point_global = surface .geometry() .point_from_surface_coords(point_surface); (point_curve, point_global) @@ -102,17 +103,15 @@ fn approx_global_curve( [curve.path().point_from_path_coords(point_curve).u] })); - let approx_u = (curve.surface().geometry().u, range_u) + let approx_u = (surface.geometry().u, range_u) .approx_with_cache(tolerance, &mut ()); let mut points = Vec::new(); for (u, _) in approx_u { let t = (u.t - line.origin().u) / line.direction().u; let point_surface = curve.path().point_from_path_coords([t]); - let point_global = curve - .surface() - .geometry() - .point_from_surface_coords(point_surface); + let point_global = + surface.geometry().point_from_surface_coords(point_surface); points.push((u, point_global)); } @@ -211,7 +210,7 @@ impl GlobalCurveApprox { #[cfg(test)] mod tests { - use std::f64::consts::TAU; + use std::{f64::consts::TAU, ops::Deref}; use pretty_assertions::assert_eq; @@ -220,7 +219,7 @@ mod tests { builder::{CurveBuilder, SurfaceBuilder}, geometry::path::GlobalPath, insert::Insert, - partial::{Partial, PartialCurve, PartialObject, PartialSurface}, + partial::{PartialCurve, PartialObject, PartialSurface}, services::Services, }; @@ -231,17 +230,14 @@ mod tests { let mut services = Services::new(); let surface = services.objects.surfaces.xz_plane(); - let mut curve = PartialCurve { - surface: Partial::from(surface), - ..Default::default() - }; + let mut curve = PartialCurve::default(); curve.update_as_line_from_points([[1., 1.], [2., 1.]]); let curve = curve .build(&mut services.objects) .insert(&mut services.objects); let range = RangeOnPath::from([[0.], [1.]]); - let approx = (&curve, range).approx(1.); + let approx = (&curve, surface.deref(), range).approx(1.); assert_eq!(approx, CurveApprox::empty()); } @@ -256,17 +252,14 @@ mod tests { ) .build(&mut services.objects) .insert(&mut services.objects); - let mut curve = PartialCurve { - surface: Partial::from(surface), - ..Default::default() - }; + let mut curve = PartialCurve::default(); curve.update_as_line_from_points([[1., 1.], [1., 2.]]); let curve = curve .build(&mut services.objects) .insert(&mut services.objects); let range = RangeOnPath::from([[0.], [1.]]); - let approx = (&curve, range).approx(1.); + let approx = (&curve, surface.deref(), range).approx(1.); assert_eq!(approx, CurveApprox::empty()); } @@ -279,10 +272,7 @@ mod tests { let surface = PartialSurface::from_axes(path, [0., 0., 1.]) .build(&mut services.objects) .insert(&mut services.objects); - let mut curve = PartialCurve { - surface: Partial::from(surface.clone()), - ..Default::default() - }; + let mut curve = PartialCurve::default(); curve.update_as_line_from_points([[0., 1.], [1., 1.]]); let curve = curve .build(&mut services.objects) @@ -291,7 +281,7 @@ mod tests { let range = RangeOnPath::from([[0.], [TAU]]); let tolerance = 1.; - let approx = (&curve, range).approx(tolerance); + let approx = (&curve, surface.deref(), range).approx(tolerance); let expected_approx = (path, range) .approx(tolerance) @@ -312,10 +302,7 @@ mod tests { let mut services = Services::new(); let surface = services.objects.surfaces.xz_plane(); - let mut curve = PartialCurve { - surface: Partial::from(surface), - ..Default::default() - }; + let mut curve = PartialCurve::default(); curve.update_as_circle_from_radius(1.); let curve = curve .build(&mut services.objects) @@ -323,16 +310,14 @@ mod tests { let range = RangeOnPath::from([[0.], [TAU]]); let tolerance = 1.; - let approx = (&curve, range).approx(tolerance); + let approx = (&curve, surface.deref(), range).approx(tolerance); let expected_approx = (curve.path(), range) .approx(tolerance) .into_iter() .map(|(_, point_surface)| { - let point_global = curve - .surface() - .geometry() - .point_from_surface_coords(point_surface); + let point_global = + surface.geometry().point_from_surface_coords(point_surface); ApproxPoint::new(point_surface, point_global) }) .collect::>(); diff --git a/crates/fj-kernel/src/algorithms/approx/edge.rs b/crates/fj-kernel/src/algorithms/approx/edge.rs index 41376dac7..2d74e66d5 100644 --- a/crates/fj-kernel/src/algorithms/approx/edge.rs +++ b/crates/fj-kernel/src/algorithms/approx/edge.rs @@ -5,6 +5,8 @@ //! approximations are usually used to build cycle approximations, and this way, //! the caller doesn't have to call with duplicate vertices. +use std::ops::Deref; + use crate::{objects::HalfEdge, storage::Handle}; use super::{ @@ -30,8 +32,8 @@ impl Approx for &Handle { self.start_vertex().global_form().position(), ) .with_source((self.clone(), self.boundary()[0])); - let curve_approx = - (self.curve(), range).approx_with_cache(tolerance, cache); + let curve_approx = (self.curve(), self.surface().deref(), range) + .approx_with_cache(tolerance, cache); HalfEdgeApprox { first, diff --git a/crates/fj-kernel/src/algorithms/intersect/curve_edge.rs b/crates/fj-kernel/src/algorithms/intersect/curve_edge.rs index eaaca63b5..d7ca55ac7 100644 --- a/crates/fj-kernel/src/algorithms/intersect/curve_edge.rs +++ b/crates/fj-kernel/src/algorithms/intersect/curve_edge.rs @@ -87,10 +87,7 @@ mod tests { let mut services = Services::new(); let surface = Partial::from(services.objects.surfaces.xy_plane()); - let mut curve = PartialCurve { - surface: surface.clone(), - ..Default::default() - }; + let mut curve = PartialCurve::default(); curve.update_as_u_axis(); let curve = curve.build(&mut services.objects); let half_edge = { @@ -118,10 +115,7 @@ mod tests { let mut services = Services::new(); let surface = Partial::from(services.objects.surfaces.xy_plane()); - let mut curve = PartialCurve { - surface: surface.clone(), - ..Default::default() - }; + let mut curve = PartialCurve::default(); curve.update_as_u_axis(); let curve = curve.build(&mut services.objects); let half_edge = { @@ -149,10 +143,7 @@ mod tests { let mut services = Services::new(); let surface = Partial::from(services.objects.surfaces.xy_plane()); - let mut curve = PartialCurve { - surface: surface.clone(), - ..Default::default() - }; + let mut curve = PartialCurve::default(); curve.update_as_u_axis(); let curve = curve.build(&mut services.objects); let half_edge = { @@ -175,10 +166,7 @@ mod tests { let mut services = Services::new(); let surface = Partial::from(services.objects.surfaces.xy_plane()); - let mut curve = PartialCurve { - surface: surface.clone(), - ..Default::default() - }; + let mut curve = PartialCurve::default(); curve.update_as_u_axis(); let curve = curve.build(&mut services.objects); let half_edge = { diff --git a/crates/fj-kernel/src/algorithms/intersect/curve_face.rs b/crates/fj-kernel/src/algorithms/intersect/curve_face.rs index 3724fb123..5e5048d89 100644 --- a/crates/fj-kernel/src/algorithms/intersect/curve_face.rs +++ b/crates/fj-kernel/src/algorithms/intersect/curve_face.rs @@ -163,10 +163,7 @@ mod tests { let surface = Partial::from(services.objects.surfaces.xy_plane()); - let mut curve = PartialCurve { - surface: surface.clone(), - ..Default::default() - }; + let mut curve = PartialCurve::default(); curve.update_as_line_from_points([[-3., 0.], [-2., 0.]]); let curve = curve.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 499aa0719..fcf233da8 100644 --- a/crates/fj-kernel/src/algorithms/intersect/face_face.rs +++ b/crates/fj-kernel/src/algorithms/intersect/face_face.rs @@ -132,11 +132,8 @@ mod tests { let intersection = FaceFaceIntersection::compute([&a, &b], &mut services.objects); - let expected_curves = surfaces.map(|surface| { - let mut curve = PartialCurve { - surface: Partial::from(surface), - ..Default::default() - }; + let expected_curves = surfaces.map(|_| { + let mut curve = PartialCurve::default(); curve.update_as_line_from_points([[0., 0.], [1., 0.]]); curve .build(&mut services.objects) diff --git a/crates/fj-kernel/src/algorithms/intersect/surface_surface.rs b/crates/fj-kernel/src/algorithms/intersect/surface_surface.rs index 53cb2d34f..48b37f882 100644 --- a/crates/fj-kernel/src/algorithms/intersect/surface_surface.rs +++ b/crates/fj-kernel/src/algorithms/intersect/surface_surface.rs @@ -27,14 +27,10 @@ impl SurfaceSurfaceIntersection { // Adaptations were made to get the intersection curves in local // coordinates for each surface. - let surfaces_and_planes = surfaces.map(|surface| { - let plane = plane_from_surface(&surface); - (surface, plane) - }); - let [a, b] = surfaces_and_planes.clone().map(|(_, plane)| plane); + let planes = surfaces.map(|surface| plane_from_surface(&surface)); - let (a_distance, a_normal) = a.constant_normal_form(); - let (b_distance, b_normal) = b.constant_normal_form(); + let [(a_distance, a_normal), (b_distance, b_normal)] = + planes.map(|plane| plane.constant_normal_form()); let direction = a_normal.cross(&b_normal); @@ -57,11 +53,11 @@ impl SurfaceSurfaceIntersection { let line = Line::from_origin_and_direction(origin, direction); - let curves = surfaces_and_planes.map(|(surface, plane)| { + let curves = planes.map(|plane| { let path = SurfacePath::Line(plane.project_line(&line)); let global_form = GlobalCurve.insert(objects); - Curve::new(surface, path, global_form).insert(objects) + Curve::new(path, global_form).insert(objects) }); Some(Self { @@ -92,7 +88,7 @@ mod tests { algorithms::transform::TransformObject, builder::CurveBuilder, insert::Insert, - partial::{Partial, PartialCurve, PartialObject}, + partial::{PartialCurve, PartialObject}, services::Services, }; @@ -120,18 +116,13 @@ mod tests { None, ); - let mut expected_xy = PartialCurve { - surface: Partial::from(xy.clone()), - ..Default::default() - }; + let mut expected_xy = PartialCurve::default(); expected_xy.update_as_u_axis(); let expected_xy = expected_xy .build(&mut services.objects) .insert(&mut services.objects); - let mut expected_xz = PartialCurve { - surface: Partial::from(xz.clone()), - ..Default::default() - }; + + let mut expected_xz = PartialCurve::default(); expected_xz.update_as_u_axis(); let expected_xz = expected_xz .build(&mut services.objects) diff --git a/crates/fj-kernel/src/algorithms/reverse/edge.rs b/crates/fj-kernel/src/algorithms/reverse/edge.rs index 1a9023356..721f77dc8 100644 --- a/crates/fj-kernel/src/algorithms/reverse/edge.rs +++ b/crates/fj-kernel/src/algorithms/reverse/edge.rs @@ -19,6 +19,7 @@ impl Reverse for Handle { }; HalfEdge::new( + self.surface().clone(), self.curve().clone(), vertices, self.global_form().clone(), diff --git a/crates/fj-kernel/src/algorithms/sweep/curve.rs b/crates/fj-kernel/src/algorithms/sweep/curve.rs index 3a4ba6cba..34d6a706b 100644 --- a/crates/fj-kernel/src/algorithms/sweep/curve.rs +++ b/crates/fj-kernel/src/algorithms/sweep/curve.rs @@ -12,7 +12,7 @@ use crate::{ use super::{Sweep, SweepCache}; -impl Sweep for Handle { +impl Sweep for (Handle, &Surface) { type Swept = Handle; fn sweep_with_cache( @@ -21,7 +21,9 @@ impl Sweep for Handle { _: &mut SweepCache, objects: &mut Service, ) -> Self::Swept { - match self.surface().geometry().u { + let (curve, surface) = self; + + match surface.geometry().u { GlobalPath::Circle(_) => { // Sweeping a `Curve` creates a `Surface`. The u-axis of that // `Surface` is a `GlobalPath`, which we are computing below. @@ -45,32 +47,24 @@ impl Sweep for Handle { } } - let u = match self.path() { + let u = match curve.path() { SurfacePath::Circle(circle) => { - let center = self - .surface() + let center = surface .geometry() .point_from_surface_coords(circle.center()); - let a = self - .surface() - .geometry() - .vector_from_surface_coords(circle.a()); - let b = self - .surface() - .geometry() - .vector_from_surface_coords(circle.b()); + let a = + surface.geometry().vector_from_surface_coords(circle.a()); + let b = + surface.geometry().vector_from_surface_coords(circle.b()); let circle = Circle::new(center, a, b); GlobalPath::Circle(circle) } SurfacePath::Line(line) => { - let origin = self - .surface() - .geometry() - .point_from_surface_coords(line.origin()); - let direction = self - .surface() + let origin = + surface.geometry().point_from_surface_coords(line.origin()); + let direction = surface .geometry() .vector_from_surface_coords(line.direction()); diff --git a/crates/fj-kernel/src/algorithms/sweep/edge.rs b/crates/fj-kernel/src/algorithms/sweep/edge.rs index e4319de67..7086b20f7 100644 --- a/crates/fj-kernel/src/algorithms/sweep/edge.rs +++ b/crates/fj-kernel/src/algorithms/sweep/edge.rs @@ -1,3 +1,5 @@ +use std::ops::Deref; + use fj_interop::{ext::ArrayExt, mesh::Color}; use fj_math::{Point, Scalar, Vector}; @@ -34,7 +36,8 @@ impl Sweep for (Handle, Color) { // be created by sweeping a curve, so let's sweep the curve of the edge // we're sweeping. face.exterior.write().surface = Partial::from( - edge.curve().clone().sweep_with_cache(path, cache, objects), + (edge.curve().clone(), edge.surface().deref()) + .sweep_with_cache(path, cache, objects), ); // Now we're ready to create the edges. @@ -194,7 +197,7 @@ mod tests { }; let side_up = { let mut side_up = PartialHalfEdge::default(); - side_up.curve.write().surface = surface.clone(); + side_up.replace_surface(surface.clone()); { let [back, front] = side_up @@ -206,7 +209,6 @@ mod tests { let mut front = front.write(); front.position = Some([1., 1.].into()); - front.surface = surface.clone(); } side_up.infer_global_form(); @@ -216,7 +218,7 @@ mod tests { }; let top = { let mut top = PartialHalfEdge::default(); - top.curve.write().surface = surface.clone(); + top.replace_surface(surface.clone()); { let [(back, back_surface), (front, front_surface)] = @@ -228,7 +230,6 @@ mod tests { *front = Some(Point::from([0.])); let mut front_surface = front_surface.write(); front_surface.position = Some([0., 1.].into()); - front_surface.surface = surface.clone(); } top.infer_global_form(); @@ -243,7 +244,7 @@ mod tests { }; let side_down = { let mut side_down = PartialHalfEdge::default(); - side_down.curve.write().surface = surface; + side_down.replace_surface(surface); let [(back, back_surface), (front, front_surface)] = side_down.vertices.each_mut_ext(); diff --git a/crates/fj-kernel/src/algorithms/transform/curve.rs b/crates/fj-kernel/src/algorithms/transform/curve.rs index 9beb760c0..3b786abcd 100644 --- a/crates/fj-kernel/src/algorithms/transform/curve.rs +++ b/crates/fj-kernel/src/algorithms/transform/curve.rs @@ -18,16 +18,12 @@ impl TransformObject for Curve { // coordinates, and thus transforming `surface` takes care of it. let path = self.path(); - let surface = self - .surface() - .clone() - .transform_with_cache(transform, objects, cache); let global_form = self .global_form() .clone() .transform_with_cache(transform, objects, cache); - Self::new(surface, path, global_form) + Self::new(path, global_form) } } diff --git a/crates/fj-kernel/src/algorithms/transform/edge.rs b/crates/fj-kernel/src/algorithms/transform/edge.rs index 4c5b7b242..796769f5e 100644 --- a/crates/fj-kernel/src/algorithms/transform/edge.rs +++ b/crates/fj-kernel/src/algorithms/transform/edge.rs @@ -15,6 +15,10 @@ impl TransformObject for HalfEdge { objects: &mut Service, cache: &mut TransformCache, ) -> Self { + let surface = self + .surface() + .clone() + .transform_with_cache(transform, objects, cache); let curve = self .curve() .clone() @@ -32,7 +36,7 @@ impl TransformObject for HalfEdge { .clone() .transform_with_cache(transform, objects, cache); - Self::new(curve, boundary, global_form) + Self::new(surface, curve, boundary, global_form) } } diff --git a/crates/fj-kernel/src/builder/edge.rs b/crates/fj-kernel/src/builder/edge.rs index 229bbaab6..6a1e920a0 100644 --- a/crates/fj-kernel/src/builder/edge.rs +++ b/crates/fj-kernel/src/builder/edge.rs @@ -64,7 +64,7 @@ impl HalfEdgeBuilder for PartialHalfEdge { fn replace_surface(&mut self, surface: impl Into>) { let surface = surface.into(); - self.curve.write().surface = surface.clone(); + self.surface = surface.clone(); for vertex in &mut self.vertices { vertex.1.write().surface = surface.clone(); @@ -134,14 +134,11 @@ impl HalfEdgeBuilder for PartialHalfEdge { surface: impl Into>, points: [impl Into>; 2], ) { - let surface = surface.into(); - - self.curve.write().surface = surface.clone(); + self.replace_surface(surface.into()); for (vertex, point) in self.vertices.each_mut_ext().zip_ext(points) { let mut surface_form = vertex.1.write(); surface_form.position = Some(point.into()); - surface_form.surface = surface.clone(); } self.update_as_line_segment() @@ -196,7 +193,7 @@ impl HalfEdgeBuilder for PartialHalfEdge { self.curve.write().path = other.read().curve.read().path.as_ref().and_then(|path| { - match other.read().curve.read().surface.read().geometry { + match other.read().surface.read().geometry { Some(surface) => { // We have information about the other edge's surface // available. We need to use that to interpret what the diff --git a/crates/fj-kernel/src/objects/full/curve.rs b/crates/fj-kernel/src/objects/full/curve.rs index 2db17d3fc..5515141ce 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, - objects::Surface, storage::{Handle, HandleWrapper}, }; @@ -8,19 +7,16 @@ use crate::{ #[derive(Clone, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)] pub struct Curve { path: SurfacePath, - surface: Handle, global_form: HandleWrapper, } impl Curve { /// Construct a new instance of `Curve` pub fn new( - surface: Handle, path: SurfacePath, global_form: impl Into>, ) -> Self { Self { - surface, path, global_form: global_form.into(), } @@ -31,11 +27,6 @@ impl Curve { self.path } - /// Access the surface that the curve is defined in - pub fn surface(&self) -> &Handle { - &self.surface - } - /// Access the global form of the curve pub fn global_form(&self) -> &Handle { &self.global_form diff --git a/crates/fj-kernel/src/objects/full/cycle.rs b/crates/fj-kernel/src/objects/full/cycle.rs index 2a829a8a5..66e56a200 100644 --- a/crates/fj-kernel/src/objects/full/cycle.rs +++ b/crates/fj-kernel/src/objects/full/cycle.rs @@ -39,7 +39,7 @@ impl Cycle { /// Access the surface that the cycle is in pub fn surface(&self) -> &Handle { if let Some(half_edge) = self.half_edges.first() { - return half_edge.curve().surface(); + return half_edge.surface(); } unreachable!( diff --git a/crates/fj-kernel/src/objects/full/edge.rs b/crates/fj-kernel/src/objects/full/edge.rs index 390ec41e3..f7a77b378 100644 --- a/crates/fj-kernel/src/objects/full/edge.rs +++ b/crates/fj-kernel/src/objects/full/edge.rs @@ -4,13 +4,14 @@ use fj_interop::ext::ArrayExt; use fj_math::Point; use crate::{ - objects::{Curve, GlobalCurve, GlobalVertex, SurfaceVertex}, + objects::{Curve, GlobalCurve, GlobalVertex, Surface, SurfaceVertex}, storage::{Handle, HandleWrapper}, }; /// A half-edge #[derive(Clone, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)] pub struct HalfEdge { + surface: Handle, curve: Handle, boundary: [(Point<1>, Handle); 2], global_form: Handle, @@ -19,17 +20,24 @@ pub struct HalfEdge { impl HalfEdge { /// Create an instance of `HalfEdge` pub fn new( + surface: Handle, curve: Handle, boundary: [(Point<1>, Handle); 2], global_form: Handle, ) -> Self { Self { + surface, curve, boundary, global_form, } } + /// Access the surface that the half-edge is defined in + pub fn surface(&self) -> &Handle { + &self.surface + } + /// Access the curve that defines the half-edge's geometry pub fn curve(&self) -> &Handle { &self.curve diff --git a/crates/fj-kernel/src/partial/objects/curve.rs b/crates/fj-kernel/src/partial/objects/curve.rs index e1924b692..3826d4cb2 100644 --- a/crates/fj-kernel/src/partial/objects/curve.rs +++ b/crates/fj-kernel/src/partial/objects/curve.rs @@ -2,7 +2,7 @@ use fj_math::Scalar; use crate::{ geometry::path::SurfacePath, - objects::{Curve, GlobalCurve, Objects, Surface}, + objects::{Curve, GlobalCurve, Objects}, partial::{FullToPartialCache, Partial, PartialObject}, services::Service, }; @@ -13,9 +13,6 @@ pub struct PartialCurve { /// The path that defines the curve pub path: Option, - /// The surface the curve is defined in - pub surface: Partial, - /// The global form of the curve pub global_form: Partial, } @@ -26,7 +23,6 @@ impl PartialObject for PartialCurve { fn from_full(curve: &Self::Full, cache: &mut FullToPartialCache) -> Self { Self { path: Some(curve.path().into()), - surface: Partial::from_full(curve.surface().clone(), cache), global_form: Partial::from_full(curve.global_form().clone(), cache), } } @@ -40,10 +36,9 @@ impl PartialObject for PartialCurve { ) } }; - let surface = self.surface.build(objects); let global_form = self.global_form.build(objects); - Curve::new(surface, path, global_form) + Curve::new(path, global_form) } } diff --git a/crates/fj-kernel/src/partial/objects/edge.rs b/crates/fj-kernel/src/partial/objects/edge.rs index 6eda1fe16..ff0addbbb 100644 --- a/crates/fj-kernel/src/partial/objects/edge.rs +++ b/crates/fj-kernel/src/partial/objects/edge.rs @@ -6,7 +6,7 @@ use fj_math::Point; use crate::{ objects::{ Curve, GlobalCurve, GlobalEdge, GlobalVertex, HalfEdge, Objects, - SurfaceVertex, + Surface, SurfaceVertex, }, partial::{ FullToPartialCache, Partial, PartialObject, PartialSurfaceVertex, @@ -17,6 +17,9 @@ use crate::{ /// A partial [`HalfEdge`] #[derive(Clone, Debug)] pub struct PartialHalfEdge { + /// The surface that the half-edge is defined in + pub surface: Partial, + /// The curve that the half-edge is defined in pub curve: Partial, @@ -35,6 +38,7 @@ impl PartialObject for PartialHalfEdge { cache: &mut FullToPartialCache, ) -> Self { Self { + surface: Partial::from_full(half_edge.surface().clone(), cache), curve: Partial::from_full(half_edge.curve().clone(), cache), vertices: half_edge .boundary() @@ -53,6 +57,7 @@ impl PartialObject for PartialHalfEdge { } fn build(self, objects: &mut Service) -> Self::Full { + let surface = self.surface.build(objects); let curve = self.curve.build(objects); let vertices = self.vertices.map(|mut vertex| { let position_surface = vertex.1.read().position; @@ -76,10 +81,9 @@ impl PartialObject for PartialHalfEdge { // Infer global position, if not available. let position_global = vertex.1.read().global_form.read().position; if position_global.is_none() { - let surface = curve.surface().geometry(); - - let position_global = - surface.point_from_surface_coords(position_surface); + let position_global = surface + .geometry() + .point_from_surface_coords(position_surface); vertex.1.write().global_form.write().position = Some(position_global); } @@ -92,18 +96,18 @@ impl PartialObject for PartialHalfEdge { }); let global_form = self.global_form.build(objects); - HalfEdge::new(curve, vertices, global_form) + HalfEdge::new(surface, curve, vertices, global_form) } } impl Default for PartialHalfEdge { fn default() -> Self { + let surface = Partial::new(); + let curve = Partial::::new(); let vertices = array::from_fn(|_| { - let surface = Partial::new(); - let surface_form = Partial::from_partial(PartialSurfaceVertex { - surface, + surface: surface.clone(), ..Default::default() }); @@ -125,6 +129,7 @@ impl Default for PartialHalfEdge { }); Self { + surface, curve, vertices, global_form, diff --git a/crates/fj-kernel/src/validate/edge.rs b/crates/fj-kernel/src/validate/edge.rs index 75445fefd..ed434ea1a 100644 --- a/crates/fj-kernel/src/validate/edge.rs +++ b/crates/fj-kernel/src/validate/edge.rs @@ -165,13 +165,13 @@ impl HalfEdgeValidationError { half_edge: &HalfEdge, errors: &mut Vec, ) { - let curve_surface = half_edge.curve().surface(); + let surface = half_edge.surface(); let surface_form_surface = half_edge.start_vertex().surface(); - if curve_surface.id() != surface_form_surface.id() { + if surface.id() != surface_form_surface.id() { errors.push( Box::new(Self::SurfaceMismatch { - curve_surface: curve_surface.clone(), + curve_surface: surface.clone(), surface_form_surface: surface_form_surface.clone(), }) .into(), @@ -240,7 +240,12 @@ mod tests { .boundary() .zip_ext(valid.surface_vertices().map(Clone::clone)); - HalfEdge::new(valid.curve().clone(), vertices, global_form) + HalfEdge::new( + valid.surface().clone(), + valid.curve().clone(), + vertices, + global_form, + ) }; valid.validate_and_return_first_error()?; @@ -282,7 +287,12 @@ mod tests { .boundary() .zip_ext(valid.surface_vertices().map(Clone::clone)); - HalfEdge::new(valid.curve().clone(), vertices, global_form) + HalfEdge::new( + valid.surface().clone(), + valid.curve().clone(), + vertices, + global_form, + ) }; valid.validate_and_return_first_error()?; @@ -318,6 +328,7 @@ mod tests { }); HalfEdge::new( + valid.surface().clone(), valid.curve().clone(), vertices, valid.global_form().clone(), @@ -349,6 +360,7 @@ mod tests { }); HalfEdge::new( + valid.surface().clone(), valid.curve().clone(), vertices, valid.global_form().clone(), diff --git a/crates/fj-operations/src/sketch.rs b/crates/fj-operations/src/sketch.rs index 03f89119e..54c736008 100644 --- a/crates/fj-operations/src/sketch.rs +++ b/crates/fj-operations/src/sketch.rs @@ -31,13 +31,7 @@ impl Shape for fj::Sketch { let surface = Partial::from(surface); let mut half_edge = PartialHalfEdge::default(); - - half_edge.curve.write().surface = surface.clone(); - - for vertex in &mut half_edge.vertices { - vertex.1.write().surface = surface.clone(); - } - + half_edge.replace_surface(surface); half_edge.update_as_circle_from_radius(circle.radius()); Partial::from_partial(half_edge)