From 210f8ac27bc779ab078c68e57fa0fd00b4beef91 Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Sat, 23 Mar 2024 00:33:30 +0100 Subject: [PATCH 01/18] Refactor to reduce redundancy --- crates/fj-core/src/operations/split/half_edge.rs | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/crates/fj-core/src/operations/split/half_edge.rs b/crates/fj-core/src/operations/split/half_edge.rs index 9279599a8..eacb111f4 100644 --- a/crates/fj-core/src/operations/split/half_edge.rs +++ b/crates/fj-core/src/operations/split/half_edge.rs @@ -42,6 +42,7 @@ impl SplitHalfEdge for Handle { ) -> [Handle; 2] { let point = point.into(); + let geometry = core.layers.geometry.of_half_edge(self); let [start, end] = self.boundary().inner; let a = HalfEdge::new( @@ -52,10 +53,7 @@ impl SplitHalfEdge for Handle { .insert(core) .derive_from(self, core) .set_geometry( - core.layers - .geometry - .of_half_edge(self) - .with_boundary([start, point]), + geometry.with_boundary([start, point]), &mut core.layers.geometry, ); let b = HalfEdge::new( @@ -66,10 +64,7 @@ impl SplitHalfEdge for Handle { .insert(core) .derive_from(self, core) .set_geometry( - core.layers - .geometry - .of_half_edge(self) - .with_boundary([point, end]), + geometry.with_boundary([point, end]), &mut core.layers.geometry, ); From f2621c4e888bdcfe2735c77bc52e95c3248cd506 Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Sat, 23 Mar 2024 00:34:52 +0100 Subject: [PATCH 02/18] Read boundary from layer in `SplitHalfEdge` --- crates/fj-core/src/operations/split/half_edge.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/fj-core/src/operations/split/half_edge.rs b/crates/fj-core/src/operations/split/half_edge.rs index eacb111f4..ebe1ef0a1 100644 --- a/crates/fj-core/src/operations/split/half_edge.rs +++ b/crates/fj-core/src/operations/split/half_edge.rs @@ -43,7 +43,7 @@ impl SplitHalfEdge for Handle { let point = point.into(); let geometry = core.layers.geometry.of_half_edge(self); - let [start, end] = self.boundary().inner; + let [start, end] = geometry.boundary.inner; let a = HalfEdge::new( [start, point], From f392d9a8078ba599a63825251929a1925df2cfd2 Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Sat, 23 Mar 2024 00:38:05 +0100 Subject: [PATCH 03/18] Rename variables to prepare for follow-on change --- crates/fj-core/src/algorithms/approx/curve.rs | 33 +++++++++---------- 1 file changed, 15 insertions(+), 18 deletions(-) diff --git a/crates/fj-core/src/algorithms/approx/curve.rs b/crates/fj-core/src/algorithms/approx/curve.rs index f76043d48..db90e56b7 100644 --- a/crates/fj-core/src/algorithms/approx/curve.rs +++ b/crates/fj-core/src/algorithms/approx/curve.rs @@ -198,14 +198,14 @@ mod tests { let mut core = Core::new(); let curve = Curve::new().insert(&mut core); - let (surface_path, boundary) = + let (path, boundary) = SurfacePath::line_from_points([[1., 1.], [2., 1.]]); let boundary = CurveBoundary::from(boundary); let surface = core.layers.geometry.xz_plane(); let tolerance = 1.; - let approx = (&curve, surface_path, &surface, boundary) - .approx(tolerance, &mut core); + let approx = + (&curve, path, &surface, boundary).approx(tolerance, &mut core); assert_eq!(approx.points, vec![]); } @@ -215,7 +215,7 @@ mod tests { let mut core = Core::new(); let curve = Curve::new().insert(&mut core); - let (surface_path, boundary) = + let (path, boundary) = SurfacePath::line_from_points([[1., 1.], [2., 1.]]); let boundary = CurveBoundary::from(boundary); let surface = SurfaceGeometry { @@ -224,8 +224,8 @@ mod tests { }; let tolerance = 1.; - let approx = (&curve, surface_path, &surface, boundary) - .approx(tolerance, &mut core); + let approx = + (&curve, path, &surface, boundary).approx(tolerance, &mut core); assert_eq!(approx.points, vec![]); } @@ -236,7 +236,7 @@ mod tests { let global_path = GlobalPath::circle_from_radius(1.); let curve = Curve::new().insert(&mut core); - let surface_path = SurfacePath::line_from_points_with_coords([ + let path = SurfacePath::line_from_points_with_coords([ ([0.], [0., 1.]), ([TAU], [TAU, 1.]), ]); @@ -247,15 +247,14 @@ mod tests { }; let tolerance = 1.; - let approx = (&curve, surface_path, &surface, boundary) - .approx(tolerance, &mut core); + let approx = + (&curve, path, &surface, boundary).approx(tolerance, &mut core); let expected_approx = (global_path, boundary) .approx(tolerance, &mut core) .into_iter() .map(|(point_local, _)| { - let point_surface = - surface_path.point_from_path_coords(point_local); + let point_surface = path.point_from_path_coords(point_local); let point_global = surface.point_from_surface_coords(point_surface); ApproxPoint::new(point_local, point_global) @@ -269,21 +268,19 @@ mod tests { let mut core = Core::new(); let curve = Curve::new().insert(&mut core); - let surface_path = - SurfacePath::circle_from_center_and_radius([0., 0.], 1.); + let path = SurfacePath::circle_from_center_and_radius([0., 0.], 1.); let boundary = CurveBoundary::from([[0.], [TAU]]); let surface = core.layers.geometry.xz_plane(); let tolerance = 1.; - let approx = (&curve, surface_path, &surface, boundary) - .approx(tolerance, &mut core); + let approx = + (&curve, path, &surface, boundary).approx(tolerance, &mut core); - let expected_approx = (&surface_path, boundary) + let expected_approx = (&path, boundary) .approx(tolerance, &mut core) .into_iter() .map(|(point_local, _)| { - let point_surface = - surface_path.point_from_path_coords(point_local); + let point_surface = path.point_from_path_coords(point_local); let point_global = surface.point_from_surface_coords(point_surface); ApproxPoint::new(point_local, point_global) From bf3b6b5b8272aed86dc03d22f2f304f1e15b0b9a Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Sat, 23 Mar 2024 00:40:40 +0100 Subject: [PATCH 04/18] Simplify arguments of curve approximation impl --- crates/fj-core/src/algorithms/approx/curve.rs | 41 ++++++++++--------- crates/fj-core/src/algorithms/approx/edge.rs | 3 +- 2 files changed, 23 insertions(+), 21 deletions(-) diff --git a/crates/fj-core/src/algorithms/approx/curve.rs b/crates/fj-core/src/algorithms/approx/curve.rs index db90e56b7..6a5dc4bfa 100644 --- a/crates/fj-core/src/algorithms/approx/curve.rs +++ b/crates/fj-core/src/algorithms/approx/curve.rs @@ -5,7 +5,10 @@ use std::collections::BTreeMap; use fj_math::Point; use crate::{ - geometry::{CurveBoundary, GlobalPath, SurfaceGeometry, SurfacePath}, + geometry::{ + CurveBoundary, GlobalPath, HalfEdgeGeometry, SurfaceGeometry, + SurfacePath, + }, objects::Curve, storage::Handle, Core, @@ -13,14 +16,7 @@ use crate::{ use super::{Approx, ApproxPoint, Tolerance}; -impl Approx - for ( - &Handle, - SurfacePath, - &SurfaceGeometry, - CurveBoundary>, - ) -{ +impl Approx for (&Handle, &HalfEdgeGeometry, &SurfaceGeometry) { type Approximation = CurveApprox; type Cache = CurveApproxCache; @@ -30,20 +26,20 @@ impl Approx cache: &mut Self::Cache, core: &mut Core, ) -> Self::Approximation { - let (curve, surface_path, surface, boundary) = self; + let (curve, half_edge, surface) = self; - match cache.get(curve, boundary) { + match cache.get(curve, half_edge.boundary) { Some(approx) => approx, None => { let approx = approx_curve( - &surface_path, + &half_edge.path, surface, - boundary, + half_edge.boundary, tolerance, core, ); - cache.insert(curve.clone(), boundary, approx) + cache.insert(curve.clone(), half_edge.boundary, approx) } } } @@ -187,7 +183,10 @@ mod tests { use crate::{ algorithms::approx::{Approx, ApproxPoint}, - geometry::{CurveBoundary, GlobalPath, SurfaceGeometry, SurfacePath}, + geometry::{ + CurveBoundary, GlobalPath, HalfEdgeGeometry, SurfaceGeometry, + SurfacePath, + }, objects::Curve, operations::insert::Insert, Core, @@ -201,11 +200,12 @@ mod tests { let (path, boundary) = SurfacePath::line_from_points([[1., 1.], [2., 1.]]); let boundary = CurveBoundary::from(boundary); + let half_edge = HalfEdgeGeometry { path, boundary }; let surface = core.layers.geometry.xz_plane(); let tolerance = 1.; let approx = - (&curve, path, &surface, boundary).approx(tolerance, &mut core); + (&curve, &half_edge, &surface).approx(tolerance, &mut core); assert_eq!(approx.points, vec![]); } @@ -218,6 +218,7 @@ mod tests { let (path, boundary) = SurfacePath::line_from_points([[1., 1.], [2., 1.]]); let boundary = CurveBoundary::from(boundary); + let half_edge = HalfEdgeGeometry { path, boundary }; let surface = SurfaceGeometry { u: GlobalPath::circle_from_radius(1.), v: [0., 0., 1.].into(), @@ -225,7 +226,7 @@ mod tests { let tolerance = 1.; let approx = - (&curve, path, &surface, boundary).approx(tolerance, &mut core); + (&curve, &half_edge, &surface).approx(tolerance, &mut core); assert_eq!(approx.points, vec![]); } @@ -241,6 +242,7 @@ mod tests { ([TAU], [TAU, 1.]), ]); let boundary = CurveBoundary::from([[0.], [TAU]]); + let half_edge = HalfEdgeGeometry { path, boundary }; let surface = SurfaceGeometry { u: global_path, v: [0., 0., 1.].into(), @@ -248,7 +250,7 @@ mod tests { let tolerance = 1.; let approx = - (&curve, path, &surface, boundary).approx(tolerance, &mut core); + (&curve, &half_edge, &surface).approx(tolerance, &mut core); let expected_approx = (global_path, boundary) .approx(tolerance, &mut core) @@ -270,11 +272,12 @@ mod tests { let curve = Curve::new().insert(&mut core); let path = SurfacePath::circle_from_center_and_radius([0., 0.], 1.); let boundary = CurveBoundary::from([[0.], [TAU]]); + let half_edge = HalfEdgeGeometry { path, boundary }; let surface = core.layers.geometry.xz_plane(); let tolerance = 1.; let approx = - (&curve, path, &surface, boundary).approx(tolerance, &mut core); + (&curve, &half_edge, &surface).approx(tolerance, &mut core); let expected_approx = (&path, boundary) .approx(tolerance, &mut core) diff --git a/crates/fj-core/src/algorithms/approx/edge.rs b/crates/fj-core/src/algorithms/approx/edge.rs index 356cb193d..5db47de99 100644 --- a/crates/fj-core/src/algorithms/approx/edge.rs +++ b/crates/fj-core/src/algorithms/approx/edge.rs @@ -50,9 +50,8 @@ impl Approx for (&Handle, &SurfaceGeometry) { let rest = { let approx = ( half_edge.curve(), - core.layers.geometry.of_half_edge(half_edge).path, + &core.layers.geometry.of_half_edge(half_edge), surface, - half_edge.boundary(), ) .approx_with_cache( tolerance, From 83eab225d2fd2cc42c9f66202e5afdad4ffd725f Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Sat, 23 Mar 2024 00:41:48 +0100 Subject: [PATCH 05/18] Refactor to prepare for follow-on change --- crates/fj-core/src/algorithms/bounding_volume/edge.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/crates/fj-core/src/algorithms/bounding_volume/edge.rs b/crates/fj-core/src/algorithms/bounding_volume/edge.rs index ec7ed05f2..c958d8e48 100644 --- a/crates/fj-core/src/algorithms/bounding_volume/edge.rs +++ b/crates/fj-core/src/algorithms/bounding_volume/edge.rs @@ -22,11 +22,10 @@ impl super::BoundingVolume<2> for Handle { }) } SurfacePath::Line(_) => { + let geometry = geometry.of_half_edge(self); + let points = self.boundary().inner.map(|point_curve| { - geometry - .of_half_edge(self) - .path - .point_from_path_coords(point_curve) + geometry.path.point_from_path_coords(point_curve) }); Some(Aabb::<2>::from_points(points)) From 5fed3493a86fcd4af58f1ed108e65695535b93ff Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Sat, 23 Mar 2024 00:43:01 +0100 Subject: [PATCH 06/18] Read geometry from layer in `BoundingVolume` impl --- crates/fj-core/src/algorithms/bounding_volume/edge.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/fj-core/src/algorithms/bounding_volume/edge.rs b/crates/fj-core/src/algorithms/bounding_volume/edge.rs index c958d8e48..4e243d158 100644 --- a/crates/fj-core/src/algorithms/bounding_volume/edge.rs +++ b/crates/fj-core/src/algorithms/bounding_volume/edge.rs @@ -24,7 +24,7 @@ impl super::BoundingVolume<2> for Handle { SurfacePath::Line(_) => { let geometry = geometry.of_half_edge(self); - let points = self.boundary().inner.map(|point_curve| { + let points = geometry.boundary.inner.map(|point_curve| { geometry.path.point_from_path_coords(point_curve) }); From 82c7666a6332b722cc96ab6595bb4482db23cb87 Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Sat, 23 Mar 2024 00:44:23 +0100 Subject: [PATCH 07/18] Refactor to prepare for follow-on change --- crates/fj-core/src/objects/kinds/cycle.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/crates/fj-core/src/objects/kinds/cycle.rs b/crates/fj-core/src/objects/kinds/cycle.rs index b1fc57b6a..1629ab2ce 100644 --- a/crates/fj-core/src/objects/kinds/cycle.rs +++ b/crates/fj-core/src/objects/kinds/cycle.rs @@ -40,10 +40,12 @@ impl Cycle { .next() .expect("Invalid cycle: expected at least one edge"); + let geometry = geometry.of_half_edge(first); + let [a, b] = first.boundary().inner; let edge_direction_positive = a < b; - let circle = match geometry.of_half_edge(first).path { + let circle = match geometry.path { SurfacePath::Circle(circle) => circle, SurfacePath::Line(_) => unreachable!( "Invalid cycle: less than 3 edges, but not all are circles" From 88716ed327732bbb8264be319515313bc3c01aa1 Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Sat, 23 Mar 2024 00:45:32 +0100 Subject: [PATCH 08/18] Read geometry from layer in `Cycle::winding` --- crates/fj-core/src/objects/kinds/cycle.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/fj-core/src/objects/kinds/cycle.rs b/crates/fj-core/src/objects/kinds/cycle.rs index 1629ab2ce..40e84b53a 100644 --- a/crates/fj-core/src/objects/kinds/cycle.rs +++ b/crates/fj-core/src/objects/kinds/cycle.rs @@ -42,7 +42,7 @@ impl Cycle { let geometry = geometry.of_half_edge(first); - let [a, b] = first.boundary().inner; + let [a, b] = geometry.boundary.inner; let edge_direction_positive = a < b; let circle = match geometry.path { From f74669cdb47b7a7cd48d8223e7c4ff21e15843d4 Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Sat, 23 Mar 2024 00:50:38 +0100 Subject: [PATCH 09/18] Simplify args of `JoinCycle::add_joined_edges` --- crates/fj-core/src/operations/holes.rs | 18 +++--------------- crates/fj-core/src/operations/join/cycle.rs | 20 ++++++-------------- crates/fj-core/src/operations/sweep/cycle.rs | 3 +-- 3 files changed, 10 insertions(+), 31 deletions(-) diff --git a/crates/fj-core/src/operations/holes.rs b/crates/fj-core/src/operations/holes.rs index 3017c09ef..7b19b7347 100644 --- a/crates/fj-core/src/operations/holes.rs +++ b/crates/fj-core/src/operations/holes.rs @@ -68,11 +68,7 @@ impl AddHole for Shell { [Cycle::empty().add_joined_edges( [( entry.clone(), - core.layers - .geometry - .of_half_edge(&entry) - .path, - entry.boundary(), + core.layers.geometry.of_half_edge(&entry), )], core, )], @@ -142,11 +138,7 @@ impl AddHole for Shell { [Cycle::empty().add_joined_edges( [( entry.clone(), - core.layers - .geometry - .of_half_edge(&entry) - .path, - entry.boundary(), + core.layers.geometry.of_half_edge(&entry), )], core, )], @@ -167,11 +159,7 @@ impl AddHole for Shell { [Cycle::empty().add_joined_edges( [( exit.clone(), - core.layers - .geometry - .of_half_edge(exit) - .path, - exit.boundary(), + core.layers.geometry.of_half_edge(exit), )], core, )], diff --git a/crates/fj-core/src/operations/join/cycle.rs b/crates/fj-core/src/operations/join/cycle.rs index 82cd9bfc8..f28850262 100644 --- a/crates/fj-core/src/operations/join/cycle.rs +++ b/crates/fj-core/src/operations/join/cycle.rs @@ -1,10 +1,9 @@ use std::ops::RangeInclusive; -use fj_math::Point; use itertools::Itertools; use crate::{ - geometry::{CurveBoundary, HalfEdgeGeometry, SurfacePath}, + geometry::HalfEdgeGeometry, objects::{Cycle, HalfEdge}, operations::{ build::BuildHalfEdge, @@ -22,9 +21,7 @@ pub trait JoinCycle { #[must_use] fn add_joined_edges(&self, edges: Es, core: &mut Core) -> Self where - Es: IntoIterator< - Item = (Handle, SurfacePath, CurveBoundary>), - >, + Es: IntoIterator, HalfEdgeGeometry)>, Es::IntoIter: Clone + ExactSizeIterator; /// Join the cycle to another @@ -81,26 +78,21 @@ pub trait JoinCycle { impl JoinCycle for Cycle { fn add_joined_edges(&self, edges: Es, core: &mut Core) -> Self where - Es: IntoIterator< - Item = (Handle, SurfacePath, CurveBoundary>), - >, + Es: IntoIterator, HalfEdgeGeometry)>, Es::IntoIter: Clone + ExactSizeIterator, { let half_edges = edges .into_iter() .circular_tuple_windows() - .map(|((prev_half_edge, _, _), (half_edge, path, boundary))| { - HalfEdge::unjoined(boundary, core) + .map(|((prev_half_edge, _), (half_edge, geometry))| { + HalfEdge::unjoined(geometry.boundary, core) .update_curve(|_, _| half_edge.curve().clone(), core) .update_start_vertex( |_, _| prev_half_edge.start_vertex().clone(), core, ) .insert(core) - .set_geometry( - HalfEdgeGeometry { path, boundary }, - &mut core.layers.geometry, - ) + .set_geometry(geometry, &mut core.layers.geometry) }) .collect::>(); self.add_half_edges(half_edges, core) diff --git a/crates/fj-core/src/operations/sweep/cycle.rs b/crates/fj-core/src/operations/sweep/cycle.rs index 23f04051c..313c71efc 100644 --- a/crates/fj-core/src/operations/sweep/cycle.rs +++ b/crates/fj-core/src/operations/sweep/cycle.rs @@ -77,8 +77,7 @@ impl SweepCycle for Cycle { top_edges.push(( top_edge, - core.layers.geometry.of_half_edge(bottom_half_edge).path, - bottom_half_edge.boundary(), + core.layers.geometry.of_half_edge(bottom_half_edge), )); } From 426ef782b9288b98447863ac6fcd41b622ceee80 Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Sat, 23 Mar 2024 00:52:06 +0100 Subject: [PATCH 10/18] Refactor to prepare for follow-on change --- crates/fj-core/src/operations/sweep/half_edge.rs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/crates/fj-core/src/operations/sweep/half_edge.rs b/crates/fj-core/src/operations/sweep/half_edge.rs index 3014c16b2..5f8bf1a9d 100644 --- a/crates/fj-core/src/operations/sweep/half_edge.rs +++ b/crates/fj-core/src/operations/sweep/half_edge.rs @@ -59,12 +59,8 @@ impl SweepHalfEdge for Handle { ) -> (Face, Handle) { let path = path.into(); - let surface = core - .layers - .geometry - .of_half_edge(self) - .path - .sweep_surface_path(surface, path, core); + let geometry = core.layers.geometry.of_half_edge(self); + let surface = geometry.path.sweep_surface_path(surface, path, core); // Next, we need to define the boundaries of the face. Let's start with // the global vertices and edges. From 9656a2638cda46e0c08455cdb17066c0fb0ab1a4 Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Sat, 23 Mar 2024 00:53:28 +0100 Subject: [PATCH 11/18] Read geometry from layer in `SweepHalfEdge` --- crates/fj-core/src/operations/sweep/half_edge.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/fj-core/src/operations/sweep/half_edge.rs b/crates/fj-core/src/operations/sweep/half_edge.rs index 5f8bf1a9d..4fbb1f711 100644 --- a/crates/fj-core/src/operations/sweep/half_edge.rs +++ b/crates/fj-core/src/operations/sweep/half_edge.rs @@ -82,7 +82,7 @@ impl SweepHalfEdge for Handle { // Let's figure out the surface coordinates of the edge vertices. let surface_points = { - let [a, b] = self.boundary().inner; + let [a, b] = geometry.boundary.inner; [ [a.t, Scalar::ZERO], @@ -100,7 +100,7 @@ impl SweepHalfEdge for Handle { // Now, the boundaries of each edge. let boundaries = { - let [a, b] = self.boundary().inner; + let [a, b] = geometry.boundary.inner; let [c, d] = [0., 1.].map(|coord| Point::from([coord])); [[a, b], [c, d], [b, a], [d, c]] From 1302dd89c48b11f5f9cffb5272101d2957e349db Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Sat, 23 Mar 2024 00:55:57 +0100 Subject: [PATCH 12/18] Expect `&Geometry` in `get_sibling_of` --- crates/fj-core/src/operations/split/edge.rs | 2 +- crates/fj-core/src/queries/sibling_of_half_edge.rs | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/crates/fj-core/src/operations/split/edge.rs b/crates/fj-core/src/operations/split/edge.rs index 84496ca44..b85893a4f 100644 --- a/crates/fj-core/src/operations/split/edge.rs +++ b/crates/fj-core/src/operations/split/edge.rs @@ -37,7 +37,7 @@ impl SplitEdge for Shell { let point = point.into(); let sibling = self - .get_sibling_of(half_edge) + .get_sibling_of(half_edge, &core.layers.geometry) .expect("Expected half-edge and its sibling to be part of shell"); let [half_edge_a, half_edge_b] = half_edge.split_half_edge(point, core); diff --git a/crates/fj-core/src/queries/sibling_of_half_edge.rs b/crates/fj-core/src/queries/sibling_of_half_edge.rs index 5c5dd2314..a05619b84 100644 --- a/crates/fj-core/src/queries/sibling_of_half_edge.rs +++ b/crates/fj-core/src/queries/sibling_of_half_edge.rs @@ -1,4 +1,5 @@ use crate::{ + geometry::Geometry, objects::{HalfEdge, Shell}, storage::Handle, }; @@ -18,6 +19,7 @@ pub trait SiblingOfHalfEdge { fn get_sibling_of( &self, half_edge: &Handle, + geometry: &Geometry, ) -> Option>; } @@ -44,6 +46,7 @@ impl SiblingOfHalfEdge for Shell { fn get_sibling_of( &self, half_edge: &Handle, + _: &Geometry, ) -> Option> { for face in self.faces() { for cycle in face.region().all_cycles() { From 6ba10adb0c727879e5d7949346eb0093738e5271 Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Sat, 23 Mar 2024 00:57:13 +0100 Subject: [PATCH 13/18] Expect `&Geometry` in `check_half_edge_pairs` --- crates/fj-core/src/validate/shell.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/crates/fj-core/src/validate/shell.rs b/crates/fj-core/src/validate/shell.rs index 237d743c1..676a1e934 100644 --- a/crates/fj-core/src/validate/shell.rs +++ b/crates/fj-core/src/validate/shell.rs @@ -23,7 +23,7 @@ impl Validate for Shell { ShellValidationError::check_curve_coordinates( self, geometry, config, errors, ); - ShellValidationError::check_half_edge_pairs(self, errors); + ShellValidationError::check_half_edge_pairs(self, geometry, errors); ShellValidationError::check_half_edge_coincidence( self, geometry, config, errors, ); @@ -177,7 +177,11 @@ impl ShellValidationError { } /// Check that each half-edge is part of a pair - fn check_half_edge_pairs(shell: &Shell, errors: &mut Vec) { + fn check_half_edge_pairs( + shell: &Shell, + _: &Geometry, + errors: &mut Vec, + ) { let mut unmatched_half_edges = BTreeMap::new(); for face in shell.faces() { From f037fc979c975443eebf6de3250978bf151dbc69 Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Sat, 23 Mar 2024 00:59:01 +0100 Subject: [PATCH 14/18] Read geometry from layer in `are_siblings` --- .../src/queries/sibling_of_half_edge.rs | 21 ++++++++++++++----- crates/fj-core/src/validate/shell.rs | 7 ++++--- 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/crates/fj-core/src/queries/sibling_of_half_edge.rs b/crates/fj-core/src/queries/sibling_of_half_edge.rs index a05619b84..07583f548 100644 --- a/crates/fj-core/src/queries/sibling_of_half_edge.rs +++ b/crates/fj-core/src/queries/sibling_of_half_edge.rs @@ -9,7 +9,12 @@ use super::BoundingVerticesOfHalfEdge; /// Queries related to the sibling of a [`HalfEdge`] pub trait SiblingOfHalfEdge { /// Indicate whether the provided half-edges are siblings - fn are_siblings(&self, a: &Handle, b: &Handle) -> bool; + fn are_siblings( + &self, + a: &Handle, + b: &Handle, + geometry: &Geometry, + ) -> bool; /// Retrieve the sibling of this half-edge /// @@ -24,9 +29,15 @@ pub trait SiblingOfHalfEdge { } impl SiblingOfHalfEdge for Shell { - fn are_siblings(&self, a: &Handle, b: &Handle) -> bool { + fn are_siblings( + &self, + a: &Handle, + b: &Handle, + geometry: &Geometry, + ) -> bool { let same_curve = a.curve().id() == b.curve().id(); - let same_boundary = a.boundary() == b.boundary().reverse(); + let same_boundary = geometry.of_half_edge(a).boundary + == geometry.of_half_edge(b).boundary.reverse(); let same_vertices = { let Some(a_vertices) = self.bounding_vertices_of_half_edge(a) else { @@ -46,12 +57,12 @@ impl SiblingOfHalfEdge for Shell { fn get_sibling_of( &self, half_edge: &Handle, - _: &Geometry, + geometry: &Geometry, ) -> Option> { for face in self.faces() { for cycle in face.region().all_cycles() { for h in cycle.half_edges() { - if self.are_siblings(half_edge, h) { + if self.are_siblings(half_edge, h, geometry) { return Some(h.clone()); } } diff --git a/crates/fj-core/src/validate/shell.rs b/crates/fj-core/src/validate/shell.rs index 676a1e934..6a2760f03 100644 --- a/crates/fj-core/src/validate/shell.rs +++ b/crates/fj-core/src/validate/shell.rs @@ -179,7 +179,7 @@ impl ShellValidationError { /// Check that each half-edge is part of a pair fn check_half_edge_pairs( shell: &Shell, - _: &Geometry, + geometry: &Geometry, errors: &mut Vec, ) { let mut unmatched_half_edges = BTreeMap::new(); @@ -204,7 +204,8 @@ impl ShellValidationError { // currently looking at. Let's make sure the logic // we use here to determine that matches the // "official" definition. - assert!(shell.are_siblings(half_edge, sibling)); + assert!(shell + .are_siblings(half_edge, sibling, geometry)); } None => { // If this half-edge has a sibling, we haven't seen @@ -242,7 +243,7 @@ impl ShellValidationError { continue; } - if shell.are_siblings(half_edge_a, half_edge_b) { + if shell.are_siblings(half_edge_a, half_edge_b, geometry) { // If the half-edges are siblings, they are allowed to be // coincident. Must be, in fact. There's another validation // check that takes care of that. From a33bcc9add0e60e5e59ceabf59eec31a2cceb949 Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Sat, 23 Mar 2024 01:01:03 +0100 Subject: [PATCH 15/18] Read boundary from layer in shell validation code --- crates/fj-core/src/validate/shell.rs | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/crates/fj-core/src/validate/shell.rs b/crates/fj-core/src/validate/shell.rs index 6a2760f03..e687aa2dd 100644 --- a/crates/fj-core/src/validate/shell.rs +++ b/crates/fj-core/src/validate/shell.rs @@ -112,7 +112,7 @@ impl ShellValidationError { // we have right now are circles, 3 would be enough to check // for coincidence. But the first and last might be // identical, so let's add an extra one. - let [a, d] = edge_a.boundary().inner; + let [a, d] = geometry.of_half_edge(edge_a).boundary.inner; let b = a + (d - a) * 1. / 3.; let c = a + (d - a) * 2. / 3.; @@ -188,7 +188,7 @@ impl ShellValidationError { for cycle in face.region().all_cycles() { for half_edge in cycle.half_edges() { let curve = half_edge.curve().clone(); - let boundary = half_edge.boundary(); + let boundary = geometry.of_half_edge(half_edge).boundary; let vertices = cycle.bounding_vertices_of_half_edge(half_edge).expect( "`half_edge` came from `cycle`, must exist there", @@ -262,8 +262,11 @@ impl ShellValidationError { .all(|d| d < config.distinct_min_distance) { let boundaries = Box::new(CoincidentHalfEdgeBoundaries { - boundaries: [half_edge_a, half_edge_b] - .map(|half_edge| half_edge.boundary()), + boundaries: [half_edge_a, half_edge_b].map( + |half_edge| { + geometry.of_half_edge(half_edge).boundary + }, + ), }); let curves = Box::new(CoincidentHalfEdgeCurves { curves: [half_edge_a, half_edge_b] @@ -389,7 +392,7 @@ fn distances( (edge, surface): (&Handle, &SurfaceGeometry), geometry: &Geometry, ) -> Point<3> { - let [start, end] = edge.boundary().inner; + let [start, end] = geometry.of_half_edge(edge).boundary.inner; let path_coords = start + (end - start) * percent; let surface_coords = geometry .of_half_edge(edge) From f1a6e63260184c76f83166debe0cd05ff1197d51 Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Sat, 23 Mar 2024 01:08:12 +0100 Subject: [PATCH 16/18] Read boundary from layer in cycle validation check --- crates/fj-core/src/validation/checks/half_edge_connection.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/fj-core/src/validation/checks/half_edge_connection.rs b/crates/fj-core/src/validation/checks/half_edge_connection.rs index 0cad2daa8..7fefc9560 100644 --- a/crates/fj-core/src/validation/checks/half_edge_connection.rs +++ b/crates/fj-core/src/validation/checks/half_edge_connection.rs @@ -46,7 +46,7 @@ impl ValidationCheck for AdjacentHalfEdgesNotConnected { ) -> impl Iterator { object.half_edges().pairs().filter_map(|(first, second)| { let end_pos_of_first_half_edge = { - let [_, end] = first.boundary().inner; + let [_, end] = geometry.of_half_edge(first).boundary.inner; geometry .of_half_edge(first) .path From 4740b3bdb6199ec6e44a95f174390704c3550009 Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Sat, 23 Mar 2024 01:13:55 +0100 Subject: [PATCH 17/18] Remove curve boundary from `HalfEdge` --- crates/fj-core/src/objects/kinds/half_edge.rs | 16 +------- .../fj-core/src/operations/build/half_edge.rs | 14 +++---- .../fj-core/src/operations/reverse/cycle.rs | 1 - crates/fj-core/src/operations/reverse/edge.rs | 11 ++---- .../fj-core/src/operations/split/half_edge.rs | 37 ++++++++----------- .../fj-core/src/operations/transform/edge.rs | 4 +- .../src/operations/update/half_edge.rs | 2 - crates/fj-core/src/validate/shell.rs | 1 - 8 files changed, 26 insertions(+), 60 deletions(-) diff --git a/crates/fj-core/src/objects/kinds/half_edge.rs b/crates/fj-core/src/objects/kinds/half_edge.rs index 523def5dc..6608d40d3 100644 --- a/crates/fj-core/src/objects/kinds/half_edge.rs +++ b/crates/fj-core/src/objects/kinds/half_edge.rs @@ -1,7 +1,4 @@ -use fj_math::Point; - use crate::{ - geometry::CurveBoundary, objects::{Curve, Vertex}, storage::Handle, }; @@ -35,30 +32,19 @@ use crate::{ /// [`Shell`]: crate::objects::Shell #[derive(Clone, Debug)] pub struct HalfEdge { - boundary: CurveBoundary>, curve: Handle, start_vertex: Handle, } impl HalfEdge { /// Create an instance of `Edge` - pub fn new( - boundary: impl Into>>, - curve: Handle, - start_vertex: Handle, - ) -> Self { + pub fn new(curve: Handle, start_vertex: Handle) -> Self { Self { - boundary: boundary.into(), curve, start_vertex, } } - /// Access the boundary points of the edge on the curve - pub fn boundary(&self) -> CurveBoundary> { - self.boundary - } - /// Access the curve of the edge pub fn curve(&self) -> &Handle { &self.curve diff --git a/crates/fj-core/src/operations/build/half_edge.rs b/crates/fj-core/src/operations/build/half_edge.rs index 0d0a3ce5a..36004248b 100644 --- a/crates/fj-core/src/operations/build/half_edge.rs +++ b/crates/fj-core/src/operations/build/half_edge.rs @@ -17,13 +17,13 @@ use crate::{ pub trait BuildHalfEdge { /// Create a half-edge that is not joined to a sibling fn unjoined( - boundary: impl Into>>, + _: impl Into>>, core: &mut Core, ) -> HalfEdge { let curve = Curve::new().insert(core); let start_vertex = Vertex::new().insert(core); - HalfEdge::new(boundary, curve, start_vertex) + HalfEdge::new(curve, start_vertex) } /// Create a half-edge from its sibling @@ -35,13 +35,9 @@ pub trait BuildHalfEdge { let mut geometry = core.layers.geometry.of_half_edge(sibling); geometry.boundary = geometry.boundary.reverse(); - HalfEdge::new( - sibling.boundary().reverse(), - sibling.curve().clone(), - start_vertex, - ) - .insert(core) - .set_geometry(geometry, &mut core.layers.geometry) + HalfEdge::new(sibling.curve().clone(), start_vertex) + .insert(core) + .set_geometry(geometry, &mut core.layers.geometry) } /// Create an arc diff --git a/crates/fj-core/src/operations/reverse/cycle.rs b/crates/fj-core/src/operations/reverse/cycle.rs index a3dd7b3cb..f3d3f341d 100644 --- a/crates/fj-core/src/operations/reverse/cycle.rs +++ b/crates/fj-core/src/operations/reverse/cycle.rs @@ -18,7 +18,6 @@ impl Reverse for Cycle { geometry.boundary = geometry.boundary.reverse(); HalfEdge::new( - current.boundary().reverse(), current.curve().clone(), next.start_vertex().clone(), ) diff --git a/crates/fj-core/src/operations/reverse/edge.rs b/crates/fj-core/src/operations/reverse/edge.rs index 4508a25e7..e42ae6a98 100644 --- a/crates/fj-core/src/operations/reverse/edge.rs +++ b/crates/fj-core/src/operations/reverse/edge.rs @@ -13,13 +13,10 @@ impl ReverseCurveCoordinateSystems for Handle { geometry.path = geometry.path.reverse(); geometry.boundary = geometry.boundary.reverse(); - let half_edge = HalfEdge::new( - geometry.boundary, - self.curve().clone(), - self.start_vertex().clone(), - ) - .insert(core) - .derive_from(self, core); + let half_edge = + HalfEdge::new(self.curve().clone(), self.start_vertex().clone()) + .insert(core) + .derive_from(self, core); core.layers .geometry diff --git a/crates/fj-core/src/operations/split/half_edge.rs b/crates/fj-core/src/operations/split/half_edge.rs index ebe1ef0a1..92621b7fa 100644 --- a/crates/fj-core/src/operations/split/half_edge.rs +++ b/crates/fj-core/src/operations/split/half_edge.rs @@ -45,28 +45,21 @@ impl SplitHalfEdge for Handle { let geometry = core.layers.geometry.of_half_edge(self); let [start, end] = geometry.boundary.inner; - let a = HalfEdge::new( - [start, point], - self.curve().clone(), - self.start_vertex().clone(), - ) - .insert(core) - .derive_from(self, core) - .set_geometry( - geometry.with_boundary([start, point]), - &mut core.layers.geometry, - ); - let b = HalfEdge::new( - [point, end], - self.curve().clone(), - Vertex::new().insert(core), - ) - .insert(core) - .derive_from(self, core) - .set_geometry( - geometry.with_boundary([point, end]), - &mut core.layers.geometry, - ); + let a = + HalfEdge::new(self.curve().clone(), self.start_vertex().clone()) + .insert(core) + .derive_from(self, core) + .set_geometry( + geometry.with_boundary([start, point]), + &mut core.layers.geometry, + ); + let b = HalfEdge::new(self.curve().clone(), Vertex::new().insert(core)) + .insert(core) + .derive_from(self, core) + .set_geometry( + geometry.with_boundary([point, end]), + &mut core.layers.geometry, + ); [a, b] } diff --git a/crates/fj-core/src/operations/transform/edge.rs b/crates/fj-core/src/operations/transform/edge.rs index 9e1a708ad..6baf3fcc9 100644 --- a/crates/fj-core/src/operations/transform/edge.rs +++ b/crates/fj-core/src/operations/transform/edge.rs @@ -13,7 +13,6 @@ impl TransformObject for Handle { core: &mut Core, cache: &mut TransformCache, ) -> Self { - let boundary = self.boundary(); let curve = self .curve() .clone() @@ -23,8 +22,7 @@ impl TransformObject for Handle { .clone() .transform_with_cache(transform, core, cache); - let half_edge = - HalfEdge::new(boundary, curve, start_vertex).insert(core); + let half_edge = HalfEdge::new(curve, start_vertex).insert(core); core.layers.geometry.define_half_edge( half_edge.clone(), diff --git a/crates/fj-core/src/operations/update/half_edge.rs b/crates/fj-core/src/operations/update/half_edge.rs index 003a6a224..b1f782d1d 100644 --- a/crates/fj-core/src/operations/update/half_edge.rs +++ b/crates/fj-core/src/operations/update/half_edge.rs @@ -38,7 +38,6 @@ impl UpdateHalfEdge for HalfEdge { T: Insert>, { HalfEdge::new( - self.boundary(), update(self.curve(), core) .insert(core) .derive_from(self.curve(), core), @@ -55,7 +54,6 @@ impl UpdateHalfEdge for HalfEdge { T: Insert>, { HalfEdge::new( - self.boundary(), self.curve().clone(), update(self.start_vertex(), core) .insert(core) diff --git a/crates/fj-core/src/validate/shell.rs b/crates/fj-core/src/validate/shell.rs index e687aa2dd..83d85a258 100644 --- a/crates/fj-core/src/validate/shell.rs +++ b/crates/fj-core/src/validate/shell.rs @@ -462,7 +462,6 @@ mod tests { geometry.boundary.reverse(); [HalfEdge::new( - half_edge.boundary().reverse(), half_edge.curve().clone(), half_edge.start_vertex().clone(), ) From 53d1fb882d179e9a690f9caaa332d3a7c53477b0 Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Sat, 23 Mar 2024 01:15:37 +0100 Subject: [PATCH 18/18] Remove unused argument --- .../fj-core/src/operations/build/half_edge.rs | 27 ++++++++----------- crates/fj-core/src/operations/join/cycle.rs | 2 +- 2 files changed, 12 insertions(+), 17 deletions(-) diff --git a/crates/fj-core/src/operations/build/half_edge.rs b/crates/fj-core/src/operations/build/half_edge.rs index 36004248b..53c3abcd5 100644 --- a/crates/fj-core/src/operations/build/half_edge.rs +++ b/crates/fj-core/src/operations/build/half_edge.rs @@ -2,7 +2,7 @@ use fj_interop::ext::ArrayExt; use fj_math::{Arc, Point, Scalar}; use crate::{ - geometry::{CurveBoundary, HalfEdgeGeometry, SurfacePath}, + geometry::{HalfEdgeGeometry, SurfacePath}, objects::{Curve, HalfEdge, Vertex}, operations::{geometry::UpdateHalfEdgeGeometry, insert::Insert}, storage::Handle, @@ -16,10 +16,7 @@ use crate::{ /// [module-level documentation]: super pub trait BuildHalfEdge { /// Create a half-edge that is not joined to a sibling - fn unjoined( - _: impl Into>>, - core: &mut Core, - ) -> HalfEdge { + fn unjoined(core: &mut Core) -> HalfEdge { let curve = Curve::new().insert(core); let start_vertex = Vertex::new().insert(core); @@ -63,7 +60,7 @@ pub trait BuildHalfEdge { let boundary = [arc.start_angle, arc.end_angle].map(|coord| Point::from([coord])); - let half_edge = HalfEdge::unjoined(boundary, core).insert(core); + let half_edge = HalfEdge::unjoined(core).insert(core); core.layers.geometry.define_half_edge( half_edge.clone(), HalfEdgeGeometry { @@ -85,7 +82,7 @@ pub trait BuildHalfEdge { let boundary = [Scalar::ZERO, Scalar::TAU].map(|coord| Point::from([coord])); - let half_edge = HalfEdge::unjoined(boundary, core).insert(core); + let half_edge = HalfEdge::unjoined(core).insert(core); core.layers.geometry.define_half_edge( half_edge.clone(), HalfEdgeGeometry { @@ -109,15 +106,13 @@ pub trait BuildHalfEdge { boundary.zip_ext(points_surface), ); - HalfEdge::unjoined(boundary, core) - .insert(core) - .set_geometry( - HalfEdgeGeometry { - path, - boundary: boundary.into(), - }, - &mut core.layers.geometry, - ) + HalfEdge::unjoined(core).insert(core).set_geometry( + HalfEdgeGeometry { + path, + boundary: boundary.into(), + }, + &mut core.layers.geometry, + ) } } diff --git a/crates/fj-core/src/operations/join/cycle.rs b/crates/fj-core/src/operations/join/cycle.rs index f28850262..5821a1d68 100644 --- a/crates/fj-core/src/operations/join/cycle.rs +++ b/crates/fj-core/src/operations/join/cycle.rs @@ -85,7 +85,7 @@ impl JoinCycle for Cycle { .into_iter() .circular_tuple_windows() .map(|((prev_half_edge, _), (half_edge, geometry))| { - HalfEdge::unjoined(geometry.boundary, core) + HalfEdge::unjoined(core) .update_curve(|_, _| half_edge.curve().clone(), core) .update_start_vertex( |_, _| prev_half_edge.start_vertex().clone(),