From 1bda47c69e35527079cd6869a9321cadb36d2523 Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Thu, 30 Mar 2023 10:40:55 +0200 Subject: [PATCH 01/29] Add `BuildHalfEdge` --- crates/fj-kernel/src/operations/build/edge.rs | 37 +++++++++++++++++++ crates/fj-kernel/src/operations/build/mod.rs | 2 + crates/fj-kernel/src/operations/mod.rs | 5 ++- 3 files changed, 43 insertions(+), 1 deletion(-) create mode 100644 crates/fj-kernel/src/operations/build/edge.rs diff --git a/crates/fj-kernel/src/operations/build/edge.rs b/crates/fj-kernel/src/operations/build/edge.rs new file mode 100644 index 000000000..c4a30582c --- /dev/null +++ b/crates/fj-kernel/src/operations/build/edge.rs @@ -0,0 +1,37 @@ +use fj_math::{Point, Scalar}; + +use crate::{ + geometry::curve::Curve, + objects::{GlobalEdge, HalfEdge, Objects, Vertex}, + operations::Insert, + services::Service, +}; + +/// Build a [`HalfEdge`] +pub trait BuildHalfEdge { + /// Create a half-edge that is not joined to another + fn unjoined( + curve: Curve, + boundary: [Point<1>; 2], + objects: &mut Service, + ) -> HalfEdge { + let start_vertex = Vertex::new().insert(objects); + let global_form = GlobalEdge::new().insert(objects); + + HalfEdge::new(curve, boundary, start_vertex, global_form) + } + + /// Create a circle + fn circle( + radius: impl Into, + objects: &mut Service, + ) -> HalfEdge { + let curve = Curve::circle_from_radius(radius); + let boundary = + [Scalar::ZERO, Scalar::TAU].map(|coord| Point::from([coord])); + + HalfEdge::unjoined(curve, boundary, objects) + } +} + +impl BuildHalfEdge for HalfEdge {} diff --git a/crates/fj-kernel/src/operations/build/mod.rs b/crates/fj-kernel/src/operations/build/mod.rs index 8b0bd2521..213b234c5 100644 --- a/crates/fj-kernel/src/operations/build/mod.rs +++ b/crates/fj-kernel/src/operations/build/mod.rs @@ -1,8 +1,10 @@ +mod edge; mod face; mod shell; mod surface; pub use self::{ + edge::BuildHalfEdge, face::{BuildFace, Triangle}, shell::{BuildShell, Tetrahedron}, surface::BuildSurface, diff --git a/crates/fj-kernel/src/operations/mod.rs b/crates/fj-kernel/src/operations/mod.rs index 6067f1735..564086b46 100644 --- a/crates/fj-kernel/src/operations/mod.rs +++ b/crates/fj-kernel/src/operations/mod.rs @@ -5,7 +5,10 @@ mod insert; mod update; pub use self::{ - build::{BuildFace, BuildShell, BuildSurface, Tetrahedron, Triangle}, + build::{ + BuildFace, BuildHalfEdge, BuildShell, BuildSurface, Tetrahedron, + Triangle, + }, insert::Insert, update::{UpdateCycle, UpdateFace, UpdateHalfEdge, UpdateShell}, }; From 2513d3b386f73e6740dd30b95afbd456501d0414 Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Thu, 30 Mar 2023 10:50:27 +0200 Subject: [PATCH 02/29] Make use of `BuildHalfEdge::circle` --- crates/fj-kernel/src/algorithms/approx/edge.rs | 7 +++---- crates/fj-operations/src/sketch.rs | 9 ++++----- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/crates/fj-kernel/src/algorithms/approx/edge.rs b/crates/fj-kernel/src/algorithms/approx/edge.rs index 5901e0d8f..488370895 100644 --- a/crates/fj-kernel/src/algorithms/approx/edge.rs +++ b/crates/fj-kernel/src/algorithms/approx/edge.rs @@ -264,8 +264,8 @@ mod tests { algorithms::approx::{path::RangeOnPath, Approx, ApproxPoint}, builder::HalfEdgeBuilder, geometry::{curve::GlobalPath, surface::SurfaceGeometry}, - objects::Surface, - operations::Insert, + objects::{HalfEdge, Surface}, + operations::{BuildHalfEdge, Insert}, services::Services, }; @@ -343,8 +343,7 @@ mod tests { let mut services = Services::new(); let surface = services.objects.surfaces.xz_plane(); - let half_edge = - HalfEdgeBuilder::circle(1.).build(&mut services.objects); + let half_edge = HalfEdge::circle(1., &mut services.objects); let tolerance = 1.; let approx = (&half_edge, surface.deref()).approx(tolerance); diff --git a/crates/fj-operations/src/sketch.rs b/crates/fj-operations/src/sketch.rs index 72b071312..a81536729 100644 --- a/crates/fj-operations/src/sketch.rs +++ b/crates/fj-operations/src/sketch.rs @@ -3,8 +3,8 @@ use std::ops::Deref; use fj_interop::{debug::DebugInfo, mesh::Color}; use fj_kernel::{ builder::{CycleBuilder, HalfEdgeBuilder}, - objects::{Cycle, Face, Objects, Sketch}, - operations::Insert, + objects::{Cycle, Face, HalfEdge, Objects, Sketch}, + operations::{BuildHalfEdge, Insert}, services::Service, }; use fj_math::{Aabb, Point}; @@ -24,9 +24,8 @@ impl Shape for fj::Sketch { let face = match self.chain() { fj::Chain::Circle(circle) => { - let half_edge = HalfEdgeBuilder::circle(circle.radius()) - .build(objects) - .insert(objects); + let half_edge = + HalfEdge::circle(circle.radius(), objects).insert(objects); let exterior = Cycle::new([half_edge]).insert(objects); Face::new( From b626792eb9cf426a91662219214db22c793f019e Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Thu, 30 Mar 2023 10:52:20 +0200 Subject: [PATCH 03/29] Remove unused `HalfEdgeBuilder::circle` --- crates/fj-kernel/src/builder/edge.rs | 9 --------- 1 file changed, 9 deletions(-) diff --git a/crates/fj-kernel/src/builder/edge.rs b/crates/fj-kernel/src/builder/edge.rs index 857856ccb..d2148297f 100644 --- a/crates/fj-kernel/src/builder/edge.rs +++ b/crates/fj-kernel/src/builder/edge.rs @@ -53,15 +53,6 @@ impl HalfEdgeBuilder { Self::new(curve, boundary) } - /// Create a circle - pub fn circle(radius: impl Into) -> Self { - let curve = Curve::circle_from_radius(radius); - let boundary = - [Scalar::ZERO, Scalar::TAU].map(|coord| Point::from([coord])); - - Self::new(curve, boundary) - } - /// Create a line segment pub fn line_segment( points_surface: [impl Into>; 2], From c5a36b1a60837d6afba3bf3a3bf0526bbaac16ed Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Thu, 30 Mar 2023 11:14:28 +0200 Subject: [PATCH 04/29] Add `BuildHalfEdge::line_segment` --- crates/fj-kernel/src/operations/build/edge.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/crates/fj-kernel/src/operations/build/edge.rs b/crates/fj-kernel/src/operations/build/edge.rs index c4a30582c..675025e57 100644 --- a/crates/fj-kernel/src/operations/build/edge.rs +++ b/crates/fj-kernel/src/operations/build/edge.rs @@ -1,3 +1,4 @@ +use fj_interop::ext::ArrayExt; use fj_math::{Point, Scalar}; use crate::{ @@ -32,6 +33,21 @@ pub trait BuildHalfEdge { HalfEdge::unjoined(curve, boundary, objects) } + + /// Create a line segment + fn line_segment( + points_surface: [impl Into>; 2], + boundary: Option<[Point<1>; 2]>, + objects: &mut Service, + ) -> HalfEdge { + let boundary = + boundary.unwrap_or_else(|| [[0.], [1.]].map(Point::from)); + let curve = Curve::line_from_points_with_coords( + boundary.zip_ext(points_surface), + ); + + HalfEdge::unjoined(curve, boundary, objects) + } } impl BuildHalfEdge for HalfEdge {} From 5220872197108fa740582c2828b9a6f2f3a822ab Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Thu, 30 Mar 2023 11:16:44 +0200 Subject: [PATCH 05/29] Make use of `BuildHalfEdge::line_segment` --- .../fj-kernel/src/algorithms/approx/edge.rs | 23 ++++++------ .../src/algorithms/intersect/curve_edge.rs | 35 ++++++++++++------- crates/fj-kernel/src/validate/edge.rs | 9 +++-- 3 files changed, 41 insertions(+), 26 deletions(-) diff --git a/crates/fj-kernel/src/algorithms/approx/edge.rs b/crates/fj-kernel/src/algorithms/approx/edge.rs index 488370895..2dfdbbf1e 100644 --- a/crates/fj-kernel/src/algorithms/approx/edge.rs +++ b/crates/fj-kernel/src/algorithms/approx/edge.rs @@ -262,7 +262,6 @@ mod tests { use crate::{ algorithms::approx::{path::RangeOnPath, Approx, ApproxPoint}, - builder::HalfEdgeBuilder, geometry::{curve::GlobalPath, surface::SurfaceGeometry}, objects::{HalfEdge, Surface}, operations::{BuildHalfEdge, Insert}, @@ -274,9 +273,11 @@ mod tests { let mut services = Services::new(); let surface = services.objects.surfaces.xz_plane(); - let half_edge = - HalfEdgeBuilder::line_segment([[1., 1.], [2., 1.]], None) - .build(&mut services.objects); + let half_edge = HalfEdge::line_segment( + [[1., 1.], [2., 1.]], + None, + &mut services.objects, + ); let tolerance = 1.; let approx = (&half_edge, surface.deref()).approx(tolerance); @@ -293,9 +294,11 @@ mod tests { v: [0., 0., 1.].into(), }) .insert(&mut services.objects); - let half_edge = - HalfEdgeBuilder::line_segment([[1., 1.], [2., 1.]], None) - .build(&mut services.objects); + let half_edge = HalfEdge::line_segment( + [[1., 1.], [2., 1.]], + None, + &mut services.objects, + ); let tolerance = 1.; let approx = (&half_edge, surface.deref()).approx(tolerance); @@ -315,11 +318,11 @@ mod tests { v: [0., 0., 1.].into(), }) .insert(&mut services.objects); - let half_edge = HalfEdgeBuilder::line_segment( + let half_edge = HalfEdge::line_segment( [[0., 1.], [TAU, 1.]], Some(range.boundary), - ) - .build(&mut services.objects); + &mut services.objects, + ); let tolerance = 1.; let approx = (&half_edge, surface.deref()).approx(tolerance); diff --git a/crates/fj-kernel/src/algorithms/intersect/curve_edge.rs b/crates/fj-kernel/src/algorithms/intersect/curve_edge.rs index f63cd17af..c5b759c41 100644 --- a/crates/fj-kernel/src/algorithms/intersect/curve_edge.rs +++ b/crates/fj-kernel/src/algorithms/intersect/curve_edge.rs @@ -72,7 +72,8 @@ mod tests { use fj_math::Point; use crate::{ - builder::HalfEdgeBuilder, geometry::curve::Curve, services::Services, + geometry::curve::Curve, objects::HalfEdge, operations::BuildHalfEdge, + services::Services, }; use super::CurveEdgeIntersection; @@ -82,9 +83,11 @@ mod tests { let mut services = Services::new(); let curve = Curve::u_axis(); - let half_edge = - HalfEdgeBuilder::line_segment([[1., -1.], [1., 1.]], None) - .build(&mut services.objects); + let half_edge = HalfEdge::line_segment( + [[1., -1.], [1., 1.]], + None, + &mut services.objects, + ); let intersection = CurveEdgeIntersection::compute(&curve, &half_edge); @@ -101,9 +104,11 @@ mod tests { let mut services = Services::new(); let curve = Curve::u_axis(); - let half_edge = - HalfEdgeBuilder::line_segment([[-1., -1.], [-1., 1.]], None) - .build(&mut services.objects); + let half_edge = HalfEdge::line_segment( + [[-1., -1.], [-1., 1.]], + None, + &mut services.objects, + ); let intersection = CurveEdgeIntersection::compute(&curve, &half_edge); @@ -120,9 +125,11 @@ mod tests { let mut services = Services::new(); let curve = Curve::u_axis(); - let half_edge = - HalfEdgeBuilder::line_segment([[-1., -1.], [1., -1.]], None) - .build(&mut services.objects); + let half_edge = HalfEdge::line_segment( + [[-1., -1.], [1., -1.]], + None, + &mut services.objects, + ); let intersection = CurveEdgeIntersection::compute(&curve, &half_edge); @@ -134,9 +141,11 @@ mod tests { let mut services = Services::new(); let curve = Curve::u_axis(); - let half_edge = - HalfEdgeBuilder::line_segment([[-1., 0.], [1., 0.]], None) - .build(&mut services.objects); + let half_edge = HalfEdge::line_segment( + [[-1., 0.], [1., 0.]], + None, + &mut services.objects, + ); let intersection = CurveEdgeIntersection::compute(&curve, &half_edge); diff --git a/crates/fj-kernel/src/validate/edge.rs b/crates/fj-kernel/src/validate/edge.rs index e5399a7ce..053cc3c3d 100644 --- a/crates/fj-kernel/src/validate/edge.rs +++ b/crates/fj-kernel/src/validate/edge.rs @@ -77,8 +77,8 @@ mod tests { use crate::{ assert_contains_err, - builder::HalfEdgeBuilder, objects::HalfEdge, + operations::BuildHalfEdge, services::Services, validate::{HalfEdgeValidationError, Validate, ValidationError}, }; @@ -87,8 +87,11 @@ mod tests { fn half_edge_vertices_are_coincident() -> anyhow::Result<()> { let mut services = Services::new(); - let valid = HalfEdgeBuilder::line_segment([[0., 0.], [1., 0.]], None) - .build(&mut services.objects); + let valid = HalfEdge::line_segment( + [[0., 0.], [1., 0.]], + None, + &mut services.objects, + ); let invalid = { let boundary = [Point::from([0.]); 2]; From 8cd70404e6b5201e84a11e13e807032edcbb6eda Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Tue, 28 Mar 2023 13:18:21 +0200 Subject: [PATCH 06/29] Add `BuildCycle` --- crates/fj-kernel/src/operations/build/cycle.rs | 11 +++++++++++ crates/fj-kernel/src/operations/build/mod.rs | 2 ++ crates/fj-kernel/src/operations/mod.rs | 4 ++-- 3 files changed, 15 insertions(+), 2 deletions(-) create mode 100644 crates/fj-kernel/src/operations/build/cycle.rs diff --git a/crates/fj-kernel/src/operations/build/cycle.rs b/crates/fj-kernel/src/operations/build/cycle.rs new file mode 100644 index 000000000..93dae568e --- /dev/null +++ b/crates/fj-kernel/src/operations/build/cycle.rs @@ -0,0 +1,11 @@ +use crate::objects::Cycle; + +/// Build a [`Cycle`] +pub trait BuildCycle { + /// Build an empty cycle + fn empty() -> Cycle { + Cycle::new([]) + } +} + +impl BuildCycle for Cycle {} diff --git a/crates/fj-kernel/src/operations/build/mod.rs b/crates/fj-kernel/src/operations/build/mod.rs index 213b234c5..2cc47ed35 100644 --- a/crates/fj-kernel/src/operations/build/mod.rs +++ b/crates/fj-kernel/src/operations/build/mod.rs @@ -1,9 +1,11 @@ +mod cycle; mod edge; mod face; mod shell; mod surface; pub use self::{ + cycle::BuildCycle, edge::BuildHalfEdge, face::{BuildFace, Triangle}, shell::{BuildShell, Tetrahedron}, diff --git a/crates/fj-kernel/src/operations/mod.rs b/crates/fj-kernel/src/operations/mod.rs index 564086b46..7b05c5335 100644 --- a/crates/fj-kernel/src/operations/mod.rs +++ b/crates/fj-kernel/src/operations/mod.rs @@ -6,8 +6,8 @@ mod update; pub use self::{ build::{ - BuildFace, BuildHalfEdge, BuildShell, BuildSurface, Tetrahedron, - Triangle, + BuildCycle, BuildFace, BuildHalfEdge, BuildShell, BuildSurface, + Tetrahedron, Triangle, }, insert::Insert, update::{UpdateCycle, UpdateFace, UpdateHalfEdge, UpdateShell}, From bd286c82c4055b8b236fcbca93daf566524a0db2 Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Thu, 30 Mar 2023 10:56:49 +0200 Subject: [PATCH 07/29] Add `UpdateCycle::add_half_edges` --- crates/fj-kernel/src/operations/update/cycle.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/crates/fj-kernel/src/operations/update/cycle.rs b/crates/fj-kernel/src/operations/update/cycle.rs index 43e8d441b..ffcb2cf5e 100644 --- a/crates/fj-kernel/src/operations/update/cycle.rs +++ b/crates/fj-kernel/src/operations/update/cycle.rs @@ -5,6 +5,12 @@ use crate::{ /// Update a [`Cycle`] pub trait UpdateCycle { + /// Add half-edges to the cycle + fn add_half_edges( + &self, + half_edges: impl IntoIterator>, + ) -> Cycle; + /// Update a half-edge of the cycle fn update_half_edge( &self, @@ -14,6 +20,14 @@ pub trait UpdateCycle { } impl UpdateCycle for Cycle { + fn add_half_edges( + &self, + half_edges: impl IntoIterator>, + ) -> Cycle { + let half_edges = self.half_edges().cloned().chain(half_edges); + Cycle::new(half_edges) + } + fn update_half_edge( &self, index: usize, From c83fc71d2386e1ec23b983db5e3ef9af4c418896 Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Thu, 30 Mar 2023 11:27:39 +0200 Subject: [PATCH 08/29] Refactor code to prepare for follow-on change --- crates/fj-kernel/src/validate/cycle.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/crates/fj-kernel/src/validate/cycle.rs b/crates/fj-kernel/src/validate/cycle.rs index 592dca4f3..066468ee4 100644 --- a/crates/fj-kernel/src/validate/cycle.rs +++ b/crates/fj-kernel/src/validate/cycle.rs @@ -112,13 +112,13 @@ mod tests { valid.validate_and_return_first_error()?; let disconnected = { - let first = - HalfEdgeBuilder::line_segment([[0., 0.], [1., 0.]], None); - let second = - HalfEdgeBuilder::line_segment([[0., 0.], [1., 0.]], None); + let half_edges = [ + HalfEdgeBuilder::line_segment([[0., 0.], [1., 0.]], None), + HalfEdgeBuilder::line_segment([[0., 0.], [1., 0.]], None), + ]; CycleBuilder::new() - .add_half_edges([first, second]) + .add_half_edges(half_edges) .build(&mut services.objects) }; From d9c14b5cbef2b4a4a7e359b738d0141c175cf143 Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Thu, 30 Mar 2023 11:29:21 +0200 Subject: [PATCH 09/29] Replace use of `HalfEdgeBuilder`/`CycleBuilder` --- crates/fj-kernel/src/validate/cycle.rs | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/crates/fj-kernel/src/validate/cycle.rs b/crates/fj-kernel/src/validate/cycle.rs index 066468ee4..baeaf92cb 100644 --- a/crates/fj-kernel/src/validate/cycle.rs +++ b/crates/fj-kernel/src/validate/cycle.rs @@ -96,8 +96,9 @@ mod tests { use crate::{ assert_contains_err, - builder::{CycleBuilder, HalfEdgeBuilder}, - objects::Cycle, + builder::CycleBuilder, + objects::{Cycle, HalfEdge}, + operations::{BuildCycle, BuildHalfEdge, Insert, UpdateCycle}, services::Services, validate::{cycle::CycleValidationError, Validate, ValidationError}, }; @@ -113,13 +114,21 @@ mod tests { let disconnected = { let half_edges = [ - HalfEdgeBuilder::line_segment([[0., 0.], [1., 0.]], None), - HalfEdgeBuilder::line_segment([[0., 0.], [1., 0.]], None), + HalfEdge::line_segment( + [[0., 0.], [1., 0.]], + None, + &mut services.objects, + ), + HalfEdge::line_segment( + [[0., 0.], [1., 0.]], + None, + &mut services.objects, + ), ]; + let half_edges = half_edges + .map(|half_edge| half_edge.insert(&mut services.objects)); - CycleBuilder::new() - .add_half_edges(half_edges) - .build(&mut services.objects) + Cycle::empty().add_half_edges(half_edges) }; assert_contains_err!( From d5888e74259242603b20beed048725130e543ffa Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Thu, 30 Mar 2023 11:31:41 +0200 Subject: [PATCH 10/29] Add `BuildHalfEdge::arc` --- crates/fj-kernel/src/operations/build/edge.rs | 28 ++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/crates/fj-kernel/src/operations/build/edge.rs b/crates/fj-kernel/src/operations/build/edge.rs index 675025e57..36e89f47d 100644 --- a/crates/fj-kernel/src/operations/build/edge.rs +++ b/crates/fj-kernel/src/operations/build/edge.rs @@ -1,5 +1,5 @@ use fj_interop::ext::ArrayExt; -use fj_math::{Point, Scalar}; +use fj_math::{Arc, Point, Scalar}; use crate::{ geometry::curve::Curve, @@ -22,6 +22,32 @@ pub trait BuildHalfEdge { HalfEdge::new(curve, boundary, start_vertex, global_form) } + /// Create an arc + /// + /// # Panics + /// + /// Panics if the given angle is not within the range (-2pi, 2pi) radians. + fn arc( + start: impl Into>, + end: impl Into>, + angle_rad: impl Into, + objects: &mut Service, + ) -> HalfEdge { + 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 arc = Arc::from_endpoints_and_angle(start, end, angle_rad); + + let curve = + Curve::circle_from_center_and_radius(arc.center, arc.radius); + let boundary = + [arc.start_angle, arc.end_angle].map(|coord| Point::from([coord])); + + HalfEdge::unjoined(curve, boundary, objects) + } + /// Create a circle fn circle( radius: impl Into, From b85b4c0d7d51baf5a2c19151ae5263331a50573c Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Thu, 30 Mar 2023 11:33:38 +0200 Subject: [PATCH 11/29] Replace use of `HalfEdgeBuilder`/`CycleBuilder` --- crates/fj-operations/src/sketch.rs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/crates/fj-operations/src/sketch.rs b/crates/fj-operations/src/sketch.rs index a81536729..4e03865b0 100644 --- a/crates/fj-operations/src/sketch.rs +++ b/crates/fj-operations/src/sketch.rs @@ -2,9 +2,8 @@ use std::ops::Deref; use fj_interop::{debug::DebugInfo, mesh::Color}; use fj_kernel::{ - builder::{CycleBuilder, HalfEdgeBuilder}, objects::{Cycle, Face, HalfEdge, Objects, Sketch}, - operations::{BuildHalfEdge, Insert}, + operations::{BuildCycle, BuildHalfEdge, Insert, UpdateCycle}, services::Service, }; use fj_math::{Aabb, Point}; @@ -43,7 +42,7 @@ impl Shape for fj::Sketch { ); let exterior = { - let mut cycle = CycleBuilder::new(); + let mut cycle = Cycle::empty(); let segments = poly_chain .to_segments() @@ -57,20 +56,22 @@ impl Shape for fj::Sketch { for ((start, route), (end, _)) in segments { let half_edge = match route { fj::SketchSegmentRoute::Direct => { - HalfEdgeBuilder::line_segment( + HalfEdge::line_segment( [start, end], None, + objects, ) } fj::SketchSegmentRoute::Arc { angle } => { - HalfEdgeBuilder::arc(start, end, angle.rad()) + HalfEdge::arc(start, end, angle.rad(), objects) } }; + let half_edge = half_edge.insert(objects); cycle = cycle.add_half_edges([half_edge]); } - cycle.build(objects).insert(objects) + cycle.insert(objects) }; Face::new( From 00d5bfb86d452b8385d4e36e0b1ef993902af14c Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Thu, 30 Mar 2023 11:35:03 +0200 Subject: [PATCH 12/29] Remove unused `HalfEdgeBuilder::arc` --- crates/fj-kernel/src/builder/edge.rs | 27 +-------------------------- 1 file changed, 1 insertion(+), 26 deletions(-) diff --git a/crates/fj-kernel/src/builder/edge.rs b/crates/fj-kernel/src/builder/edge.rs index d2148297f..b7c4e262a 100644 --- a/crates/fj-kernel/src/builder/edge.rs +++ b/crates/fj-kernel/src/builder/edge.rs @@ -1,5 +1,5 @@ use fj_interop::ext::ArrayExt; -use fj_math::{Arc, Point, Scalar}; +use fj_math::Point; use crate::{ geometry::curve::Curve, @@ -28,31 +28,6 @@ impl HalfEdgeBuilder { } } - /// Create an arc - /// - /// # Panics - /// - /// Panics if the given angle is not within the range (-2pi, 2pi) radians. - pub fn arc( - start: impl Into>, - end: impl Into>, - angle_rad: impl Into, - ) -> Self { - 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 arc = Arc::from_endpoints_and_angle(start, end, angle_rad); - - let curve = - Curve::circle_from_center_and_radius(arc.center, arc.radius); - let boundary = - [arc.start_angle, arc.end_angle].map(|coord| Point::from([coord])); - - Self::new(curve, boundary) - } - /// Create a line segment pub fn line_segment( points_surface: [impl Into>; 2], From db75ff6349cda2ae27fe72c043bd8299679f4f98 Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Thu, 30 Mar 2023 11:46:14 +0200 Subject: [PATCH 13/29] Refactor code to simplify it --- crates/fj-kernel/src/algorithms/sweep/edge.rs | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/crates/fj-kernel/src/algorithms/sweep/edge.rs b/crates/fj-kernel/src/algorithms/sweep/edge.rs index 4526b163b..04577f2fa 100644 --- a/crates/fj-kernel/src/algorithms/sweep/edge.rs +++ b/crates/fj-kernel/src/algorithms/sweep/edge.rs @@ -4,7 +4,7 @@ use fj_math::{Point, Scalar, Vector}; use crate::{ builder::HalfEdgeBuilder, objects::{Cycle, Face, HalfEdge, Objects, Surface, Vertex}, - operations::Insert, + operations::{Insert, UpdateCycle}, services::Service, storage::Handle, }; @@ -94,15 +94,12 @@ impl Sweep for (&HalfEdge, &Handle, &Surface, Option) { builder.build(objects).insert(objects) }; - let updated = { - let exterior = exterior.take().unwrap(); - let half_edges = exterior - .half_edges() - .cloned() - .chain([half_edge.clone()]); - Cycle::new(half_edges) - }; - exterior = Some(updated); + exterior = Some( + exterior + .take() + .unwrap() + .add_half_edges([half_edge.clone()]), + ); half_edge }); From 289f0707255e193fb0cf5604f3b1742d498eff86 Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Thu, 30 Mar 2023 11:48:30 +0200 Subject: [PATCH 14/29] Add `UpdateHalfEdge::update_start_vertex` --- crates/fj-kernel/src/operations/update/edge.rs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/crates/fj-kernel/src/operations/update/edge.rs b/crates/fj-kernel/src/operations/update/edge.rs index 6a1f0f873..74b4ce630 100644 --- a/crates/fj-kernel/src/operations/update/edge.rs +++ b/crates/fj-kernel/src/operations/update/edge.rs @@ -1,15 +1,27 @@ use crate::{ - objects::{GlobalEdge, HalfEdge}, + objects::{GlobalEdge, HalfEdge, Vertex}, storage::Handle, }; /// Update a [`HalfEdge`] pub trait UpdateHalfEdge { + /// Update the start vertex of the half-edge + fn update_start_vertex(&self, start_vertex: Handle) -> HalfEdge; + /// Update the global form of the half-edge fn update_global_form(&self, global_form: Handle) -> HalfEdge; } impl UpdateHalfEdge for HalfEdge { + fn update_start_vertex(&self, start_vertex: Handle) -> HalfEdge { + HalfEdge::new( + self.curve(), + self.boundary(), + start_vertex, + self.global_form().clone(), + ) + } + fn update_global_form(&self, global_form: Handle) -> HalfEdge { HalfEdge::new( self.curve(), From 841f9ba2f4908a0340cf8b3b9066ee651f54defe Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Thu, 30 Mar 2023 11:50:12 +0200 Subject: [PATCH 15/29] Replace use of `HalfEdgeBuilder` --- crates/fj-kernel/src/algorithms/sweep/edge.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/crates/fj-kernel/src/algorithms/sweep/edge.rs b/crates/fj-kernel/src/algorithms/sweep/edge.rs index 04577f2fa..fdda20088 100644 --- a/crates/fj-kernel/src/algorithms/sweep/edge.rs +++ b/crates/fj-kernel/src/algorithms/sweep/edge.rs @@ -2,9 +2,8 @@ use fj_interop::{ext::ArrayExt, mesh::Color}; use fj_math::{Point, Scalar, Vector}; use crate::{ - builder::HalfEdgeBuilder, objects::{Cycle, Face, HalfEdge, Objects, Surface, Vertex}, - operations::{Insert, UpdateCycle}, + operations::{BuildHalfEdge, Insert, UpdateCycle, UpdateHalfEdge}, services::Service, storage::Handle, }; @@ -79,19 +78,20 @@ impl Sweep for (&HalfEdge, &Handle, &Surface, Option) { .zip_ext(global_edges) .map(|((((boundary, start), end), start_vertex), global_edge)| { let half_edge = { - let builder = HalfEdgeBuilder::line_segment( + let builder = HalfEdge::line_segment( [start, end], Some(boundary), + objects, ) - .with_start_vertex(start_vertex); + .update_start_vertex(start_vertex); let builder = if let Some(global_edge) = global_edge { - builder.with_global_form(global_edge) + builder.update_global_form(global_edge) } else { builder }; - builder.build(objects).insert(objects) + builder.insert(objects) }; exterior = Some( From 57654a0fec7168999a65b968d5cff5d3075fcad9 Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Thu, 30 Mar 2023 11:50:53 +0200 Subject: [PATCH 16/29] Update variable name --- crates/fj-kernel/src/algorithms/sweep/edge.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/fj-kernel/src/algorithms/sweep/edge.rs b/crates/fj-kernel/src/algorithms/sweep/edge.rs index fdda20088..af1590a51 100644 --- a/crates/fj-kernel/src/algorithms/sweep/edge.rs +++ b/crates/fj-kernel/src/algorithms/sweep/edge.rs @@ -78,7 +78,7 @@ impl Sweep for (&HalfEdge, &Handle, &Surface, Option) { .zip_ext(global_edges) .map(|((((boundary, start), end), start_vertex), global_edge)| { let half_edge = { - let builder = HalfEdge::line_segment( + let half_edge = HalfEdge::line_segment( [start, end], Some(boundary), objects, @@ -86,9 +86,9 @@ impl Sweep for (&HalfEdge, &Handle, &Surface, Option) { .update_start_vertex(start_vertex); let builder = if let Some(global_edge) = global_edge { - builder.update_global_form(global_edge) + half_edge.update_global_form(global_edge) } else { - builder + half_edge }; builder.insert(objects) From 093c797ca663edb05f56b2ae1466e523140f3b35 Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Thu, 30 Mar 2023 11:51:25 +0200 Subject: [PATCH 17/29] Update variable name --- crates/fj-kernel/src/algorithms/sweep/edge.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/fj-kernel/src/algorithms/sweep/edge.rs b/crates/fj-kernel/src/algorithms/sweep/edge.rs index af1590a51..dffe0eda3 100644 --- a/crates/fj-kernel/src/algorithms/sweep/edge.rs +++ b/crates/fj-kernel/src/algorithms/sweep/edge.rs @@ -85,13 +85,13 @@ impl Sweep for (&HalfEdge, &Handle, &Surface, Option) { ) .update_start_vertex(start_vertex); - let builder = if let Some(global_edge) = global_edge { + let half_edge = if let Some(global_edge) = global_edge { half_edge.update_global_form(global_edge) } else { half_edge }; - builder.insert(objects) + half_edge.insert(objects) }; exterior = Some( From 2ab02443f1f38900d8c29c5092ac3ffbd52acd51 Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Thu, 30 Mar 2023 12:00:17 +0200 Subject: [PATCH 18/29] Add new `BuildHalfEdge` method --- crates/fj-kernel/src/operations/build/edge.rs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/crates/fj-kernel/src/operations/build/edge.rs b/crates/fj-kernel/src/operations/build/edge.rs index 36e89f47d..cacd54cda 100644 --- a/crates/fj-kernel/src/operations/build/edge.rs +++ b/crates/fj-kernel/src/operations/build/edge.rs @@ -3,7 +3,7 @@ use fj_math::{Arc, Point, Scalar}; use crate::{ geometry::curve::Curve, - objects::{GlobalEdge, HalfEdge, Objects, Vertex}, + objects::{GlobalEdge, HalfEdge, Objects, Surface, Vertex}, operations::Insert, services::Service, }; @@ -74,6 +74,18 @@ pub trait BuildHalfEdge { HalfEdge::unjoined(curve, boundary, objects) } + + /// Create a line segment from global points + fn line_segment_from_global_points( + points_global: [impl Into>; 2], + surface: &Surface, + boundary: Option<[Point<1>; 2]>, + objects: &mut Service, + ) -> HalfEdge { + let points_surface = points_global + .map(|point| surface.geometry().project_global_point(point)); + HalfEdge::line_segment(points_surface, boundary, objects) + } } impl BuildHalfEdge for HalfEdge {} From c2d99928d6139937a110318b7eb6b4673e57e7b9 Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Thu, 30 Mar 2023 12:01:55 +0200 Subject: [PATCH 19/29] Replace use of `HalfEdgeBuilder` --- crates/fj-kernel/src/operations/build/face.rs | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/crates/fj-kernel/src/operations/build/face.rs b/crates/fj-kernel/src/operations/build/face.rs index e4c5af4c3..68cbb47d6 100644 --- a/crates/fj-kernel/src/operations/build/face.rs +++ b/crates/fj-kernel/src/operations/build/face.rs @@ -2,14 +2,13 @@ use fj_interop::ext::ArrayExt; use fj_math::Point; use crate::{ - builder::HalfEdgeBuilder, - objects::{Cycle, Face, GlobalEdge, Objects, Surface}, - operations::Insert, + objects::{Cycle, Face, GlobalEdge, HalfEdge, Objects, Surface}, + operations::{Insert, UpdateHalfEdge}, services::Service, storage::Handle, }; -use super::BuildSurface; +use super::{BuildHalfEdge, BuildSurface}; /// Build a [`Face`] pub trait BuildFace { @@ -25,16 +24,15 @@ pub trait BuildFace { let (exterior, edges) = { let half_edges = [[a, b], [b, c], [c, a]].zip_ext(edges).map( |(points, global_form)| { - let mut builder = - HalfEdgeBuilder::line_segment_from_global_points( - points, &surface, None, - ); + let mut builder = HalfEdge::line_segment_from_global_points( + points, &surface, None, objects, + ); if let Some(global_form) = global_form { - builder = builder.with_global_form(global_form); + builder = builder.update_global_form(global_form); } - builder.build(objects).insert(objects) + builder.insert(objects) }, ); From 3d980bee5ab6e09dfebb760e0e86769255e4c30c Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Thu, 30 Mar 2023 12:02:32 +0200 Subject: [PATCH 20/29] Update variable name --- crates/fj-kernel/src/operations/build/face.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/crates/fj-kernel/src/operations/build/face.rs b/crates/fj-kernel/src/operations/build/face.rs index 68cbb47d6..076e80ca5 100644 --- a/crates/fj-kernel/src/operations/build/face.rs +++ b/crates/fj-kernel/src/operations/build/face.rs @@ -24,15 +24,16 @@ pub trait BuildFace { let (exterior, edges) = { let half_edges = [[a, b], [b, c], [c, a]].zip_ext(edges).map( |(points, global_form)| { - let mut builder = HalfEdge::line_segment_from_global_points( - points, &surface, None, objects, - ); + let mut half_edge = + HalfEdge::line_segment_from_global_points( + points, &surface, None, objects, + ); if let Some(global_form) = global_form { - builder = builder.update_global_form(global_form); + half_edge = half_edge.update_global_form(global_form); } - builder.insert(objects) + half_edge.insert(objects) }, ); From 8a0dda92b1653467c42b8d4e1577ab8f3606421a Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Thu, 30 Mar 2023 12:03:13 +0200 Subject: [PATCH 21/29] Remove unused `HalfEdgeBuilder` method --- crates/fj-kernel/src/builder/edge.rs | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/crates/fj-kernel/src/builder/edge.rs b/crates/fj-kernel/src/builder/edge.rs index b7c4e262a..0028f1daa 100644 --- a/crates/fj-kernel/src/builder/edge.rs +++ b/crates/fj-kernel/src/builder/edge.rs @@ -3,7 +3,7 @@ use fj_math::Point; use crate::{ geometry::curve::Curve, - objects::{GlobalEdge, HalfEdge, Objects, Surface, Vertex}, + objects::{GlobalEdge, HalfEdge, Objects, Vertex}, operations::Insert, services::Service, storage::Handle, @@ -42,17 +42,6 @@ impl HalfEdgeBuilder { Self::new(curve, boundary) } - /// Create a line segment from global points - pub fn line_segment_from_global_points( - points_global: [impl Into>; 2], - surface: &Surface, - boundary: Option<[Point<1>; 2]>, - ) -> Self { - let points_surface = points_global - .map(|point| surface.geometry().project_global_point(point)); - Self::line_segment(points_surface, boundary) - } - /// Build the half-edge with a specific start vertex pub fn with_start_vertex(mut self, start_vertex: Handle) -> Self { self.start_vertex = Some(start_vertex); From 3adefe40e56b5094ff353a6eb6dbd312880b2b27 Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Thu, 30 Mar 2023 12:16:35 +0200 Subject: [PATCH 22/29] Refactor code to prepare for follow-on change --- crates/fj-kernel/src/builder/cycle.rs | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/crates/fj-kernel/src/builder/cycle.rs b/crates/fj-kernel/src/builder/cycle.rs index 00a19d165..89cd77fac 100644 --- a/crates/fj-kernel/src/builder/cycle.rs +++ b/crates/fj-kernel/src/builder/cycle.rs @@ -14,7 +14,7 @@ use super::HalfEdgeBuilder; /// Builder API for [`Cycle`] #[derive(Default)] pub struct CycleBuilder { - half_edges: Vec, + half_edges: Vec, } impl CycleBuilder { @@ -28,6 +28,9 @@ impl CycleBuilder { mut self, half_edges: impl IntoIterator, ) -> Self { + let half_edges = half_edges + .into_iter() + .map(HalfEdgeOrHalfEdgeBuilder::HalfEdgeBuilder); self.half_edges.extend(half_edges); self } @@ -52,6 +55,7 @@ impl CycleBuilder { .with_start_vertex(prev.start_vertex().clone()) .with_global_form(half_edge.global_form().clone()) }) + .map(HalfEdgeOrHalfEdgeBuilder::HalfEdgeBuilder) .collect(); Self { half_edges } @@ -71,6 +75,7 @@ impl CycleBuilder { .map(|(start, end)| { HalfEdgeBuilder::line_segment([start, end], None) }) + .map(HalfEdgeOrHalfEdgeBuilder::HalfEdgeBuilder) .collect(); Self { half_edges } @@ -78,10 +83,21 @@ impl CycleBuilder { /// Build the cycle pub fn build(self, objects: &mut Service) -> Cycle { - let half_edges = self - .half_edges - .into_iter() - .map(|half_edge| half_edge.build(objects).insert(objects)); + let half_edges = self.half_edges.into_iter().map(|half_edge| { + let half_edge = match half_edge { + HalfEdgeOrHalfEdgeBuilder::HalfEdge(half_edge) => half_edge, + HalfEdgeOrHalfEdgeBuilder::HalfEdgeBuilder(half_edge) => { + half_edge.build(objects) + } + }; + half_edge.insert(objects) + }); Cycle::new(half_edges) } } + +enum HalfEdgeOrHalfEdgeBuilder { + #[allow(unused)] + HalfEdge(HalfEdge), + HalfEdgeBuilder(HalfEdgeBuilder), +} From e72e288c670e5845f2e0ba6a10eebfeca60e8610 Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Thu, 30 Mar 2023 12:19:58 +0200 Subject: [PATCH 23/29] Replace use of `HalfEdgeBuilder` --- .../src/algorithms/intersect/curve_face.rs | 10 ++- .../src/algorithms/intersect/face_face.rs | 10 ++- .../src/algorithms/intersect/face_point.rs | 76 ++++++++----------- .../src/algorithms/intersect/ray_face.rs | 70 +++++++---------- .../src/algorithms/triangulate/mod.rs | 20 ++++- crates/fj-kernel/src/builder/cycle.rs | 8 +- crates/fj-kernel/src/validate/cycle.rs | 7 +- crates/fj-kernel/src/validate/face.rs | 18 ++--- 8 files changed, 109 insertions(+), 110 deletions(-) diff --git a/crates/fj-kernel/src/algorithms/intersect/curve_face.rs b/crates/fj-kernel/src/algorithms/intersect/curve_face.rs index 8e41209be..4ff2c6c08 100644 --- a/crates/fj-kernel/src/algorithms/intersect/curve_face.rs +++ b/crates/fj-kernel/src/algorithms/intersect/curve_face.rs @@ -179,8 +179,14 @@ mod tests { ]; let face = FaceBuilder::new(services.objects.surfaces.xy_plane()) - .with_exterior(CycleBuilder::polygon(exterior_points)) - .with_interior(CycleBuilder::polygon(interior_points)) + .with_exterior(CycleBuilder::polygon( + exterior_points, + &mut services.objects, + )) + .with_interior(CycleBuilder::polygon( + interior_points, + &mut services.objects, + )) .build(&mut services.objects); let expected = diff --git a/crates/fj-kernel/src/algorithms/intersect/face_face.rs b/crates/fj-kernel/src/algorithms/intersect/face_face.rs index 10d748afa..dbee4285e 100644 --- a/crates/fj-kernel/src/algorithms/intersect/face_face.rs +++ b/crates/fj-kernel/src/algorithms/intersect/face_face.rs @@ -86,7 +86,10 @@ mod tests { ] .map(|surface| { FaceBuilder::new(surface) - .with_exterior(CycleBuilder::polygon(points)) + .with_exterior(CycleBuilder::polygon( + points, + &mut services.objects, + )) .build(&mut services.objects) }); @@ -112,7 +115,10 @@ mod tests { ]; let [a, b] = surfaces.clone().map(|surface| { FaceBuilder::new(surface) - .with_exterior(CycleBuilder::polygon(points)) + .with_exterior(CycleBuilder::polygon( + points, + &mut services.objects, + )) .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 1dcb4d579..5f8c9202b 100644 --- a/crates/fj-kernel/src/algorithms/intersect/face_point.rs +++ b/crates/fj-kernel/src/algorithms/intersect/face_point.rs @@ -147,11 +147,10 @@ mod tests { let mut services = Services::new(); let face = FaceBuilder::new(services.objects.surfaces.xy_plane()) - .with_exterior(CycleBuilder::polygon([ - [0., 0.], - [1., 1.], - [0., 2.], - ])) + .with_exterior(CycleBuilder::polygon( + [[0., 0.], [1., 1.], [0., 2.]], + &mut services.objects, + )) .build(&mut services.objects); let point = Point::from([2., 1.]); @@ -164,11 +163,10 @@ mod tests { let mut services = Services::new(); let face = FaceBuilder::new(services.objects.surfaces.xy_plane()) - .with_exterior(CycleBuilder::polygon([ - [0., 0.], - [2., 1.], - [0., 2.], - ])) + .with_exterior(CycleBuilder::polygon( + [[0., 0.], [2., 1.], [0., 2.]], + &mut services.objects, + )) .build(&mut services.objects); let point = Point::from([1., 1.]); @@ -184,11 +182,10 @@ mod tests { let mut services = Services::new(); let face = FaceBuilder::new(services.objects.surfaces.xy_plane()) - .with_exterior(CycleBuilder::polygon([ - [4., 2.], - [0., 4.], - [0., 0.], - ])) + .with_exterior(CycleBuilder::polygon( + [[4., 2.], [0., 4.], [0., 0.]], + &mut services.objects, + )) .build(&mut services.objects); let point = Point::from([1., 2.]); @@ -204,12 +201,10 @@ mod tests { let mut services = Services::new(); let face = FaceBuilder::new(services.objects.surfaces.xy_plane()) - .with_exterior(CycleBuilder::polygon([ - [0., 0.], - [2., 1.], - [3., 0.], - [3., 4.], - ])) + .with_exterior(CycleBuilder::polygon( + [[0., 0.], [2., 1.], [3., 0.], [3., 4.]], + &mut services.objects, + )) .build(&mut services.objects); let point = Point::from([1., 1.]); @@ -225,12 +220,10 @@ mod tests { let mut services = Services::new(); let face = FaceBuilder::new(services.objects.surfaces.xy_plane()) - .with_exterior(CycleBuilder::polygon([ - [0., 0.], - [2., 1.], - [3., 1.], - [0., 2.], - ])) + .with_exterior(CycleBuilder::polygon( + [[0., 0.], [2., 1.], [3., 1.], [0., 2.]], + &mut services.objects, + )) .build(&mut services.objects); let point = Point::from([1., 1.]); @@ -246,13 +239,10 @@ mod tests { let mut services = Services::new(); let face = FaceBuilder::new(services.objects.surfaces.xy_plane()) - .with_exterior(CycleBuilder::polygon([ - [0., 0.], - [2., 1.], - [3., 1.], - [4., 0.], - [4., 5.], - ])) + .with_exterior(CycleBuilder::polygon( + [[0., 0.], [2., 1.], [3., 1.], [4., 0.], [4., 5.]], + &mut services.objects, + )) .build(&mut services.objects); let point = Point::from([1., 1.]); @@ -268,11 +258,10 @@ mod tests { let mut services = Services::new(); let face = FaceBuilder::new(services.objects.surfaces.xy_plane()) - .with_exterior(CycleBuilder::polygon([ - [0., 0.], - [2., 0.], - [0., 1.], - ])) + .with_exterior(CycleBuilder::polygon( + [[0., 0.], [2., 0.], [0., 1.]], + &mut services.objects, + )) .build(&mut services.objects); let point = Point::from([1., 0.]); @@ -294,11 +283,10 @@ mod tests { let mut services = Services::new(); let face = FaceBuilder::new(services.objects.surfaces.xy_plane()) - .with_exterior(CycleBuilder::polygon([ - [0., 0.], - [1., 0.], - [0., 1.], - ])) + .with_exterior(CycleBuilder::polygon( + [[0., 0.], [1., 0.], [0., 1.]], + &mut services.objects, + )) .build(&mut services.objects); let point = Point::from([1., 0.]); diff --git a/crates/fj-kernel/src/algorithms/intersect/ray_face.rs b/crates/fj-kernel/src/algorithms/intersect/ray_face.rs index a8277410f..d1b5e17a5 100644 --- a/crates/fj-kernel/src/algorithms/intersect/ray_face.rs +++ b/crates/fj-kernel/src/algorithms/intersect/ray_face.rs @@ -162,12 +162,10 @@ mod tests { let ray = HorizontalRayToTheRight::from([0., 0., 0.]); let face = FaceBuilder::new(services.objects.surfaces.yz_plane()) - .with_exterior(CycleBuilder::polygon([ - [-1., -1.], - [1., -1.], - [1., 1.], - [-1., 1.], - ])) + .with_exterior(CycleBuilder::polygon( + [[-1., -1.], [1., -1.], [1., 1.], [-1., 1.]], + &mut services.objects, + )) .build(&mut services.objects); let face = face.translate([-1., 0., 0.], &mut services.objects); @@ -181,12 +179,10 @@ mod tests { let ray = HorizontalRayToTheRight::from([0., 0., 0.]); let face = FaceBuilder::new(services.objects.surfaces.yz_plane()) - .with_exterior(CycleBuilder::polygon([ - [-1., -1.], - [1., -1.], - [1., 1.], - [-1., 1.], - ])) + .with_exterior(CycleBuilder::polygon( + [[-1., -1.], [1., -1.], [1., 1.], [-1., 1.]], + &mut services.objects, + )) .build(&mut services.objects); let face = face.translate([1., 0., 0.], &mut services.objects); @@ -203,12 +199,10 @@ mod tests { let ray = HorizontalRayToTheRight::from([0., 0., 0.]); let face = FaceBuilder::new(services.objects.surfaces.yz_plane()) - .with_exterior(CycleBuilder::polygon([ - [-1., -1.], - [1., -1.], - [1., 1.], - [-1., 1.], - ])) + .with_exterior(CycleBuilder::polygon( + [[-1., -1.], [1., -1.], [1., 1.], [-1., 1.]], + &mut services.objects, + )) .build(&mut services.objects); let face = face.translate([0., 0., 2.], &mut services.objects); @@ -222,12 +216,10 @@ mod tests { let ray = HorizontalRayToTheRight::from([0., 0., 0.]); let face = FaceBuilder::new(services.objects.surfaces.yz_plane()) - .with_exterior(CycleBuilder::polygon([ - [-1., -1.], - [1., -1.], - [1., 1.], - [-1., 1.], - ])) + .with_exterior(CycleBuilder::polygon( + [[-1., -1.], [1., -1.], [1., 1.], [-1., 1.]], + &mut services.objects, + )) .build(&mut services.objects); let face = face.translate([1., 1., 0.], &mut services.objects); @@ -249,12 +241,10 @@ mod tests { let ray = HorizontalRayToTheRight::from([0., 0., 0.]); let face = FaceBuilder::new(services.objects.surfaces.yz_plane()) - .with_exterior(CycleBuilder::polygon([ - [-1., -1.], - [1., -1.], - [1., 1.], - [-1., 1.], - ])) + .with_exterior(CycleBuilder::polygon( + [[-1., -1.], [1., -1.], [1., 1.], [-1., 1.]], + &mut services.objects, + )) .build(&mut services.objects); let face = face.translate([1., 1., 1.], &mut services.objects); @@ -279,12 +269,10 @@ mod tests { let ray = HorizontalRayToTheRight::from([0., 0., 0.]); let face = FaceBuilder::new(services.objects.surfaces.xy_plane()) - .with_exterior(CycleBuilder::polygon([ - [-1., -1.], - [1., -1.], - [1., 1.], - [-1., 1.], - ])) + .with_exterior(CycleBuilder::polygon( + [[-1., -1.], [1., -1.], [1., 1.], [-1., 1.]], + &mut services.objects, + )) .build(&mut services.objects); assert_eq!( @@ -300,12 +288,10 @@ mod tests { let ray = HorizontalRayToTheRight::from([0., 0., 0.]); let face = FaceBuilder::new(services.objects.surfaces.xy_plane()) - .with_exterior(CycleBuilder::polygon([ - [-1., -1.], - [1., -1.], - [1., 1.], - [-1., 1.], - ])) + .with_exterior(CycleBuilder::polygon( + [[-1., -1.], [1., -1.], [1., 1.], [-1., 1.]], + &mut services.objects, + )) .build(&mut services.objects); let face = face.translate([0., 0., 1.], &mut services.objects); diff --git a/crates/fj-kernel/src/algorithms/triangulate/mod.rs b/crates/fj-kernel/src/algorithms/triangulate/mod.rs index 28281353c..18889bb75 100644 --- a/crates/fj-kernel/src/algorithms/triangulate/mod.rs +++ b/crates/fj-kernel/src/algorithms/triangulate/mod.rs @@ -96,7 +96,10 @@ mod tests { let d = [0., 1.]; let face = FaceBuilder::new(services.objects.surfaces.xy_plane()) - .with_exterior(CycleBuilder::polygon([a, b, c, d])) + .with_exterior(CycleBuilder::polygon( + [a, b, c, d], + &mut services.objects, + )) .build(&mut services.objects); let a = Point::from(a).to_xyz(); @@ -131,8 +134,14 @@ mod tests { let surface = services.objects.surfaces.xy_plane(); let face = FaceBuilder::new(surface.clone()) - .with_exterior(CycleBuilder::polygon([a, b, c, d])) - .with_interior(CycleBuilder::polygon([e, f, g, h])) + .with_exterior(CycleBuilder::polygon( + [a, b, c, d], + &mut services.objects, + )) + .with_interior(CycleBuilder::polygon( + [e, f, g, h], + &mut services.objects, + )) .build(&mut services.objects); let triangles = triangulate(face)?; @@ -189,7 +198,10 @@ mod tests { let surface = services.objects.surfaces.xy_plane(); let face = FaceBuilder::new(surface.clone()) - .with_exterior(CycleBuilder::polygon([a, b, c, d, e])) + .with_exterior(CycleBuilder::polygon( + [a, b, c, d, e], + &mut services.objects, + )) .build(&mut services.objects); let triangles = triangulate(face)?; diff --git a/crates/fj-kernel/src/builder/cycle.rs b/crates/fj-kernel/src/builder/cycle.rs index 89cd77fac..df5e1e6e8 100644 --- a/crates/fj-kernel/src/builder/cycle.rs +++ b/crates/fj-kernel/src/builder/cycle.rs @@ -4,7 +4,7 @@ use itertools::Itertools; use crate::{ geometry::curve::Curve, objects::{Cycle, HalfEdge, Objects}, - operations::Insert, + operations::{BuildHalfEdge, Insert}, services::Service, storage::Handle, }; @@ -62,7 +62,7 @@ impl CycleBuilder { } /// Create a polygon - pub fn polygon(points: Ps) -> Self + pub fn polygon(points: Ps, objects: &mut Service) -> Self where P: Into>, Ps: IntoIterator, @@ -73,9 +73,9 @@ impl CycleBuilder { .map(Into::into) .circular_tuple_windows() .map(|(start, end)| { - HalfEdgeBuilder::line_segment([start, end], None) + HalfEdge::line_segment([start, end], None, objects) }) - .map(HalfEdgeOrHalfEdgeBuilder::HalfEdgeBuilder) + .map(HalfEdgeOrHalfEdgeBuilder::HalfEdge) .collect(); Self { half_edges } diff --git a/crates/fj-kernel/src/validate/cycle.rs b/crates/fj-kernel/src/validate/cycle.rs index baeaf92cb..b1ae299d7 100644 --- a/crates/fj-kernel/src/validate/cycle.rs +++ b/crates/fj-kernel/src/validate/cycle.rs @@ -107,8 +107,11 @@ mod tests { fn half_edges_connected() -> anyhow::Result<()> { let mut services = Services::new(); - let valid = CycleBuilder::polygon([[0.0, 0.0], [1.0, 0.0], [1.0, 1.0]]) - .build(&mut services.objects); + let valid = CycleBuilder::polygon( + [[0.0, 0.0], [1.0, 0.0], [1.0, 1.0]], + &mut services.objects, + ) + .build(&mut services.objects); valid.validate_and_return_first_error()?; diff --git a/crates/fj-kernel/src/validate/face.rs b/crates/fj-kernel/src/validate/face.rs index bf4857d27..1dc0c8be1 100644 --- a/crates/fj-kernel/src/validate/face.rs +++ b/crates/fj-kernel/src/validate/face.rs @@ -84,16 +84,14 @@ mod tests { let mut services = Services::new(); let valid = FaceBuilder::new(services.objects.surfaces.xy_plane()) - .with_exterior(CycleBuilder::polygon([ - [0., 0.], - [3., 0.], - [0., 3.], - ])) - .with_interior(CycleBuilder::polygon([ - [1., 1.], - [1., 2.], - [2., 1.], - ])) + .with_exterior(CycleBuilder::polygon( + [[0., 0.], [3., 0.], [0., 3.]], + &mut services.objects, + )) + .with_interior(CycleBuilder::polygon( + [[1., 1.], [1., 2.], [2., 1.]], + &mut services.objects, + )) .build(&mut services.objects); let invalid = { let interiors = valid From 205d565d58345e42d4d188e699b5a9112859f32f Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Thu, 30 Mar 2023 12:20:59 +0200 Subject: [PATCH 24/29] Remove unused `HalfEdgeBuilder::line_segment` --- crates/fj-kernel/src/builder/edge.rs | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/crates/fj-kernel/src/builder/edge.rs b/crates/fj-kernel/src/builder/edge.rs index 0028f1daa..0bc26b479 100644 --- a/crates/fj-kernel/src/builder/edge.rs +++ b/crates/fj-kernel/src/builder/edge.rs @@ -1,4 +1,3 @@ -use fj_interop::ext::ArrayExt; use fj_math::Point; use crate::{ @@ -28,20 +27,6 @@ impl HalfEdgeBuilder { } } - /// Create a line segment - pub fn line_segment( - points_surface: [impl Into>; 2], - boundary: Option<[Point<1>; 2]>, - ) -> Self { - let boundary = - boundary.unwrap_or_else(|| [[0.], [1.]].map(Point::from)); - let curve = Curve::line_from_points_with_coords( - boundary.zip_ext(points_surface), - ); - - Self::new(curve, boundary) - } - /// Build the half-edge with a specific start vertex pub fn with_start_vertex(mut self, start_vertex: Handle) -> Self { self.start_vertex = Some(start_vertex); From 7a4e0d6c953ca8b25b6afbb4ab00872ed3c83e4e Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Thu, 30 Mar 2023 12:22:43 +0200 Subject: [PATCH 25/29] Replace use of `HalfEdgeBuilder` --- crates/fj-kernel/src/algorithms/sweep/face.rs | 4 ++-- crates/fj-kernel/src/builder/cycle.rs | 15 +++++++++------ 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/crates/fj-kernel/src/algorithms/sweep/face.rs b/crates/fj-kernel/src/algorithms/sweep/face.rs index 465c74d92..26dddd24e 100644 --- a/crates/fj-kernel/src/algorithms/sweep/face.rs +++ b/crates/fj-kernel/src/algorithms/sweep/face.rs @@ -82,8 +82,8 @@ impl Sweep for Handle { )); } - let top_cycle = - CycleBuilder::connect_to_edges(top_edges).build(objects); + let top_cycle = CycleBuilder::connect_to_edges(top_edges, objects) + .build(objects); if i == 0 { exterior = Some(top_cycle.insert(objects)); diff --git a/crates/fj-kernel/src/builder/cycle.rs b/crates/fj-kernel/src/builder/cycle.rs index df5e1e6e8..7c317681f 100644 --- a/crates/fj-kernel/src/builder/cycle.rs +++ b/crates/fj-kernel/src/builder/cycle.rs @@ -4,7 +4,7 @@ use itertools::Itertools; use crate::{ geometry::curve::Curve, objects::{Cycle, HalfEdge, Objects}, - operations::{BuildHalfEdge, Insert}, + operations::{BuildHalfEdge, Insert, UpdateHalfEdge}, services::Service, storage::Handle, }; @@ -42,7 +42,10 @@ impl CycleBuilder { /// /// Assumes that the provided half-edges, once translated into local /// equivalents of this cycle, form a cycle themselves. - pub fn connect_to_edges(edges: Es) -> Self + pub fn connect_to_edges( + edges: Es, + objects: &mut Service, + ) -> Self where Es: IntoIterator, Curve, [Point<1>; 2])>, Es::IntoIter: Clone + ExactSizeIterator, @@ -51,11 +54,11 @@ impl CycleBuilder { .into_iter() .circular_tuple_windows() .map(|((prev, _, _), (half_edge, curve, boundary))| { - HalfEdgeBuilder::new(curve, boundary) - .with_start_vertex(prev.start_vertex().clone()) - .with_global_form(half_edge.global_form().clone()) + HalfEdge::unjoined(curve, boundary, objects) + .update_start_vertex(prev.start_vertex().clone()) + .update_global_form(half_edge.global_form().clone()) }) - .map(HalfEdgeOrHalfEdgeBuilder::HalfEdgeBuilder) + .map(HalfEdgeOrHalfEdgeBuilder::HalfEdge) .collect(); Self { half_edges } From b3c6ae9de8e74a01a4edf25281a72c6f0c473f75 Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Thu, 30 Mar 2023 12:24:19 +0200 Subject: [PATCH 26/29] Remove unused `HalfEdgeBuilder` methods --- crates/fj-kernel/src/builder/edge.rs | 22 ---------------------- 1 file changed, 22 deletions(-) diff --git a/crates/fj-kernel/src/builder/edge.rs b/crates/fj-kernel/src/builder/edge.rs index 0bc26b479..3cc544596 100644 --- a/crates/fj-kernel/src/builder/edge.rs +++ b/crates/fj-kernel/src/builder/edge.rs @@ -17,28 +17,6 @@ pub struct HalfEdgeBuilder { } impl HalfEdgeBuilder { - /// Create an instance of `HalfEdgeBuilder` - pub fn new(curve: Curve, boundary: [Point<1>; 2]) -> Self { - Self { - curve, - boundary, - start_vertex: None, - global_form: None, - } - } - - /// Build the half-edge with a specific start vertex - pub fn with_start_vertex(mut self, start_vertex: Handle) -> Self { - self.start_vertex = Some(start_vertex); - self - } - - /// Build the half-edge with a specific global form - pub fn with_global_form(mut self, global_form: Handle) -> Self { - self.global_form = Some(global_form); - self - } - /// Build the half-edge pub fn build(self, objects: &mut Service) -> HalfEdge { HalfEdge::new( From 2ca7945f5abfcac97f13d0a789e635986c25800c Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Thu, 30 Mar 2023 12:25:22 +0200 Subject: [PATCH 27/29] Remove unused `CycleBuilder` method --- crates/fj-kernel/src/builder/cycle.rs | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/crates/fj-kernel/src/builder/cycle.rs b/crates/fj-kernel/src/builder/cycle.rs index 7c317681f..0b26d6dda 100644 --- a/crates/fj-kernel/src/builder/cycle.rs +++ b/crates/fj-kernel/src/builder/cycle.rs @@ -23,18 +23,6 @@ impl CycleBuilder { Self::default() } - /// Add a half-edge to the cycle - pub fn add_half_edges( - mut self, - half_edges: impl IntoIterator, - ) -> Self { - let half_edges = half_edges - .into_iter() - .map(HalfEdgeOrHalfEdgeBuilder::HalfEdgeBuilder); - self.half_edges.extend(half_edges); - self - } - /// Create a cycle whose half-edges are connected to the provided half-edges /// /// The half-edges of the new circle will be coincident with the provided @@ -100,7 +88,7 @@ impl CycleBuilder { } enum HalfEdgeOrHalfEdgeBuilder { - #[allow(unused)] HalfEdge(HalfEdge), + #[allow(unused)] HalfEdgeBuilder(HalfEdgeBuilder), } From fe69359ac279073d637c954116348ce7a6c69dfc Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Thu, 30 Mar 2023 12:26:31 +0200 Subject: [PATCH 28/29] Clean up `CycleBuilder` --- crates/fj-kernel/src/builder/cycle.rs | 25 +++++-------------------- 1 file changed, 5 insertions(+), 20 deletions(-) diff --git a/crates/fj-kernel/src/builder/cycle.rs b/crates/fj-kernel/src/builder/cycle.rs index 0b26d6dda..fa84e4cb2 100644 --- a/crates/fj-kernel/src/builder/cycle.rs +++ b/crates/fj-kernel/src/builder/cycle.rs @@ -9,12 +9,10 @@ use crate::{ storage::Handle, }; -use super::HalfEdgeBuilder; - /// Builder API for [`Cycle`] #[derive(Default)] pub struct CycleBuilder { - half_edges: Vec, + half_edges: Vec, } impl CycleBuilder { @@ -46,7 +44,6 @@ impl CycleBuilder { .update_start_vertex(prev.start_vertex().clone()) .update_global_form(half_edge.global_form().clone()) }) - .map(HalfEdgeOrHalfEdgeBuilder::HalfEdge) .collect(); Self { half_edges } @@ -66,7 +63,6 @@ impl CycleBuilder { .map(|(start, end)| { HalfEdge::line_segment([start, end], None, objects) }) - .map(HalfEdgeOrHalfEdgeBuilder::HalfEdge) .collect(); Self { half_edges } @@ -74,21 +70,10 @@ impl CycleBuilder { /// Build the cycle pub fn build(self, objects: &mut Service) -> Cycle { - let half_edges = self.half_edges.into_iter().map(|half_edge| { - let half_edge = match half_edge { - HalfEdgeOrHalfEdgeBuilder::HalfEdge(half_edge) => half_edge, - HalfEdgeOrHalfEdgeBuilder::HalfEdgeBuilder(half_edge) => { - half_edge.build(objects) - } - }; - half_edge.insert(objects) - }); + let half_edges = self + .half_edges + .into_iter() + .map(|half_edge| half_edge.insert(objects)); Cycle::new(half_edges) } } - -enum HalfEdgeOrHalfEdgeBuilder { - HalfEdge(HalfEdge), - #[allow(unused)] - HalfEdgeBuilder(HalfEdgeBuilder), -} From da6cc2ec96d24241a6c8cc7e12e0b5d781be01cc Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Thu, 30 Mar 2023 12:27:41 +0200 Subject: [PATCH 29/29] Remove unused `HalfEdgeBuilder` --- crates/fj-kernel/src/builder/edge.rs | 31 ---------------------------- crates/fj-kernel/src/builder/mod.rs | 3 +-- 2 files changed, 1 insertion(+), 33 deletions(-) delete mode 100644 crates/fj-kernel/src/builder/edge.rs diff --git a/crates/fj-kernel/src/builder/edge.rs b/crates/fj-kernel/src/builder/edge.rs deleted file mode 100644 index 3cc544596..000000000 --- a/crates/fj-kernel/src/builder/edge.rs +++ /dev/null @@ -1,31 +0,0 @@ -use fj_math::Point; - -use crate::{ - geometry::curve::Curve, - objects::{GlobalEdge, HalfEdge, Objects, Vertex}, - operations::Insert, - services::Service, - storage::Handle, -}; - -/// Builder API for [`HalfEdge`] -pub struct HalfEdgeBuilder { - curve: Curve, - boundary: [Point<1>; 2], - start_vertex: Option>, - global_form: Option>, -} - -impl HalfEdgeBuilder { - /// Build the half-edge - pub fn build(self, objects: &mut Service) -> HalfEdge { - HalfEdge::new( - self.curve, - self.boundary, - self.start_vertex - .unwrap_or_else(|| Vertex::new().insert(objects)), - self.global_form - .unwrap_or_else(|| GlobalEdge::new().insert(objects)), - ) - } -} diff --git a/crates/fj-kernel/src/builder/mod.rs b/crates/fj-kernel/src/builder/mod.rs index 50756e908..067bb759d 100644 --- a/crates/fj-kernel/src/builder/mod.rs +++ b/crates/fj-kernel/src/builder/mod.rs @@ -1,7 +1,6 @@ //! API for building objects mod cycle; -mod edge; mod face; -pub use self::{cycle::CycleBuilder, edge::HalfEdgeBuilder, face::FaceBuilder}; +pub use self::{cycle::CycleBuilder, face::FaceBuilder};