From d9a5f22150da6baaaf3ec6260fe96519a81ec47e Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Thu, 23 Mar 2023 13:31:52 +0100 Subject: [PATCH 1/9] Update variable names The old names didn't make a lot of sense. Since we don't know anything about the points that the caller passes in, it only makes sense to name the faces after the order of the points, nothing that implies a position or orientation. --- crates/fj-kernel/src/operations/build/shell.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/crates/fj-kernel/src/operations/build/shell.rs b/crates/fj-kernel/src/operations/build/shell.rs index 6d4a917f1b..966bf740e8 100644 --- a/crates/fj-kernel/src/operations/build/shell.rs +++ b/crates/fj-kernel/src/operations/build/shell.rs @@ -18,22 +18,22 @@ pub trait BuildShell { let [a, b, c, d] = points.map(Into::into); let Triangle { - face: base, + face: face_abc, edges: [ab, bc, ca], } = Face::triangle([a, b, c], [None, None, None], objects); let Triangle { - face: side_a, + face: face_abd, edges: [_, bd, da], } = Face::triangle([a, b, d], [Some(ab), None, None], objects); let Triangle { - face: side_b, + face: face_cad, edges: [_, _, dc], } = Face::triangle([c, a, d], [Some(ca), Some(da), None], objects); - let Triangle { face: side_c, .. } = + let Triangle { face: face_bcd, .. } = Face::triangle([b, c, d], [Some(bc), Some(dc), Some(bd)], objects); - let faces = - [base, side_a, side_b, side_c].map(|face| face.insert(objects)); + let faces = [face_abc, face_abd, face_cad, face_bcd] + .map(|face| face.insert(objects)); Shell::new(faces) } } From 21f3fc5aa4bc0f8fd75c250c9dd3b325a923ad48 Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Thu, 23 Mar 2023 13:39:36 +0100 Subject: [PATCH 2/9] Make return value more explicit --- crates/fj-kernel/src/operations/build/mod.rs | 2 +- .../fj-kernel/src/operations/build/shell.rs | 39 ++++++++++++++++++- crates/fj-kernel/src/operations/mod.rs | 2 +- crates/fj-kernel/src/validate/shell.rs | 4 +- 4 files changed, 41 insertions(+), 6 deletions(-) diff --git a/crates/fj-kernel/src/operations/build/mod.rs b/crates/fj-kernel/src/operations/build/mod.rs index be6dfed0e3..8b0bd25210 100644 --- a/crates/fj-kernel/src/operations/build/mod.rs +++ b/crates/fj-kernel/src/operations/build/mod.rs @@ -4,6 +4,6 @@ mod surface; pub use self::{ face::{BuildFace, Triangle}, - shell::BuildShell, + shell::{BuildShell, Tetrahedron}, surface::BuildSurface, }; diff --git a/crates/fj-kernel/src/operations/build/shell.rs b/crates/fj-kernel/src/operations/build/shell.rs index 966bf740e8..a5b54957a7 100644 --- a/crates/fj-kernel/src/operations/build/shell.rs +++ b/crates/fj-kernel/src/operations/build/shell.rs @@ -4,6 +4,7 @@ use crate::{ objects::{Face, Objects, Shell}, operations::Insert, services::Service, + storage::Handle, }; use super::{BuildFace, Triangle}; @@ -14,7 +15,7 @@ pub trait BuildShell { fn tetrahedron( points: [impl Into>; 4], objects: &mut Service, - ) -> Shell { + ) -> Tetrahedron { let [a, b, c, d] = points.map(Into::into); let Triangle { @@ -34,8 +35,42 @@ pub trait BuildShell { let faces = [face_abc, face_abd, face_cad, face_bcd] .map(|face| face.insert(objects)); - Shell::new(faces) + let shell = Shell::new(faces.clone()); + + let [face_abc, face_abd, face_cad, face_bcd] = faces; + + Tetrahedron { + shell, + face_abc, + face_abd, + face_cad, + face_bcd, + } } } impl BuildShell for Shell {} + +/// A tetrahedron +/// +/// A tetrahedron is constructed from 4 points and has 4 faces. For the purpose +/// of naming the fields of this struct, the points are named `a`, `b`, `c`, and +/// `d`, in the order in which they are passed. +/// +/// Returned by [`BuildShell::tetrahedron`]. +pub struct Tetrahedron { + /// The shell that forms the tetrahedron + pub shell: Shell, + + /// The face formed by the points `a`, `b`, and `c`. + pub face_abc: Handle, + + /// The face formed by the points `a`, `b`, and `d`. + pub face_abd: Handle, + + /// The face formed by the points `c`, `a`, and `d`. + pub face_cad: Handle, + + /// The face formed by the points `b`, `c`, and `d`. + pub face_bcd: Handle, +} diff --git a/crates/fj-kernel/src/operations/mod.rs b/crates/fj-kernel/src/operations/mod.rs index 0cfabab4c0..e81855a275 100644 --- a/crates/fj-kernel/src/operations/mod.rs +++ b/crates/fj-kernel/src/operations/mod.rs @@ -4,6 +4,6 @@ mod build; mod insert; pub use self::{ - build::{BuildFace, BuildShell, BuildSurface, Triangle}, + build::{BuildFace, BuildShell, BuildSurface, Tetrahedron, Triangle}, insert::Insert, }; diff --git a/crates/fj-kernel/src/validate/shell.rs b/crates/fj-kernel/src/validate/shell.rs index 1e4abccaa2..4438f7d54a 100644 --- a/crates/fj-kernel/src/validate/shell.rs +++ b/crates/fj-kernel/src/validate/shell.rs @@ -232,7 +232,7 @@ mod tests { Shell::new([face1, face2]) }; - valid.validate_and_return_first_error()?; + valid.shell.validate_and_return_first_error()?; assert_contains_err!( invalid, ValidationError::Shell( @@ -264,7 +264,7 @@ mod tests { Shell::new([face]) }; - valid.validate_and_return_first_error()?; + valid.shell.validate_and_return_first_error()?; assert_contains_err!( invalid, ValidationError::Shell(ShellValidationError::NotWatertight) From eebd7b716d296b901e9c8b73c3a0c6e2ceacf931 Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Thu, 23 Mar 2023 13:47:31 +0100 Subject: [PATCH 3/9] Add `UpdateShell` --- crates/fj-kernel/src/operations/mod.rs | 2 ++ crates/fj-kernel/src/operations/update/mod.rs | 3 ++ .../fj-kernel/src/operations/update/shell.rs | 32 +++++++++++++++++++ 3 files changed, 37 insertions(+) create mode 100644 crates/fj-kernel/src/operations/update/mod.rs create mode 100644 crates/fj-kernel/src/operations/update/shell.rs diff --git a/crates/fj-kernel/src/operations/mod.rs b/crates/fj-kernel/src/operations/mod.rs index e81855a275..adf7d27581 100644 --- a/crates/fj-kernel/src/operations/mod.rs +++ b/crates/fj-kernel/src/operations/mod.rs @@ -2,8 +2,10 @@ mod build; mod insert; +mod update; pub use self::{ build::{BuildFace, BuildShell, BuildSurface, Tetrahedron, Triangle}, insert::Insert, + update::UpdateShell, }; diff --git a/crates/fj-kernel/src/operations/update/mod.rs b/crates/fj-kernel/src/operations/update/mod.rs new file mode 100644 index 0000000000..945d3068c9 --- /dev/null +++ b/crates/fj-kernel/src/operations/update/mod.rs @@ -0,0 +1,3 @@ +mod shell; + +pub use self::shell::UpdateShell; diff --git a/crates/fj-kernel/src/operations/update/shell.rs b/crates/fj-kernel/src/operations/update/shell.rs new file mode 100644 index 0000000000..8ac6f62cfa --- /dev/null +++ b/crates/fj-kernel/src/operations/update/shell.rs @@ -0,0 +1,32 @@ +use crate::{ + objects::{Face, Shell}, + storage::Handle, +}; + +/// Update a [`Shell`] +pub trait UpdateShell { + /// Update a face of the shell + fn update_face( + &self, + handle: &Handle, + f: impl FnMut(&Handle) -> Handle, + ) -> Shell; +} + +impl UpdateShell for Shell { + fn update_face( + &self, + handle: &Handle, + mut f: impl FnMut(&Handle) -> Handle, + ) -> Shell { + let faces = self.faces().into_iter().map(|face| { + if face.id() == handle.id() { + f(face) + } else { + face.clone() + } + }); + + Shell::new(faces) + } +} From 6e6c1d5457856af2aaa0daf095a31c4cc33a2e42 Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Thu, 23 Mar 2023 14:03:08 +0100 Subject: [PATCH 4/9] Add `UpdateFace` --- crates/fj-kernel/src/operations/mod.rs | 2 +- .../fj-kernel/src/operations/update/face.rs | 29 +++++++++++++++++++ crates/fj-kernel/src/operations/update/mod.rs | 3 +- 3 files changed, 32 insertions(+), 2 deletions(-) create mode 100644 crates/fj-kernel/src/operations/update/face.rs diff --git a/crates/fj-kernel/src/operations/mod.rs b/crates/fj-kernel/src/operations/mod.rs index adf7d27581..0a561edd6a 100644 --- a/crates/fj-kernel/src/operations/mod.rs +++ b/crates/fj-kernel/src/operations/mod.rs @@ -7,5 +7,5 @@ mod update; pub use self::{ build::{BuildFace, BuildShell, BuildSurface, Tetrahedron, Triangle}, insert::Insert, - update::UpdateShell, + update::{UpdateFace, UpdateShell}, }; diff --git a/crates/fj-kernel/src/operations/update/face.rs b/crates/fj-kernel/src/operations/update/face.rs new file mode 100644 index 0000000000..c4e27ebcde --- /dev/null +++ b/crates/fj-kernel/src/operations/update/face.rs @@ -0,0 +1,29 @@ +use crate::{ + objects::{Cycle, Face}, + storage::Handle, +}; + +/// Update a [`Face`] +pub trait UpdateFace { + /// Update the exterior of the face + fn update_exterior( + &self, + f: impl FnOnce(&Handle) -> Handle, + ) -> Face; +} + +impl UpdateFace for Face { + fn update_exterior( + &self, + f: impl FnOnce(&Handle) -> Handle, + ) -> Face { + let exterior = f(self.exterior()); + + Face::new( + self.surface().clone(), + exterior, + self.interiors().cloned(), + self.color(), + ) + } +} diff --git a/crates/fj-kernel/src/operations/update/mod.rs b/crates/fj-kernel/src/operations/update/mod.rs index 945d3068c9..538d8254a6 100644 --- a/crates/fj-kernel/src/operations/update/mod.rs +++ b/crates/fj-kernel/src/operations/update/mod.rs @@ -1,3 +1,4 @@ +mod face; mod shell; -pub use self::shell::UpdateShell; +pub use self::{face::UpdateFace, shell::UpdateShell}; From 297db23026564517a73fd65f0d64ec8cfc7199b4 Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Thu, 23 Mar 2023 14:06:56 +0100 Subject: [PATCH 5/9] Add `UpdateCycle` --- crates/fj-kernel/src/operations/mod.rs | 2 +- .../fj-kernel/src/operations/update/cycle.rs | 32 +++++++++++++++++++ crates/fj-kernel/src/operations/update/mod.rs | 3 +- 3 files changed, 35 insertions(+), 2 deletions(-) create mode 100644 crates/fj-kernel/src/operations/update/cycle.rs diff --git a/crates/fj-kernel/src/operations/mod.rs b/crates/fj-kernel/src/operations/mod.rs index 0a561edd6a..2f721b6267 100644 --- a/crates/fj-kernel/src/operations/mod.rs +++ b/crates/fj-kernel/src/operations/mod.rs @@ -7,5 +7,5 @@ mod update; pub use self::{ build::{BuildFace, BuildShell, BuildSurface, Tetrahedron, Triangle}, insert::Insert, - update::{UpdateFace, UpdateShell}, + update::{UpdateCycle, UpdateFace, UpdateShell}, }; diff --git a/crates/fj-kernel/src/operations/update/cycle.rs b/crates/fj-kernel/src/operations/update/cycle.rs new file mode 100644 index 0000000000..43e8d441b5 --- /dev/null +++ b/crates/fj-kernel/src/operations/update/cycle.rs @@ -0,0 +1,32 @@ +use crate::{ + objects::{Cycle, HalfEdge}, + storage::Handle, +}; + +/// Update a [`Cycle`] +pub trait UpdateCycle { + /// Update a half-edge of the cycle + fn update_half_edge( + &self, + index: usize, + f: impl FnMut(&Handle) -> Handle, + ) -> Cycle; +} + +impl UpdateCycle for Cycle { + fn update_half_edge( + &self, + index: usize, + mut f: impl FnMut(&Handle) -> Handle, + ) -> Cycle { + let half_edges = self.half_edges().enumerate().map(|(i, cycle)| { + if i == index { + f(cycle) + } else { + cycle.clone() + } + }); + + Cycle::new(half_edges) + } +} diff --git a/crates/fj-kernel/src/operations/update/mod.rs b/crates/fj-kernel/src/operations/update/mod.rs index 538d8254a6..ee531c3f34 100644 --- a/crates/fj-kernel/src/operations/update/mod.rs +++ b/crates/fj-kernel/src/operations/update/mod.rs @@ -1,4 +1,5 @@ +mod cycle; mod face; mod shell; -pub use self::{face::UpdateFace, shell::UpdateShell}; +pub use self::{cycle::UpdateCycle, face::UpdateFace, shell::UpdateShell}; From 989fb3fb3ca173dfe2503fc1c84be0a8e91182b8 Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Thu, 23 Mar 2023 14:10:17 +0100 Subject: [PATCH 6/9] Add `UpdateHalfEdge` --- crates/fj-kernel/src/operations/mod.rs | 2 +- .../fj-kernel/src/operations/update/edge.rs | 21 +++++++++++++++++++ crates/fj-kernel/src/operations/update/mod.rs | 6 +++++- 3 files changed, 27 insertions(+), 2 deletions(-) create mode 100644 crates/fj-kernel/src/operations/update/edge.rs diff --git a/crates/fj-kernel/src/operations/mod.rs b/crates/fj-kernel/src/operations/mod.rs index 2f721b6267..6067f1735f 100644 --- a/crates/fj-kernel/src/operations/mod.rs +++ b/crates/fj-kernel/src/operations/mod.rs @@ -7,5 +7,5 @@ mod update; pub use self::{ build::{BuildFace, BuildShell, BuildSurface, Tetrahedron, Triangle}, insert::Insert, - update::{UpdateCycle, UpdateFace, UpdateShell}, + update::{UpdateCycle, UpdateFace, UpdateHalfEdge, UpdateShell}, }; diff --git a/crates/fj-kernel/src/operations/update/edge.rs b/crates/fj-kernel/src/operations/update/edge.rs new file mode 100644 index 0000000000..6a1f0f873c --- /dev/null +++ b/crates/fj-kernel/src/operations/update/edge.rs @@ -0,0 +1,21 @@ +use crate::{ + objects::{GlobalEdge, HalfEdge}, + storage::Handle, +}; + +/// Update a [`HalfEdge`] +pub trait UpdateHalfEdge { + /// Update the global form of the half-edge + fn update_global_form(&self, global_form: Handle) -> HalfEdge; +} + +impl UpdateHalfEdge for HalfEdge { + fn update_global_form(&self, global_form: Handle) -> HalfEdge { + HalfEdge::new( + self.curve(), + self.boundary(), + self.start_vertex().clone(), + global_form, + ) + } +} diff --git a/crates/fj-kernel/src/operations/update/mod.rs b/crates/fj-kernel/src/operations/update/mod.rs index ee531c3f34..73f5d08744 100644 --- a/crates/fj-kernel/src/operations/update/mod.rs +++ b/crates/fj-kernel/src/operations/update/mod.rs @@ -1,5 +1,9 @@ mod cycle; +mod edge; mod face; mod shell; -pub use self::{cycle::UpdateCycle, face::UpdateFace, shell::UpdateShell}; +pub use self::{ + cycle::UpdateCycle, edge::UpdateHalfEdge, face::UpdateFace, + shell::UpdateShell, +}; From 007e605d0e9c25c995b2d4c0fc895b76f7978f31 Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Thu, 23 Mar 2023 14:15:01 +0100 Subject: [PATCH 7/9] Make validation test case more specific --- crates/fj-kernel/src/validate/shell.rs | 44 +++++++++++--------------- 1 file changed, 19 insertions(+), 25 deletions(-) diff --git a/crates/fj-kernel/src/validate/shell.rs b/crates/fj-kernel/src/validate/shell.rs index 4438f7d54a..f4b52cd2fa 100644 --- a/crates/fj-kernel/src/validate/shell.rs +++ b/crates/fj-kernel/src/validate/shell.rs @@ -194,8 +194,11 @@ mod tests { use crate::{ assert_contains_err, builder::{CycleBuilder, FaceBuilder}, - objects::Shell, - operations::{BuildShell, Insert}, + objects::{GlobalEdge, Shell}, + operations::{ + BuildShell, Insert, UpdateCycle, UpdateFace, UpdateHalfEdge, + UpdateShell, + }, services::Services, validate::{shell::ShellValidationError, Validate, ValidationError}, }; @@ -208,29 +211,20 @@ mod tests { [[0., 0., 0.], [1., 0., 0.], [0., 1., 0.], [0., 0., 1.]], &mut services.objects, ); - let invalid = { - let face1 = FaceBuilder::new(services.objects.surfaces.xy_plane()) - .with_exterior(CycleBuilder::polygon([ - [0., 0.], - [0., 1.], - [1., 1.], - [1., 0.], - ])) - .build(&mut services.objects) - .insert(&mut services.objects); - - let face2 = FaceBuilder::new(services.objects.surfaces.xz_plane()) - .with_exterior(CycleBuilder::polygon([ - [0., 0.], - [0., 1.], - [1., 1.], - [1., 0.], - ])) - .build(&mut services.objects) - .insert(&mut services.objects); - - Shell::new([face1, face2]) - }; + let invalid = valid.shell.update_face(&valid.face_abc, |face| { + face.update_exterior(|cycle| { + cycle + .update_half_edge(0, |half_edge| { + let global_form = + GlobalEdge::new().insert(&mut services.objects); + half_edge + .update_global_form(global_form) + .insert(&mut services.objects) + }) + .insert(&mut services.objects) + }) + .insert(&mut services.objects) + }); valid.shell.validate_and_return_first_error()?; assert_contains_err!( From d8f38710fd0e8d413263bffdf9c0940265f4097e Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Thu, 23 Mar 2023 14:40:36 +0100 Subject: [PATCH 8/9] Add `UpdateShell::remove_face` --- crates/fj-kernel/src/operations/update/shell.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/crates/fj-kernel/src/operations/update/shell.rs b/crates/fj-kernel/src/operations/update/shell.rs index 8ac6f62cfa..f8717e6669 100644 --- a/crates/fj-kernel/src/operations/update/shell.rs +++ b/crates/fj-kernel/src/operations/update/shell.rs @@ -11,6 +11,9 @@ pub trait UpdateShell { handle: &Handle, f: impl FnMut(&Handle) -> Handle, ) -> Shell; + + /// Remove a face from the shell + fn remove_face(&self, handle: &Handle) -> Shell; } impl UpdateShell for Shell { @@ -29,4 +32,14 @@ impl UpdateShell for Shell { Shell::new(faces) } + + fn remove_face(&self, handle: &Handle) -> Shell { + let faces = self + .faces() + .into_iter() + .filter(|face| face.id() == handle.id()) + .cloned(); + + Shell::new(faces) + } } From b339ab77efaff1f6596d1762a8bc0a0c2d2d2d44 Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Thu, 23 Mar 2023 14:40:53 +0100 Subject: [PATCH 9/9] Make validation test case more specific --- crates/fj-kernel/src/validate/shell.rs | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/crates/fj-kernel/src/validate/shell.rs b/crates/fj-kernel/src/validate/shell.rs index f4b52cd2fa..11d2815b98 100644 --- a/crates/fj-kernel/src/validate/shell.rs +++ b/crates/fj-kernel/src/validate/shell.rs @@ -193,7 +193,6 @@ impl ShellValidationError { mod tests { use crate::{ assert_contains_err, - builder::{CycleBuilder, FaceBuilder}, objects::{GlobalEdge, Shell}, operations::{ BuildShell, Insert, UpdateCycle, UpdateFace, UpdateHalfEdge, @@ -244,19 +243,7 @@ mod tests { [[0., 0., 0.], [1., 0., 0.], [0., 1., 0.], [0., 0., 1.]], &mut services.objects, ); - let invalid = { - // Shell with single face is not watertight - let face = FaceBuilder::new(services.objects.surfaces.xy_plane()) - .with_exterior(CycleBuilder::polygon([ - [0., 0.], - [0., 1.], - [1., 1.], - [1., 0.], - ])) - .build(&mut services.objects) - .insert(&mut services.objects); - Shell::new([face]) - }; + let invalid = valid.shell.remove_face(&valid.face_abc); valid.shell.validate_and_return_first_error()?; assert_contains_err!(