diff --git a/crates/fj-kernel/src/algorithms/approx/edge.rs b/crates/fj-kernel/src/algorithms/approx/edge.rs index dcab7cc147..27ee3c0e3e 100644 --- a/crates/fj-kernel/src/algorithms/approx/edge.rs +++ b/crates/fj-kernel/src/algorithms/approx/edge.rs @@ -22,14 +22,12 @@ impl Approx for &HalfEdge { tolerance: impl Into, cache: &mut Self::Cache, ) -> Self::Approximation { - let [a, b] = self.vertices(); - let boundary = [a, b].map(|vertex| vertex.position()); + let boundary = self.boundary(); let range = RangeOnPath { boundary }; - let first = ApproxPoint::new( - a.surface_form().position(), - a.surface_form().global_form().position(), - ); + let [first, _] = self.surface_vertices(); + let first = + ApproxPoint::new(first.position(), first.global_form().position()); let curve_approx = (self.curve(), range).approx_with_cache(tolerance, cache); diff --git a/crates/fj-kernel/src/algorithms/intersect/curve_edge.rs b/crates/fj-kernel/src/algorithms/intersect/curve_edge.rs index 0e667ee2b1..eaaca63b52 100644 --- a/crates/fj-kernel/src/algorithms/intersect/curve_edge.rs +++ b/crates/fj-kernel/src/algorithms/intersect/curve_edge.rs @@ -45,9 +45,9 @@ impl CurveEdgeIntersection { } }; - let edge_vertices = half_edge.vertices().clone().map(|vertex| { - edge_curve_as_line.point_from_line_coords(vertex.position()) - }); + let edge_vertices = half_edge + .boundary() + .map(|point| edge_curve_as_line.point_from_line_coords(point)); Segment::from_points(edge_vertices) }; diff --git a/crates/fj-kernel/src/algorithms/intersect/face_point.rs b/crates/fj-kernel/src/algorithms/intersect/face_point.rs index b32f10ae47..a4bf8aebee 100644 --- a/crates/fj-kernel/src/algorithms/intersect/face_point.rs +++ b/crates/fj-kernel/src/algorithms/intersect/face_point.rs @@ -309,9 +309,9 @@ mod tests { .exterior() .half_edges() .find(|edge| { - let [a, b] = edge.vertices(); - a.surface_form().position() == Point::from([0., 0.]) - && b.surface_form().position() == Point::from([2., 0.]) + let [a, b] = edge.surface_vertices(); + a.position() == Point::from([0., 0.]) + && b.position() == Point::from([2., 0.]) }) .unwrap(); assert_eq!( diff --git a/crates/fj-kernel/src/algorithms/intersect/ray_edge.rs b/crates/fj-kernel/src/algorithms/intersect/ray_edge.rs index 962fed93bd..15cfa6be75 100644 --- a/crates/fj-kernel/src/algorithms/intersect/ray_edge.rs +++ b/crates/fj-kernel/src/algorithms/intersect/ray_edge.rs @@ -24,10 +24,9 @@ impl Intersect for (&HorizontalRayToTheRight<2>, &Handle) { } }; - let points = edge.vertices().clone().map(|vertex| { - let point = vertex.position(); - line.point_from_line_coords(point) - }); + let points = edge + .boundary() + .map(|point| line.point_from_line_coords(point)); let segment = Segment::from_points(points); (ray, &segment).intersect() diff --git a/crates/fj-kernel/src/algorithms/intersect/ray_face.rs b/crates/fj-kernel/src/algorithms/intersect/ray_face.rs index 08d4604482..d5f8aece92 100644 --- a/crates/fj-kernel/src/algorithms/intersect/ray_face.rs +++ b/crates/fj-kernel/src/algorithms/intersect/ray_face.rs @@ -253,9 +253,9 @@ mod tests { .exterior() .half_edges() .find(|edge| { - let [a, b] = edge.vertices(); - a.surface_form().position() == Point::from([-1., 1.]) - && b.surface_form().position() == Point::from([-1., -1.]) + let [a, b] = edge.surface_vertices(); + a.position() == Point::from([-1., 1.]) + && b.position() == Point::from([-1., -1.]) }) .unwrap(); assert_eq!( diff --git a/crates/fj-kernel/src/algorithms/sweep/edge.rs b/crates/fj-kernel/src/algorithms/sweep/edge.rs index 4f884a24e0..29e69290de 100644 --- a/crates/fj-kernel/src/algorithms/sweep/edge.rs +++ b/crates/fj-kernel/src/algorithms/sweep/edge.rs @@ -36,11 +36,9 @@ impl Sweep for (Handle, Color) { // is not defined in the right surface. Let's create a new bottom edge, // by swapping the surface of the original. let bottom_edge = { - let vertices = edge.vertices(); - - let points_curve_and_surface = vertices.clone().map(|vertex| { - (vertex.position(), [vertex.position().t, Scalar::ZERO]) - }); + let points_curve_and_surface = edge + .boundary() + .map(|point| (point, [point.t, Scalar::ZERO])); let curve = { // Please note that creating a line here is correct, even if the @@ -63,7 +61,7 @@ impl Sweep for (Handle, Color) { let points_surface = points_curve_and_surface .map(|(_, point_surface)| point_surface); - vertices + edge.vertices() .each_ref_ext() .into_iter_fixed() .zip(points_surface) @@ -89,17 +87,14 @@ impl Sweep for (Handle, Color) { }); let top_edge = { - let bottom_vertices = bottom_edge.vertices(); - let surface_vertices = side_edges.clone().map(|edge| { let [_, vertex] = edge.vertices(); vertex.surface_form().clone() }); - let points_curve_and_surface = - bottom_vertices.clone().map(|vertex| { - (vertex.position(), [vertex.position().t, Scalar::ONE]) - }); + let points_curve_and_surface = bottom_edge + .boundary() + .map(|point| (point, [point.t, Scalar::ONE])); let curve = { let global = bottom_edge @@ -127,14 +122,12 @@ impl Sweep for (Handle, Color) { ) .insert(objects); - let vertices = bottom_vertices - .each_ref_ext() + let vertices = bottom_edge + .boundary() .into_iter_fixed() .zip(surface_vertices) .collect::<[_; 2]>() - .map(|(vertex, surface_form)| { - Vertex::new(vertex.position(), surface_form) - }); + .map(|(point, surface_form)| Vertex::new(point, surface_form)); HalfEdge::new(curve, vertices, global).insert(objects) }; diff --git a/crates/fj-kernel/src/objects/full/cycle.rs b/crates/fj-kernel/src/objects/full/cycle.rs index 3104a7c1fd..dc9f8b1927 100644 --- a/crates/fj-kernel/src/objects/full/cycle.rs +++ b/crates/fj-kernel/src/objects/full/cycle.rs @@ -39,7 +39,7 @@ impl Cycle { /// Access the surface that the cycle is in pub fn surface(&self) -> &Handle { if let Some(half_edge) = self.half_edges.first() { - return half_edge.surface(); + return half_edge.curve().surface(); } unreachable!( @@ -67,8 +67,8 @@ impl Cycle { .next() .expect("Invalid cycle: expected at least one half-edge"); - let [a, b] = first.vertices(); - let edge_direction_positive = a.position() < b.position(); + let [a, b] = first.boundary(); + let edge_direction_positive = a < b; let circle = match first.curve().path() { SurfacePath::Circle(circle) => circle, @@ -93,8 +93,8 @@ impl Cycle { for [a, b] in self.half_edges.as_slice().array_windows_ext() { let [a, b] = [a, b].map(|half_edge| { - let [vertex, _] = half_edge.vertices(); - vertex.surface_form().position() + let [surface_vertex, _] = half_edge.surface_vertices(); + surface_vertex.position() }); sum += (b.u - a.u) * (b.v + a.v); diff --git a/crates/fj-kernel/src/objects/full/edge.rs b/crates/fj-kernel/src/objects/full/edge.rs index 93a82f63c1..1372c09006 100644 --- a/crates/fj-kernel/src/objects/full/edge.rs +++ b/crates/fj-kernel/src/objects/full/edge.rs @@ -1,7 +1,10 @@ use std::fmt; +use fj_interop::ext::ArrayExt; +use fj_math::Point; + use crate::{ - objects::{Curve, GlobalCurve, GlobalVertex, Surface, Vertex}, + objects::{Curve, GlobalCurve, GlobalVertex, SurfaceVertex, Vertex}, storage::{Handle, HandleWrapper}, }; @@ -32,26 +35,21 @@ impl HalfEdge { &self.curve } + /// Access the boundary points of the half-edge on the curve + pub fn boundary(&self) -> [Point<1>; 2] { + self.vertices.each_ref_ext().map(|vertex| vertex.position()) + } + /// Access the vertices that bound the half-edge on the curve pub fn vertices(&self) -> &[Vertex; 2] { &self.vertices } - /// Access the vertex at the back of the half-edge - pub fn back(&self) -> &Vertex { - let [back, _] = self.vertices(); - back - } - - /// Access the vertex at the front of the half-edge - pub fn front(&self) -> &Vertex { - let [_, front] = self.vertices(); - front - } - - /// Access the surface that the half-edge's curve is defined in - pub fn surface(&self) -> &Handle { - self.curve().surface() + /// Access the surface vertices that bound the half-edge + pub fn surface_vertices(&self) -> [&Handle; 2] { + self.vertices + .each_ref_ext() + .map(|vertex| vertex.surface_form()) } /// Access the global form of the half-edge @@ -62,7 +60,7 @@ impl HalfEdge { impl fmt::Display for HalfEdge { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let [a, b] = self.vertices().clone().map(|vertex| vertex.position()); + let [a, b] = self.boundary(); write!(f, "edge from {a:?} to {b:?}")?; write!(f, " on {:?}", self.curve().global_form())?; diff --git a/crates/fj-kernel/src/validate/cycle.rs b/crates/fj-kernel/src/validate/cycle.rs index 41b3e23733..b3fb9bde80 100644 --- a/crates/fj-kernel/src/validate/cycle.rs +++ b/crates/fj-kernel/src/validate/cycle.rs @@ -45,11 +45,8 @@ impl CycleValidationError { errors: &mut Vec, ) { for (a, b) in cycle.half_edges().circular_tuple_windows() { - let [_, prev] = a.vertices(); - let [next, _] = b.vertices(); - - let prev = prev.surface_form(); - let next = next.surface_form(); + let [_, prev] = a.surface_vertices(); + let [next, _] = b.surface_vertices(); if prev.id() != next.id() { errors.push( diff --git a/crates/fj-kernel/src/validate/edge.rs b/crates/fj-kernel/src/validate/edge.rs index 09a711d04c..6f5f127787 100644 --- a/crates/fj-kernel/src/validate/edge.rs +++ b/crates/fj-kernel/src/validate/edge.rs @@ -163,9 +163,9 @@ impl HalfEdgeValidationError { let global_vertices_from_vertices = { let (global_vertices_from_vertices, _) = VerticesInNormalizedOrder::new( - half_edge.vertices().each_ref_ext().map(|vertex| { - vertex.surface_form().global_form().clone() - }), + half_edge.surface_vertices().each_ref_ext().map( + |surface_vertex| surface_vertex.global_form().clone(), + ), ); global_vertices_from_vertices.access_in_normalized_order() @@ -200,8 +200,8 @@ impl HalfEdgeValidationError { ) { let curve_surface = half_edge.curve().surface(); - for vertex in half_edge.vertices() { - let surface_form_surface = vertex.surface_form().surface(); + for surface_vertex in half_edge.surface_vertices() { + let surface_form_surface = surface_vertex.surface(); if curve_surface.id() != surface_form_surface.id() { errors.push( @@ -220,9 +220,7 @@ impl HalfEdgeValidationError { config: &ValidationConfig, errors: &mut Vec, ) { - let back_position = half_edge.back().position(); - let front_position = half_edge.front().position(); - + let [back_position, front_position] = half_edge.boundary(); let distance = (back_position - front_position).magnitude(); if distance < config.distinct_min_distance {