diff --git a/crates/fj-kernel/src/builder/cycle.rs b/crates/fj-kernel/src/builder/cycle.rs index e35c95eb4..158b057bb 100644 --- a/crates/fj-kernel/src/builder/cycle.rs +++ b/crates/fj-kernel/src/builder/cycle.rs @@ -1,3 +1,5 @@ +use std::collections::VecDeque; + use fj_interop::ext::ArrayExt; use fj_math::Point; @@ -76,6 +78,33 @@ pub trait CycleBuilder { &mut self, points: [impl Into>; 3], ) -> [Partial; 3]; + + /// Connect the cycle to the provided half-edges + /// + /// Assumes that the provided half-edges, once translated into local + /// equivalents of this cycle, will not form a cycle themselves. + /// + /// Returns the local equivalents of the provided half-edges and, as the + /// last entry, an additional half-edge that closes the cycle. + fn connect_to_open_edges( + &mut self, + edges: O, + ) -> O::SizePlusOne> + where + O: ObjectArgument>; + + /// Connect the cycles to the provided half-edges + /// + /// Assumes that the provided half-edges, once translated into local + /// equivalents of this cycle, form a cycle themselves. + /// + /// Returns the local equivalents of the provided half-edges. + fn connect_to_closed_edges( + &mut self, + edges: O, + ) -> O::SameSize> + where + O: ObjectArgument>; } impl CycleBuilder for PartialCycle { @@ -197,4 +226,43 @@ impl CycleBuilder for PartialCycle { half_edges } + + fn connect_to_open_edges( + &mut self, + edges: O, + ) -> O::SizePlusOne> + where + O: ObjectArgument>, + { + // We need to create the additional half-edge last, but at the same time + // need to provide it to the `map_plus_one` method first. Really no + // choice but to create them all in one go, as we do here. + let mut half_edges = VecDeque::new(); + for _ in 0..edges.num_objects() { + half_edges.push_back(self.add_half_edge()); + } + let additional_half_edge = self.add_half_edge(); + + edges.map_plus_one(additional_half_edge, |other| { + let mut this = half_edges.pop_front().expect( + "Pushed correct number of half-edges; should be able to pop", + ); + this.write().update_from_other_edge(&other); + this + }) + } + + fn connect_to_closed_edges( + &mut self, + edges: O, + ) -> O::SameSize> + where + O: ObjectArgument>, + { + edges.map(|other| { + let mut this = self.add_half_edge(); + this.write().update_from_other_edge(&other); + this + }) + } } diff --git a/crates/fj-kernel/src/builder/face.rs b/crates/fj-kernel/src/builder/face.rs index 75d336cee..34bde9efc 100644 --- a/crates/fj-kernel/src/builder/face.rs +++ b/crates/fj-kernel/src/builder/face.rs @@ -4,41 +4,14 @@ use fj_interop::ext::ArrayExt; use crate::{ geometry::path::SurfacePath, - objects::{Cycle, HalfEdge, Surface}, + objects::{Cycle, Surface}, partial::{MaybeSurfacePath, Partial, PartialCycle, PartialFace}, }; -use super::{CycleBuilder, HalfEdgeBuilder, ObjectArgument, SurfaceBuilder}; +use super::SurfaceBuilder; /// Builder API for [`PartialFace`] pub trait FaceBuilder { - /// Connect the face to other faces at the provided half-edges - /// - /// Assumes that the provided half-edges, once translated into local - /// equivalents of this face, will not form a cycle. - /// - /// Returns the local equivalents of the provided half-edges and, as the - /// last entry, an additional half-edge that closes the cycle. - fn connect_to_open_edges( - &mut self, - edges: O, - ) -> O::SizePlusOne> - where - O: ObjectArgument>; - - /// Connect the face to other faces at the provided half-edges - /// - /// Assumes that the provided half-edges, once translated into local - /// equivalents of this face, form a cycle. - /// - /// Returns the local equivalents of the provided half-edges. - fn connect_to_closed_edges( - &mut self, - edges: O, - ) -> O::SameSize> - where - O: ObjectArgument>; - /// Add an interior cycle fn add_interior(&mut self) -> Partial; @@ -59,45 +32,6 @@ pub trait FaceBuilder { } impl FaceBuilder for PartialFace { - fn connect_to_open_edges( - &mut self, - edges: O, - ) -> O::SizePlusOne> - where - O: ObjectArgument>, - { - // We need to create the additional half-edge last, but at the same time - // need to provide it to the `map_plus_one` method first. Really no - // choice but to create them all in one go, as we do here. - let mut half_edges = VecDeque::new(); - for _ in 0..edges.num_objects() { - half_edges.push_back(self.exterior.write().add_half_edge()); - } - let additional_half_edge = self.exterior.write().add_half_edge(); - - edges.map_plus_one(additional_half_edge, |other| { - let mut this = half_edges.pop_front().expect( - "Pushed correct number of half-edges; should be able to pop", - ); - this.write().update_from_other_edge(&other); - this - }) - } - - fn connect_to_closed_edges( - &mut self, - edges: O, - ) -> O::SameSize> - where - O: ObjectArgument>, - { - edges.map(|other| { - let mut this = self.exterior.write().add_half_edge(); - this.write().update_from_other_edge(&other); - this - }) - } - fn add_interior(&mut self) -> Partial { let cycle = Partial::from_partial(PartialCycle { surface: self.exterior.read().surface.clone(),