diff --git a/crates/fj-kernel/src/algorithms/validate/coherence.rs b/crates/fj-kernel/src/algorithms/validate/coherence.rs index b227a6760..d3f679b8f 100644 --- a/crates/fj-kernel/src/algorithms/validate/coherence.rs +++ b/crates/fj-kernel/src/algorithms/validate/coherence.rs @@ -2,7 +2,38 @@ use std::fmt; use fj_math::{Point, Scalar}; -use crate::objects::Vertex; +use crate::objects::{Curve, Vertex}; + +pub fn validate_curve( + curve: &Curve, + max_distance: impl Into, +) -> Result<(), CoherenceIssues> { + let max_distance = max_distance.into(); + + let points_curve = [-2., -1., 0., 1., 2.].map(|point| Point::from([point])); + + for point_curve in points_curve { + let point_surface = curve.kind().point_from_curve_coords(point_curve); + let point_surface_as_global = + curve.surface().point_from_surface_coords(point_surface); + let point_global = + curve.global().kind().point_from_curve_coords(point_curve); + + let distance = (point_surface_as_global - point_global).magnitude(); + + if distance > max_distance { + Err(CurveCoherenceMismatch { + point_curve, + point_surface, + point_surface_as_global, + point_global, + curve: *curve, + })? + } + } + + Ok(()) +} pub fn validate_vertex( vertex: &Vertex, @@ -35,13 +66,49 @@ pub fn validate_vertex( } /// Issues in coherence validation +#[allow(clippy::large_enum_variant)] #[derive(Debug, thiserror::Error)] pub enum CoherenceIssues { + /// Mismatch between the surface and global forms of a curve + #[error("Mismatch between surface and global forms of curve")] + Curve(#[from] CurveCoherenceMismatch), + /// Mismatch between the local and global coordinates of a vertex #[error("Mismatch between local and global coordinates of vertex")] Vertex(#[from] VertexCoherenceMismatch), } +/// A mismatch between the surface and global forms of a curve +/// +/// Used in [`CoherenceIssues`]. +#[derive(Debug, thiserror::Error)] +pub struct CurveCoherenceMismatch { + /// The curve coordinate for which a mismatch was found + pub point_curve: Point<1>, + + /// The curve coordinate, converted to surface coordinates + pub point_surface: Point<2>, + + /// The surface coordinates, converted to global coordinates + pub point_surface_as_global: Point<3>, + + /// The curve coordinate, converted to global coordinates + pub point_global: Point<3>, + + /// The incoherent curve + pub curve: Curve, +} + +impl fmt::Display for CurveCoherenceMismatch { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!( + f, + "local: {:?} (converted to surface: {:?}; to global: {:?}), global: {:?},", + self.point_curve, self.point_surface, self.point_surface_as_global, self.point_global, + ) + } +} + /// A mismatch between the local and global forms of a vertex /// /// Used in [`CoherenceIssues`]. diff --git a/crates/fj-kernel/src/algorithms/validate/mod.rs b/crates/fj-kernel/src/algorithms/validate/mod.rs index c9fc651c2..e670d6cd0 100644 --- a/crates/fj-kernel/src/algorithms/validate/mod.rs +++ b/crates/fj-kernel/src/algorithms/validate/mod.rs @@ -63,6 +63,10 @@ where ) -> Result, ValidationError> { let mut global_vertices = HashSet::new(); + for curve in self.curve_iter() { + coherence::validate_curve(curve, config.identical_max_distance)?; + } + for global_vertex in self.global_vertex_iter() { uniqueness::validate_vertex( global_vertex, @@ -152,7 +156,7 @@ pub enum ValidationError { #[cfg(test)] mod tests { - use fj_math::{Point, Scalar}; + use fj_math::{Line, Point, Scalar}; use crate::{ algorithms::validate::{Validate, ValidationConfig, ValidationError}, @@ -162,6 +166,22 @@ mod tests { }, }; + #[test] + fn coherence_curve() { + let line_global = Line::from_points([[0., 0., 0.], [1., 0., 0.]]); + let global_curve = GlobalCurve::from_kind(CurveKind::Line(line_global)); + + let line_surface = Line::from_points([[0., 0.], [2., 0.]]); + let curve = Curve::new( + Surface::xy_plane(), + CurveKind::Line(line_surface), + global_curve, + ); + + let result = curve.validate(); + assert!(result.is_err()); + } + #[test] fn coherence_edge() { let a = Point::from([0., 0., 0.]);