diff --git a/crates/fj-kernel/src/algorithms/approx/cycles.rs b/crates/fj-kernel/src/algorithms/approx/cycles.rs index da1784063..ebf2e1f87 100644 --- a/crates/fj-kernel/src/algorithms/approx/cycles.rs +++ b/crates/fj-kernel/src/algorithms/approx/cycles.rs @@ -19,7 +19,7 @@ impl CycleApprox { pub fn new(cycle: &Cycle, tolerance: Tolerance) -> Self { let mut points = Vec::new(); - for edge in &cycle.edges { + for edge in cycle.edges() { let mut edge_points = Vec::new(); approx_curve( edge.curve().global_form(), diff --git a/crates/fj-kernel/src/algorithms/reverse.rs b/crates/fj-kernel/src/algorithms/reverse.rs index ba391344c..ce7c6a86b 100644 --- a/crates/fj-kernel/src/algorithms/reverse.rs +++ b/crates/fj-kernel/src/algorithms/reverse.rs @@ -26,37 +26,33 @@ fn reverse_local_coordinates_in_cycle<'r>( cycles: impl IntoIterator + 'r, ) -> impl Iterator + 'r { cycles.into_iter().map(|cycle| { - let edges = cycle - .edges - .iter() - .map(|edge| { - let curve = { - let local = match edge.curve().local_form() { - Curve::Circle(Circle { center, a, b }) => { - let center = Point::from([center.u, -center.v]); - - let a = Vector::from([a.u, -a.v]); - let b = Vector::from([b.u, -b.v]); - - Curve::Circle(Circle { center, a, b }) - } - Curve::Line(Line { origin, direction }) => { - let origin = Point::from([origin.u, -origin.v]); - let direction = - Vector::from([direction.u, -direction.v]); - - Curve::Line(Line { origin, direction }) - } - }; - - Local::new(local, *edge.curve().global_form()) + let edges = cycle.edges().map(|edge| { + let curve = { + let local = match edge.curve().local_form() { + Curve::Circle(Circle { center, a, b }) => { + let center = Point::from([center.u, -center.v]); + + let a = Vector::from([a.u, -a.v]); + let b = Vector::from([b.u, -b.v]); + + Curve::Circle(Circle { center, a, b }) + } + Curve::Line(Line { origin, direction }) => { + let origin = Point::from([origin.u, -origin.v]); + let direction = + Vector::from([direction.u, -direction.v]); + + Curve::Line(Line { origin, direction }) + } }; - Edge::new(curve, *edge.vertices()) - }) - .collect(); + Local::new(local, *edge.curve().global_form()) + }; - Cycle { edges } + Edge::new(curve, *edge.vertices()) + }); + + Cycle::new().with_edges(edges) }) } diff --git a/crates/fj-kernel/src/algorithms/sweep.rs b/crates/fj-kernel/src/algorithms/sweep.rs index dc5bf8526..645930bb9 100644 --- a/crates/fj-kernel/src/algorithms/sweep.rs +++ b/crates/fj-kernel/src/algorithms/sweep.rs @@ -40,7 +40,7 @@ pub fn sweep( ); for cycle in face.all_cycles() { - for edge in &cycle.edges { + for edge in cycle.edges() { if let Some(vertices) = edge.vertices().get() { create_non_continuous_side_face( path, @@ -158,7 +158,7 @@ fn create_non_continuous_side_face( edges.push(edge); } - Cycle { edges } + Cycle::new().with_edges(edges) }; let face = Face::new(surface).with_exteriors([cycle]).with_color(color); @@ -174,7 +174,7 @@ fn create_continuous_side_face( ) { let translation = Transform::translation(path); - let cycle = Cycle { edges: vec![edge] }; + let cycle = Cycle::new().with_edges([edge]); let approx = CycleApprox::new(&cycle, tolerance); let mut quads = Vec::new(); diff --git a/crates/fj-kernel/src/algorithms/transform.rs b/crates/fj-kernel/src/algorithms/transform.rs index e79583eea..7493b8944 100644 --- a/crates/fj-kernel/src/algorithms/transform.rs +++ b/crates/fj-kernel/src/algorithms/transform.rs @@ -46,12 +46,9 @@ impl TransformObject for Curve<3> { } impl TransformObject for Cycle { - fn transform(mut self, transform: &Transform) -> Self { - for edge in &mut self.edges { - *edge = edge.transform(transform); - } - - self + fn transform(self, transform: &Transform) -> Self { + Self::new() + .with_edges(self.into_edges().map(|edge| edge.transform(transform))) } } diff --git a/crates/fj-kernel/src/objects/cycle.rs b/crates/fj-kernel/src/objects/cycle.rs index 9946d07d4..c25efdebf 100644 --- a/crates/fj-kernel/src/objects/cycle.rs +++ b/crates/fj-kernel/src/objects/cycle.rs @@ -9,11 +9,30 @@ use super::{Edge, Surface}; /// one. #[derive(Clone, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)] pub struct Cycle { - /// The edges that make up the cycle - pub edges: Vec, + edges: Vec, } impl Cycle { + /// Create a new cycle + #[allow(clippy::new_without_default)] + pub fn new() -> Self { + // Implementation note: + // As I'm writing this, this constructor has no arguments. I expect it + // to take a `Surface` at some point. Remove the `#[allow(...)]` + // attribute then. + // - @hannobraun + + Self { edges: Vec::new() } + } + + /// Add edges to the cycle + /// + /// Consumes the cycle and returns the updated instance. + pub fn with_edges(mut self, edges: impl IntoIterator) -> Self { + self.edges.extend(edges); + self + } + /// Create a polygon from a list of points pub fn polygon_from_points( surface: &Surface, @@ -40,8 +59,13 @@ impl Cycle { Cycle { edges } } - /// Access this cycle's edges + /// Access edges that make up the cycle pub fn edges(&self) -> impl Iterator + '_ { self.edges.iter() } + + /// Consume the cycle and return its edges + pub fn into_edges(self) -> impl Iterator { + self.edges.into_iter() + } } diff --git a/crates/fj-operations/src/difference_2d.rs b/crates/fj-operations/src/difference_2d.rs index 307b0177b..b3fcf500f 100644 --- a/crates/fj-operations/src/difference_2d.rs +++ b/crates/fj-operations/src/difference_2d.rs @@ -92,7 +92,7 @@ impl Shape for fj::Difference2d { fn add_cycle(cycle: Cycle, reverse: bool) -> Cycle { let mut edges = Vec::new(); - for edge in cycle.edges { + for edge in cycle.edges() { let curve_local = if reverse { edge.curve().local_form().reverse() } else { @@ -120,5 +120,5 @@ fn add_cycle(cycle: Cycle, reverse: bool) -> Cycle { edges.reverse(); } - Cycle { edges } + Cycle::new().with_edges(edges) } diff --git a/crates/fj-operations/src/sketch.rs b/crates/fj-operations/src/sketch.rs index 0d0afc801..4fff1c49f 100644 --- a/crates/fj-operations/src/sketch.rs +++ b/crates/fj-operations/src/sketch.rs @@ -26,7 +26,7 @@ impl Shape for fj::Sketch { let edge = Edge::circle_from_radius(Scalar::from_f64(circle.radius())); - let cycle = Cycle { edges: vec![edge] }; + let cycle = Cycle::new().with_edges([edge]); Face::new(surface) .with_exteriors([cycle])