diff --git a/crates/fj-kernel/src/algorithms/approx/edge.rs b/crates/fj-kernel/src/algorithms/approx/edge.rs index 95bc0f724..f8899ed87 100644 --- a/crates/fj-kernel/src/algorithms/approx/edge.rs +++ b/crates/fj-kernel/src/algorithms/approx/edge.rs @@ -231,10 +231,12 @@ mod tests { use crate::{ algorithms::approx::{path::RangeOnPath, Approx, ApproxPoint}, - builder::{HalfEdgeBuilder, SurfaceBuilder}, + builder::{CycleBuilder, HalfEdgeBuilder, SurfaceBuilder}, geometry::curve::GlobalPath, insert::Insert, - partial::{PartialHalfEdge, PartialObject, PartialSurface}, + partial::{ + PartialCycle, PartialHalfEdge, PartialObject, PartialSurface, + }, services::Services, }; @@ -244,17 +246,16 @@ mod tests { let surface = services.objects.surfaces.xz_plane(); let half_edge = { - let mut half_edge = PartialHalfEdge::default(); + let mut cycle = PartialCycle::default(); - half_edge.update_as_line_segment_from_points( - [[1., 1.], [2., 1.]], - half_edge.end_vertex.clone(), - ); - half_edge.infer_vertex_positions_if_necessary( + let [mut half_edge, next_half_edge, _] = cycle + .update_as_polygon_from_points([[1., 1.], [2., 1.], [1., 2.]]); + half_edge.write().infer_vertex_positions_if_necessary( &surface.geometry(), - half_edge.end_vertex.clone(), + next_half_edge.read().start_vertex.clone(), ); + let half_edge = half_edge.read().clone(); half_edge .build(&mut services.objects) .insert(&mut services.objects) @@ -277,17 +278,16 @@ mod tests { .build(&mut services.objects) .insert(&mut services.objects); let half_edge = { - let mut half_edge = PartialHalfEdge::default(); + let mut cycle = PartialCycle::default(); - half_edge.update_as_line_segment_from_points( - [[1., 1.], [2., 1.]], - half_edge.end_vertex.clone(), - ); - half_edge.infer_vertex_positions_if_necessary( + let [mut half_edge, next_half_edge, _] = cycle + .update_as_polygon_from_points([[1., 1.], [2., 1.], [1., 2.]]); + half_edge.write().infer_vertex_positions_if_necessary( &surface.geometry(), - half_edge.end_vertex.clone(), + next_half_edge.read().start_vertex.clone(), ); + let half_edge = half_edge.read().clone(); half_edge .build(&mut services.objects) .insert(&mut services.objects) @@ -310,21 +310,20 @@ mod tests { .build(&mut services.objects) .insert(&mut services.objects); let half_edge = { - let mut half_edge = PartialHalfEdge::default(); + let mut cycle = PartialCycle::default(); - half_edge.update_as_line_segment_from_points( - [[0., 1.], [1., 1.]], - half_edge.end_vertex.clone(), - ); + let [mut half_edge, next_half_edge, _] = cycle + .update_as_polygon_from_points([[0., 1.], [1., 1.], [1., 2.]]); - half_edge.boundary[0] = Some(range.boundary[0]); - half_edge.boundary[1] = Some(range.boundary[1]); + half_edge.write().boundary[0] = Some(range.boundary[0]); + half_edge.write().boundary[1] = Some(range.boundary[1]); - half_edge.infer_vertex_positions_if_necessary( + half_edge.write().infer_vertex_positions_if_necessary( &surface.geometry(), - half_edge.end_vertex.clone(), + next_half_edge.read().start_vertex.clone(), ); + let half_edge = half_edge.read().clone(); half_edge .build(&mut services.objects) .insert(&mut services.objects) diff --git a/crates/fj-kernel/src/algorithms/intersect/curve_edge.rs b/crates/fj-kernel/src/algorithms/intersect/curve_edge.rs index 05f5f363c..ae5b67fd4 100644 --- a/crates/fj-kernel/src/algorithms/intersect/curve_edge.rs +++ b/crates/fj-kernel/src/algorithms/intersect/curve_edge.rs @@ -72,9 +72,9 @@ mod tests { use fj_math::Point; use crate::{ - builder::HalfEdgeBuilder, + builder::{CycleBuilder, HalfEdgeBuilder}, geometry::curve::Curve, - partial::{PartialHalfEdge, PartialObject}, + partial::PartialCycle, services::Services, }; @@ -87,14 +87,13 @@ mod tests { let surface = services.objects.surfaces.xy_plane(); let curve = Curve::u_axis(); let half_edge = { - let mut half_edge = PartialHalfEdge::default(); - half_edge.update_as_line_segment_from_points( - [[1., -1.], [1., 1.]], - half_edge.end_vertex.clone(), - ); - half_edge.infer_vertex_positions_if_necessary( + let mut cycle = PartialCycle::default(); + + let [mut half_edge, next_half_edge, _] = cycle + .update_as_polygon_from_points([[1., -1.], [1., 1.], [0., 1.]]); + half_edge.write().infer_vertex_positions_if_necessary( &surface.geometry(), - half_edge.end_vertex.clone(), + next_half_edge.read().start_vertex.clone(), ); half_edge.build(&mut services.objects) @@ -117,14 +116,17 @@ mod tests { let surface = services.objects.surfaces.xy_plane(); let curve = Curve::u_axis(); let half_edge = { - let mut half_edge = PartialHalfEdge::default(); - half_edge.update_as_line_segment_from_points( - [[-1., -1.], [-1., 1.]], - half_edge.end_vertex.clone(), - ); - half_edge.infer_vertex_positions_if_necessary( + let mut cycle = PartialCycle::default(); + + let [mut half_edge, next_half_edge, _] = cycle + .update_as_polygon_from_points([ + [-1., -1.], + [-1., 1.], + [0., 1.], + ]); + half_edge.write().infer_vertex_positions_if_necessary( &surface.geometry(), - half_edge.end_vertex.clone(), + next_half_edge.read().start_vertex.clone(), ); half_edge.build(&mut services.objects) @@ -147,14 +149,17 @@ mod tests { let surface = services.objects.surfaces.xy_plane(); let curve = Curve::u_axis(); let half_edge = { - let mut half_edge = PartialHalfEdge::default(); - half_edge.update_as_line_segment_from_points( - [[-1., -1.], [1., -1.]], - half_edge.end_vertex.clone(), - ); - half_edge.infer_vertex_positions_if_necessary( + let mut cycle = PartialCycle::default(); + + let [mut half_edge, next_half_edge, _] = cycle + .update_as_polygon_from_points([ + [-1., -1.], + [1., -1.], + [1., 1.], + ]); + half_edge.write().infer_vertex_positions_if_necessary( &surface.geometry(), - half_edge.end_vertex.clone(), + next_half_edge.read().start_vertex.clone(), ); half_edge.build(&mut services.objects) @@ -172,14 +177,13 @@ mod tests { let surface = services.objects.surfaces.xy_plane(); let curve = Curve::u_axis(); let half_edge = { - let mut half_edge = PartialHalfEdge::default(); - half_edge.update_as_line_segment_from_points( - [[-1., 0.], [1., 0.]], - half_edge.end_vertex.clone(), - ); - half_edge.infer_vertex_positions_if_necessary( + let mut cycle = PartialCycle::default(); + + let [mut half_edge, next_half_edge, _] = cycle + .update_as_polygon_from_points([[-1., 0.], [1., 0.], [1., 1.]]); + half_edge.write().infer_vertex_positions_if_necessary( &surface.geometry(), - half_edge.end_vertex.clone(), + next_half_edge.read().start_vertex.clone(), ); half_edge.build(&mut services.objects) diff --git a/crates/fj-kernel/src/algorithms/sweep/edge.rs b/crates/fj-kernel/src/algorithms/sweep/edge.rs index d3de6176a..6cb9a21e9 100644 --- a/crates/fj-kernel/src/algorithms/sweep/edge.rs +++ b/crates/fj-kernel/src/algorithms/sweep/edge.rs @@ -128,8 +128,7 @@ impl Sweep for (Handle, &Handle, &Surface, Color) { .into_iter() .circular_tuple_windows() { - edge.write() - .update_as_line_segment(next.read().start_vertex.clone()); + edge.write().update_as_line_segment(next.clone()); } // Finally, we can make sure that all edges refer to the correct global diff --git a/crates/fj-kernel/src/builder/cycle.rs b/crates/fj-kernel/src/builder/cycle.rs index 4fb5e7659..f11b06f17 100644 --- a/crates/fj-kernel/src/builder/cycle.rs +++ b/crates/fj-kernel/src/builder/cycle.rs @@ -140,9 +140,7 @@ impl CycleBuilder for PartialCycle { for (mut half_edge, next) in self.half_edges.iter().cloned().circular_tuple_windows() { - half_edge - .write() - .update_as_line_segment(next.read().start_vertex.clone()); + half_edge.write().update_as_line_segment(next.clone()); } } diff --git a/crates/fj-kernel/src/builder/edge.rs b/crates/fj-kernel/src/builder/edge.rs index b061d3ecb..4f12910d1 100644 --- a/crates/fj-kernel/src/builder/edge.rs +++ b/crates/fj-kernel/src/builder/edge.rs @@ -27,20 +27,13 @@ pub trait HalfEdgeBuilder { fn update_as_arc( &mut self, angle_rad: impl Into, - next_vertex: Partial, + next_half_edge: Partial, ); - /// Update partial half-edge to be a line segment, from the given points - fn update_as_line_segment_from_points( - &mut self, - points: [impl Into>; 2], - next_vertex: Partial, - ) -> Curve; - /// Update partial half-edge to be a line segment fn update_as_line_segment( &mut self, - next_vertex: Partial, + next_half_edge: Partial, ) -> Curve; /// Infer the global form of the half-edge @@ -104,17 +97,18 @@ impl HalfEdgeBuilder for PartialHalfEdge { fn update_as_arc( &mut self, angle_rad: impl Into, - mut next_vertex: Partial, + mut next_half_edge: Partial, ) { let angle_rad = angle_rad.into(); if angle_rad <= -Scalar::TAU || angle_rad >= Scalar::TAU { panic!("arc angle must be in the range (-2pi, 2pi) radians"); } - let [start, end] = [&self.start_vertex, &next_vertex].map(|vertex| { - vertex - .read() - .position - .expect("Can't infer arc without surface position") + let [start, end] = [ + &self.start_position(), + &next_half_edge.read().start_position(), + ] + .map(|position| { + position.expect("Can't infer arc without surface position") }); let arc = fj_math::Arc::from_endpoints_and_angle(start, end, angle_rad); @@ -128,7 +122,10 @@ impl HalfEdgeBuilder for PartialHalfEdge { for ((point_boundary, surface_vertex), point_curve) in self .boundary .each_mut_ext() - .zip_ext([&mut self.start_vertex, &mut next_vertex]) + .zip_ext([ + &mut self.start_vertex, + &mut next_half_edge.write().start_vertex, + ]) .zip_ext([a_curve, b_curve]) { *point_boundary = Some(point_curve); @@ -136,34 +133,20 @@ impl HalfEdgeBuilder for PartialHalfEdge { Some(path.point_from_path_coords(point_curve)); } - self.infer_global_form(next_vertex); - } - - fn update_as_line_segment_from_points( - &mut self, - points: [impl Into>; 2], - mut next_vertex: Partial, - ) -> Curve { - for (vertex, point) in - [&mut self.start_vertex, &mut next_vertex].zip_ext(points) - { - let mut surface_form = vertex.write(); - surface_form.position = Some(point.into()); - } - - self.update_as_line_segment(next_vertex) + self.infer_global_form(next_half_edge.read().start_vertex.clone()); } fn update_as_line_segment( &mut self, - next_vertex: Partial, + next_half_edge: Partial, ) -> Curve { let boundary = self.boundary; - let points_surface = [&self.start_vertex, &next_vertex].map(|vertex| { - vertex - .read() - .position - .expect("Can't infer line segment without surface position") + let points_surface = [ + &self.start_position(), + &next_half_edge.read().start_position(), + ] + .map(|position| { + position.expect("Can't infer line segment without surface position") }); let path = if let [Some(start), Some(end)] = boundary { @@ -186,7 +169,7 @@ impl HalfEdgeBuilder for PartialHalfEdge { path }; - self.infer_global_form(next_vertex); + self.infer_global_form(next_half_edge.read().start_vertex.clone()); path } diff --git a/crates/fj-kernel/src/objects/full/edge.rs b/crates/fj-kernel/src/objects/full/edge.rs index a40b1b193..23c476171 100644 --- a/crates/fj-kernel/src/objects/full/edge.rs +++ b/crates/fj-kernel/src/objects/full/edge.rs @@ -177,8 +177,8 @@ mod tests { use pretty_assertions::assert_eq; use crate::{ - builder::HalfEdgeBuilder, - partial::{PartialHalfEdge, PartialObject}, + builder::{CycleBuilder, HalfEdgeBuilder}, + partial::PartialCycle, services::Services, }; @@ -190,29 +190,28 @@ mod tests { let a = [0., 0.]; let b = [1., 0.]; + let c = [0., 1.]; let a_to_b = { - let mut half_edge = PartialHalfEdge::default(); - half_edge.update_as_line_segment_from_points( - [a, b], - half_edge.end_vertex.clone(), - ); - half_edge.infer_vertex_positions_if_necessary( + let mut cycle = PartialCycle::default(); + + let [mut half_edge, next_half_edge, _] = + cycle.update_as_polygon_from_points([a, b, c]); + half_edge.write().infer_vertex_positions_if_necessary( &surface.geometry(), - half_edge.end_vertex.clone(), + next_half_edge.read().start_vertex.clone(), ); half_edge.build(&mut services.objects) }; let b_to_a = { - let mut half_edge = PartialHalfEdge::default(); - half_edge.update_as_line_segment_from_points( - [b, a], - half_edge.end_vertex.clone(), - ); - half_edge.infer_vertex_positions_if_necessary( + let mut cycle = PartialCycle::default(); + + let [mut half_edge, next_half_edge, _] = + cycle.update_as_polygon_from_points([b, a, c]); + half_edge.write().infer_vertex_positions_if_necessary( &surface.geometry(), - half_edge.end_vertex.clone(), + next_half_edge.read().start_vertex.clone(), ); half_edge.build(&mut services.objects) diff --git a/crates/fj-kernel/src/partial/objects/edge.rs b/crates/fj-kernel/src/partial/objects/edge.rs index 5c4ad3c8b..45808b722 100644 --- a/crates/fj-kernel/src/partial/objects/edge.rs +++ b/crates/fj-kernel/src/partial/objects/edge.rs @@ -25,6 +25,13 @@ pub struct PartialHalfEdge { pub global_form: Partial, } +impl PartialHalfEdge { + /// Compute the surface position where the half-edge starts + pub fn start_position(&self) -> Option> { + self.start_vertex.read().position + } +} + impl PartialObject for PartialHalfEdge { type Full = HalfEdge; diff --git a/crates/fj-kernel/src/validate/edge.rs b/crates/fj-kernel/src/validate/edge.rs index cd8709ad1..d473182e5 100644 --- a/crates/fj-kernel/src/validate/edge.rs +++ b/crates/fj-kernel/src/validate/edge.rs @@ -143,9 +143,9 @@ mod tests { use fj_math::Point; use crate::{ - builder::HalfEdgeBuilder, + builder::{CycleBuilder, HalfEdgeBuilder}, objects::HalfEdge, - partial::{Partial, PartialHalfEdge, PartialObject}, + partial::{Partial, PartialCycle}, services::Services, validate::Validate, }; @@ -157,14 +157,13 @@ mod tests { let valid = { let surface = services.objects.surfaces.xy_plane(); - let mut half_edge = PartialHalfEdge::default(); - half_edge.update_as_line_segment_from_points( - [[0., 0.], [1., 0.]], - half_edge.end_vertex.clone(), - ); - half_edge.infer_vertex_positions_if_necessary( + let mut cycle = PartialCycle::default(); + + let [mut half_edge, next_half_edge, _] = cycle + .update_as_polygon_from_points([[0., 0.], [1., 0.], [1., 1.]]); + half_edge.write().infer_vertex_positions_if_necessary( &surface.geometry(), - half_edge.end_vertex.clone(), + next_half_edge.read().start_vertex.clone(), ); half_edge.build(&mut services.objects) @@ -208,14 +207,13 @@ mod tests { let valid = { let surface = services.objects.surfaces.xy_plane(); - let mut half_edge = PartialHalfEdge::default(); - half_edge.update_as_line_segment_from_points( - [[0., 0.], [1., 0.]], - half_edge.end_vertex.clone(), - ); - half_edge.infer_vertex_positions_if_necessary( + let mut cycle = PartialCycle::default(); + + let [mut half_edge, next_half_edge, _] = cycle + .update_as_polygon_from_points([[0., 0.], [1., 0.], [1., 1.]]); + half_edge.write().infer_vertex_positions_if_necessary( &surface.geometry(), - half_edge.end_vertex.clone(), + next_half_edge.read().start_vertex.clone(), ); half_edge.build(&mut services.objects) diff --git a/crates/fj-operations/src/sketch.rs b/crates/fj-operations/src/sketch.rs index 6a1acbec2..f102b0032 100644 --- a/crates/fj-operations/src/sketch.rs +++ b/crates/fj-operations/src/sketch.rs @@ -73,19 +73,16 @@ impl Shape for fj::Sketch { for ((mut half_edge, route), (next_half_edge, _)) in half_edges.into_iter().circular_tuple_windows() { - let next_vertex = - next_half_edge.read().start_vertex.clone(); - match route { fj::SketchSegmentRoute::Direct => { half_edge .write() - .update_as_line_segment(next_vertex); + .update_as_line_segment(next_half_edge); } fj::SketchSegmentRoute::Arc { angle } => { half_edge .write() - .update_as_arc(angle.rad(), next_vertex); + .update_as_arc(angle.rad(), next_half_edge); } } }