diff --git a/crates/fj-kernel/src/operations/build/mod.rs b/crates/fj-kernel/src/operations/build/mod.rs index 7f2e1a85a..fe6010c3b 100644 --- a/crates/fj-kernel/src/operations/build/mod.rs +++ b/crates/fj-kernel/src/operations/build/mod.rs @@ -2,12 +2,14 @@ mod cycle; mod edge; mod face; mod shell; +mod solid; mod surface; pub use self::{ cycle::BuildCycle, edge::BuildHalfEdge, face::{BuildFace, Polygon}, - shell::{BuildShell, Tetrahedron}, + shell::{BuildShell, TetrahedronShell}, + solid::{BuildSolid, Tetrahedron}, surface::BuildSurface, }; diff --git a/crates/fj-kernel/src/operations/build/shell.rs b/crates/fj-kernel/src/operations/build/shell.rs index c18b6bc06..41ed095af 100644 --- a/crates/fj-kernel/src/operations/build/shell.rs +++ b/crates/fj-kernel/src/operations/build/shell.rs @@ -2,7 +2,9 @@ use fj_math::Point; use crate::{ objects::{Face, Shell}, - operations::{Insert, IsInsertedYes, JoinCycle, UpdateFace}, + operations::{ + Insert, IsInserted, IsInsertedNo, IsInsertedYes, JoinCycle, UpdateFace, + }, services::Services, }; @@ -31,7 +33,7 @@ pub trait BuildShell { fn tetrahedron( points: [impl Into>; 4], services: &mut Services, - ) -> Tetrahedron { + ) -> TetrahedronShell { let [a, b, c, d] = points.map(Into::into); let abc = Face::triangle([a, b, c], services); @@ -64,7 +66,7 @@ pub trait BuildShell { let [abc, bad, dac, cbd] = triangles; - Tetrahedron { + TetrahedronShell { shell, abc, bad, @@ -83,9 +85,9 @@ impl BuildShell for Shell {} /// `d`, in the order in which they are passed. /// /// Returned by [`BuildShell::tetrahedron`]. -pub struct Tetrahedron { +pub struct TetrahedronShell { /// The shell that forms the tetrahedron - pub shell: Shell, + pub shell: I::T, /// The face formed by the points `a`, `b`, and `c`. pub abc: Polygon<3, IsInsertedYes>, diff --git a/crates/fj-kernel/src/operations/build/solid.rs b/crates/fj-kernel/src/operations/build/solid.rs new file mode 100644 index 000000000..080405ee5 --- /dev/null +++ b/crates/fj-kernel/src/operations/build/solid.rs @@ -0,0 +1,44 @@ +use fj_math::Point; + +use crate::{ + objects::{Shell, Solid}, + operations::{ + build::shell::BuildShell, Insert, IsInsertedYes, TetrahedronShell, + UpdateSolid, + }, + services::Services, +}; + +/// Build a [`Solid`] +pub trait BuildSolid { + /// Build an empty solid + fn empty() -> Solid { + Solid::new([]) + } + + /// Build a tetrahedron from the provided points + /// + /// See [`BuildShell::tetrahedron`] for more information. + fn tetrahedron( + points: [impl Into>; 4], + services: &mut Services, + ) -> Tetrahedron { + let shell = Shell::tetrahedron(points, services).insert(services); + let solid = Solid::empty().add_shell(shell.shell.clone()); + + Tetrahedron { solid, shell } + } +} + +impl BuildSolid for Solid {} + +/// A tetrahedron +/// +/// Returned by [`BuildSolid::tetrahedron`]. +pub struct Tetrahedron { + /// The solid that forms the tetrahedron + pub solid: Solid, + + /// The shell of the tetrahedron + pub shell: TetrahedronShell, +} diff --git a/crates/fj-kernel/src/operations/insert.rs b/crates/fj-kernel/src/operations/insert.rs index 6cf0eebc4..66b6a1b42 100644 --- a/crates/fj-kernel/src/operations/insert.rs +++ b/crates/fj-kernel/src/operations/insert.rs @@ -7,7 +7,7 @@ use crate::{ storage::Handle, }; -use super::Polygon; +use super::{Polygon, TetrahedronShell}; /// Insert an object into its respective store /// @@ -91,3 +91,17 @@ impl Insert for Polygon { } } } + +impl Insert for TetrahedronShell { + type Inserted = TetrahedronShell; + + fn insert(self, services: &mut Services) -> Self::Inserted { + TetrahedronShell { + shell: self.shell.insert(services), + abc: self.abc, + bad: self.bad, + dac: self.dac, + cbd: self.cbd, + } + } +} diff --git a/crates/fj-kernel/src/operations/mod.rs b/crates/fj-kernel/src/operations/mod.rs index de4ebc596..313bdeaae 100644 --- a/crates/fj-kernel/src/operations/mod.rs +++ b/crates/fj-kernel/src/operations/mod.rs @@ -7,10 +7,12 @@ mod update; pub use self::{ build::{ - BuildCycle, BuildFace, BuildHalfEdge, BuildShell, BuildSurface, - Polygon, Tetrahedron, + BuildCycle, BuildFace, BuildHalfEdge, BuildShell, BuildSolid, + BuildSurface, Polygon, Tetrahedron, TetrahedronShell, }, insert::{Insert, IsInserted, IsInsertedNo, IsInsertedYes}, join::JoinCycle, - update::{UpdateCycle, UpdateFace, UpdateHalfEdge, UpdateShell}, + update::{ + UpdateCycle, UpdateFace, UpdateHalfEdge, UpdateShell, UpdateSolid, + }, }; diff --git a/crates/fj-kernel/src/operations/update/mod.rs b/crates/fj-kernel/src/operations/update/mod.rs index 73f5d0874..431b97368 100644 --- a/crates/fj-kernel/src/operations/update/mod.rs +++ b/crates/fj-kernel/src/operations/update/mod.rs @@ -2,8 +2,9 @@ mod cycle; mod edge; mod face; mod shell; +mod solid; pub use self::{ cycle::UpdateCycle, edge::UpdateHalfEdge, face::UpdateFace, - shell::UpdateShell, + shell::UpdateShell, solid::UpdateSolid, }; diff --git a/crates/fj-kernel/src/operations/update/solid.rs b/crates/fj-kernel/src/operations/update/solid.rs new file mode 100644 index 000000000..9c0e340f7 --- /dev/null +++ b/crates/fj-kernel/src/operations/update/solid.rs @@ -0,0 +1,17 @@ +use crate::{ + objects::{Shell, Solid}, + storage::Handle, +}; + +/// Update a [`Solid`] +pub trait UpdateSolid { + /// Add a shell to the solid + fn add_shell(&self, shell: Handle) -> Solid; +} + +impl UpdateSolid for Solid { + fn add_shell(&self, shell: Handle) -> Solid { + let shells = self.shells().cloned().chain([shell]); + Solid::new(shells) + } +} diff --git a/crates/fj-kernel/src/validate/shell.rs b/crates/fj-kernel/src/validate/shell.rs index c20622333..91915bc3e 100644 --- a/crates/fj-kernel/src/validate/shell.rs +++ b/crates/fj-kernel/src/validate/shell.rs @@ -235,6 +235,7 @@ mod tests { Ok(()) } + #[test] fn shell_not_watertight() -> anyhow::Result<()> { let mut services = Services::new();