Merge pull request #2148 from hannobraun/validate

Improve validation error message about coincident half-edges not being siblings
This commit is contained in:
Hanno Braun 2023-12-21 21:40:53 +01:00 committed by GitHub
commit 9d56ada45d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -1,10 +1,10 @@
use std::collections::BTreeMap; use std::{collections::BTreeMap, fmt};
use fj_math::{Point, Scalar}; use fj_math::{Point, Scalar};
use crate::{ use crate::{
geometry::SurfaceGeometry, geometry::{CurveBoundary, SurfaceGeometry},
objects::{HalfEdge, Shell, Surface}, objects::{Curve, HalfEdge, Shell, Surface, Vertex},
queries::{ queries::{
AllHalfEdgesWithSurface, BoundingVerticesOfHalfEdge, SiblingOfHalfEdge, AllHalfEdgesWithSurface, BoundingVerticesOfHalfEdge, SiblingOfHalfEdge,
}, },
@ -47,10 +47,28 @@ pub enum ShellValidationError {
#[error( #[error(
"`Shell` contains `HalfEdge`s that are coincident but are not \ "`Shell` contains `HalfEdge`s that are coincident but are not \
siblings\n\ siblings\n\
Half-edge 1: {0:#?}\n\ {boundaries}\
Half-edge 2: {1:#?}" {curves}\
{vertices}\
Half-edge 1: {half_edge_a:#?}\n\
Half-edge 2: {half_edge_b:#?}"
)] )]
CoincidentHalfEdgesAreNotSiblings(Handle<HalfEdge>, Handle<HalfEdge>), CoincidentHalfEdgesAreNotSiblings {
/// The boundaries of the half-edges
boundaries: Box<CoincidentHalfEdgeBoundaries>,
/// The curves of the half-edges
curves: Box<CoincidentHalfEdgeCurves>,
/// The vertices of the half-edges
vertices: Box<CoincidentHalfEdgeVertices>,
/// The first half-edge
half_edge_a: Handle<HalfEdge>,
/// The second half-edge
half_edge_b: Handle<HalfEdge>,
},
} }
impl ShellValidationError { impl ShellValidationError {
@ -225,11 +243,32 @@ impl ShellValidationError {
) )
.all(|d| d < config.distinct_min_distance) .all(|d| d < config.distinct_min_distance)
{ {
let boundaries = Box::new(CoincidentHalfEdgeBoundaries {
boundaries: [half_edge_a, half_edge_b]
.map(|half_edge| half_edge.boundary()),
});
let curves = Box::new(CoincidentHalfEdgeCurves {
curves: [half_edge_a, half_edge_b]
.map(|half_edge| half_edge.curve().clone()),
});
let vertices = Box::new(CoincidentHalfEdgeVertices {
vertices: [half_edge_a, half_edge_b].map(|half_edge| {
shell
.bounding_vertices_of_half_edge(half_edge)
.expect(
"Expected half-edge to be part of shell",
)
}),
});
errors.push( errors.push(
Self::CoincidentHalfEdgesAreNotSiblings( Self::CoincidentHalfEdgesAreNotSiblings {
half_edge_a.clone(), boundaries,
half_edge_b.clone(), curves,
) vertices,
half_edge_a: half_edge_a.clone(),
half_edge_b: half_edge_b.clone(),
}
.into(), .into(),
) )
} }
@ -238,6 +277,52 @@ impl ShellValidationError {
} }
} }
#[derive(Clone, Debug)]
pub struct CoincidentHalfEdgeBoundaries {
pub boundaries: [CurveBoundary<Point<1>>; 2],
}
impl fmt::Display for CoincidentHalfEdgeBoundaries {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let [a, b] = &self.boundaries;
if a != &b.reverse() {
writeln!(
f,
"Boundaries don't match.\n\
\tHalf-edge 1 has boundary `{a:?}`\n\
\tHalf-edge 2 has boundary `{b:?}`\n\
\t(expecting same boundary, but reversed)"
)?;
}
Ok(())
}
}
#[derive(Clone, Debug)]
pub struct CoincidentHalfEdgeCurves {
pub curves: [Handle<Curve>; 2],
}
impl fmt::Display for CoincidentHalfEdgeCurves {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let [a, b] = &self.curves;
if a.id() != b.id() {
writeln!(
f,
"Curves don't match.\n\
\tHalf-edge 1 lies on {a:?}\n\
\tHalf-edge 2 lies on {b:?}\n\
\t(must be the same)"
)?;
}
Ok(())
}
}
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct CurveCoordinateSystemMismatch { pub struct CurveCoordinateSystemMismatch {
pub half_edge_a: Handle<HalfEdge>, pub half_edge_a: Handle<HalfEdge>,
@ -248,6 +333,29 @@ pub struct CurveCoordinateSystemMismatch {
pub distance: Scalar, pub distance: Scalar,
} }
#[derive(Clone, Debug)]
pub struct CoincidentHalfEdgeVertices {
pub vertices: [CurveBoundary<Vertex>; 2],
}
impl fmt::Display for CoincidentHalfEdgeVertices {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let [a, b] = &self.vertices;
if a != &b.clone().reverse() {
writeln!(
f,
"Vertices don't match.\n\
\tHalf-edge 1 is bounded by `{a:?}`\n\
\tHalf-edge 2 is bounded by `{b:?}`\n\
\t(expecting same vertices, but in reverse order)"
)?;
}
Ok(())
}
}
/// Sample two edges at various (currently 3) points in 3D along them. /// Sample two edges at various (currently 3) points in 3D along them.
/// ///
/// Returns an [`Iterator`] of the distance at each sample. /// Returns an [`Iterator`] of the distance at each sample.
@ -395,7 +503,7 @@ mod tests {
assert_contains_err!( assert_contains_err!(
invalid, invalid,
ValidationError::Shell( ValidationError::Shell(
ShellValidationError::CoincidentHalfEdgesAreNotSiblings(..) ShellValidationError::CoincidentHalfEdgesAreNotSiblings { .. }
) )
); );