diff --git a/crates/fj-core/src/algorithms/approx/edge.rs b/crates/fj-core/src/algorithms/approx/edge.rs index 6cff4cecb..19fc1d799 100644 --- a/crates/fj-core/src/algorithms/approx/edge.rs +++ b/crates/fj-core/src/algorithms/approx/edge.rs @@ -30,7 +30,14 @@ impl Approx for (&Handle, &Handle) { let tolerance = tolerance.into(); let start_position_surface = - geometry.of_half_edge(half_edge).start_position(); + geometry.of_half_edge(half_edge).start_position( + &geometry + .of_curve(half_edge.curve()) + .unwrap() + .local_on(surface) + .unwrap() + .path, + ); let start_position = match cache.start_position.get(half_edge.start_vertex()) { Some(position) => position, diff --git a/crates/fj-core/src/geometry/half_edge.rs b/crates/fj-core/src/geometry/half_edge.rs index 0823d6483..0ea12b321 100644 --- a/crates/fj-core/src/geometry/half_edge.rs +++ b/crates/fj-core/src/geometry/half_edge.rs @@ -47,12 +47,12 @@ impl HalfEdgeGeom { } /// Compute the surface position where the half-edge starts - pub fn start_position(&self) -> Point<2> { + pub fn start_position(&self, path: &SurfacePath) -> Point<2> { // Computing the surface position from the curve position is fine. // `HalfEdge` "owns" its start position. There is no competing code that // could compute the surface position from slightly different data. let [start, _] = self.boundary.inner; - self.path.point_from_path_coords(start) + path.point_from_path_coords(start) } } diff --git a/crates/fj-core/src/operations/split/face.rs b/crates/fj-core/src/operations/split/face.rs index 8cfd25d87..b46e241c6 100644 --- a/crates/fj-core/src/operations/split/face.rs +++ b/crates/fj-core/src/operations/split/face.rs @@ -105,8 +105,26 @@ impl SplitFace for Shell { let dividing_half_edge_a_to_d = { let half_edge = HalfEdge::line_segment( [ - core.layers.geometry.of_half_edge(&b).start_position(), - core.layers.geometry.of_half_edge(&d).start_position(), + core.layers.geometry.of_half_edge(&b).start_position( + &core + .layers + .geometry + .of_curve(b.curve()) + .unwrap() + .local_on(face.surface()) + .unwrap() + .path, + ), + core.layers.geometry.of_half_edge(&d).start_position( + &core + .layers + .geometry + .of_curve(d.curve()) + .unwrap() + .local_on(face.surface()) + .unwrap() + .path, + ), ], None, face.surface().clone(), diff --git a/crates/fj-core/src/topology/objects/cycle.rs b/crates/fj-core/src/topology/objects/cycle.rs index 032a3e4b8..019101d37 100644 --- a/crates/fj-core/src/topology/objects/cycle.rs +++ b/crates/fj-core/src/topology/objects/cycle.rs @@ -31,7 +31,11 @@ impl Cycle { /// Please note that this is not *the* winding of the cycle, only one of the /// two possible windings, depending on the direction you look at the /// surface that the cycle is defined on from. - pub fn winding(&self, geometry: &Geometry, _: &Handle) -> Winding { + pub fn winding( + &self, + geometry: &Geometry, + surface: &Handle, + ) -> Winding { // The cycle could be made up of one or two circles. If that is the // case, the winding of the cycle is determined by the winding of the // first circle. @@ -70,7 +74,14 @@ impl Cycle { for (a, b) in self.half_edges().pairs() { let [a, b] = [a, b].map(|half_edge| { - geometry.of_half_edge(half_edge).start_position() + geometry.of_half_edge(half_edge).start_position( + &geometry + .of_curve(half_edge.curve()) + .unwrap() + .local_on(surface) + .unwrap() + .path, + ) }); sum += (b.u - a.u) * (b.v + a.v); diff --git a/crates/fj-core/src/validate/solid.rs b/crates/fj-core/src/validate/solid.rs index 7f392bb6c..f51191aa7 100644 --- a/crates/fj-core/src/validate/solid.rs +++ b/crates/fj-core/src/validate/solid.rs @@ -106,13 +106,23 @@ impl SolidValidationError { .flat_map(|cycle| cycle.half_edges().iter().cloned()) .zip(repeat(face.surface())) }) - .map(|(h, s)| { - ( + .filter_map(|(h, s)| { + let Some(local_curve_geometry) = + geometry.of_curve(h.curve()).unwrap().local_on(s) + else { + // If the curve geometry has no local definition, + // there's nothing we can check. + return None; + }; + + Some(( geometry.of_surface(s).point_from_surface_coords( - geometry.of_half_edge(&h).start_position(), + geometry + .of_half_edge(&h) + .start_position(&local_curve_geometry.path), ), h.start_vertex().clone(), - ) + )) }) .collect(); diff --git a/crates/fj-core/src/validation/checks/curve_geometry_mismatch.rs b/crates/fj-core/src/validation/checks/curve_geometry_mismatch.rs index 6b23093fb..b0c96b1ef 100644 --- a/crates/fj-core/src/validation/checks/curve_geometry_mismatch.rs +++ b/crates/fj-core/src/validation/checks/curve_geometry_mismatch.rs @@ -201,6 +201,9 @@ mod tests { ) .is_err()); + // Ignore remaining validation errors. + let _ = core.layers.validation.take_errors(); + Ok(()) } } diff --git a/crates/fj-core/src/validation/checks/half_edge_connection.rs b/crates/fj-core/src/validation/checks/half_edge_connection.rs index 64166c553..636ca1b56 100644 --- a/crates/fj-core/src/validation/checks/half_edge_connection.rs +++ b/crates/fj-core/src/validation/checks/half_edge_connection.rs @@ -93,7 +93,7 @@ fn check_region<'r>( fn check_cycle<'r>( cycle: &'r Cycle, - _: &'r Handle, + surface: &'r Handle, geometry: &'r Geometry, config: &'r ValidationConfig, ) -> impl Iterator + 'r { @@ -105,8 +105,18 @@ fn check_cycle<'r>( .path .point_from_path_coords(end) }; - let start_pos_of_second_half_edge = - geometry.of_half_edge(second).start_position(); + + let Some(local_curve_geometry) = + geometry.of_curve(second.curve()).unwrap().local_on(surface) + else { + // If the curve geometry is not defined for our local surface, + // there's nothing we can check. + return None; + }; + + let start_pos_of_second_half_edge = geometry + .of_half_edge(second) + .start_position(&local_curve_geometry.path); let distance_between_positions = (end_pos_of_first_half_edge - start_pos_of_second_half_edge)