mirror of https://github.com/hannobraun/Fornjot
Merge pull request #738 from hannobraun/validation
Remove structural validation
This commit is contained in:
commit
318dc7b9f8
|
@ -26,12 +26,10 @@
|
||||||
//! [`Shape`]: crate::shape::Shape
|
//! [`Shape`]: crate::shape::Shape
|
||||||
|
|
||||||
mod coherence;
|
mod coherence;
|
||||||
mod structural;
|
|
||||||
mod uniqueness;
|
mod uniqueness;
|
||||||
|
|
||||||
pub use self::{
|
pub use self::{
|
||||||
coherence::{CoherenceIssues, CoherenceMismatch},
|
coherence::{CoherenceIssues, CoherenceMismatch},
|
||||||
structural::StructuralIssues,
|
|
||||||
uniqueness::UniquenessIssues,
|
uniqueness::UniquenessIssues,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -39,10 +37,7 @@ use std::{collections::HashSet, ops::Deref};
|
||||||
|
|
||||||
use fj_math::Scalar;
|
use fj_math::Scalar;
|
||||||
|
|
||||||
use crate::{
|
use crate::iter::ObjectIters;
|
||||||
iter::ObjectIters,
|
|
||||||
objects::{Curve, Cycle, Edge, Surface, Vertex},
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Validate the given [`Shape`]
|
/// Validate the given [`Shape`]
|
||||||
pub fn validate<T>(
|
pub fn validate<T>(
|
||||||
|
@ -52,16 +47,8 @@ pub fn validate<T>(
|
||||||
where
|
where
|
||||||
T: ObjectIters,
|
T: ObjectIters,
|
||||||
{
|
{
|
||||||
let mut curves = HashSet::new();
|
|
||||||
let mut cycles = HashSet::new();
|
|
||||||
let mut edges = HashSet::new();
|
|
||||||
let mut surfaces = HashSet::new();
|
|
||||||
let mut vertices = HashSet::new();
|
let mut vertices = HashSet::new();
|
||||||
|
|
||||||
for curve in object.curve_iter() {
|
|
||||||
curves.insert(curve);
|
|
||||||
}
|
|
||||||
|
|
||||||
for vertex in object.vertex_iter() {
|
for vertex in object.vertex_iter() {
|
||||||
uniqueness::validate_vertex(&vertex, &vertices)?;
|
uniqueness::validate_vertex(&vertex, &vertices)?;
|
||||||
|
|
||||||
|
@ -70,23 +57,6 @@ where
|
||||||
|
|
||||||
for edge in object.edge_iter() {
|
for edge in object.edge_iter() {
|
||||||
coherence::validate_edge(&edge, config.identical_max_distance)?;
|
coherence::validate_edge(&edge, config.identical_max_distance)?;
|
||||||
structural::validate_edge(&edge, &curves, &vertices)?;
|
|
||||||
|
|
||||||
edges.insert(edge);
|
|
||||||
}
|
|
||||||
|
|
||||||
for cycle in object.cycle_iter() {
|
|
||||||
structural::validate_cycle(&cycle, &edges)?;
|
|
||||||
|
|
||||||
cycles.insert(cycle);
|
|
||||||
}
|
|
||||||
|
|
||||||
for surface in object.surface_iter() {
|
|
||||||
surfaces.insert(surface);
|
|
||||||
}
|
|
||||||
|
|
||||||
for face in object.face_iter() {
|
|
||||||
structural::validate_face(&face, &cycles, &surfaces)?;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Validated(object))
|
Ok(Validated(object))
|
||||||
|
@ -157,75 +127,17 @@ pub enum ValidationError {
|
||||||
#[error("Geometric validation failed")]
|
#[error("Geometric validation failed")]
|
||||||
Geometric,
|
Geometric,
|
||||||
|
|
||||||
/// Structural validation failed
|
|
||||||
#[error("Structural validation failed")]
|
|
||||||
Structural(#[from] StructuralIssues),
|
|
||||||
|
|
||||||
/// Uniqueness validation failed
|
/// Uniqueness validation failed
|
||||||
#[error("Uniqueness validation failed")]
|
#[error("Uniqueness validation failed")]
|
||||||
Uniqueness(#[from] UniquenessIssues),
|
Uniqueness(#[from] UniquenessIssues),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ValidationError {
|
|
||||||
/// Indicate whether validation found a missing curve
|
|
||||||
pub fn missing_curve(&self, curve: &Curve<3>) -> bool {
|
|
||||||
if let Self::Structural(StructuralIssues { missing_curve, .. }) = self {
|
|
||||||
return missing_curve.as_ref() == Some(curve);
|
|
||||||
}
|
|
||||||
|
|
||||||
false
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Indicate whether validation found a missing vertex
|
|
||||||
pub fn missing_vertex(&self, vertex: &Vertex) -> bool {
|
|
||||||
if let Self::Structural(StructuralIssues {
|
|
||||||
missing_vertices, ..
|
|
||||||
}) = self
|
|
||||||
{
|
|
||||||
return missing_vertices.contains(vertex);
|
|
||||||
}
|
|
||||||
|
|
||||||
false
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Indicate whether validation found a missing edge
|
|
||||||
pub fn missing_edge(&self, edge: &Edge<3>) -> bool {
|
|
||||||
if let Self::Structural(StructuralIssues { missing_edges, .. }) = self {
|
|
||||||
return missing_edges.contains(edge);
|
|
||||||
}
|
|
||||||
|
|
||||||
false
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Indicate whether validation found a missing surface
|
|
||||||
pub fn missing_surface(&self, surface: &Surface) -> bool {
|
|
||||||
if let Self::Structural(StructuralIssues {
|
|
||||||
missing_surface, ..
|
|
||||||
}) = self
|
|
||||||
{
|
|
||||||
return missing_surface.as_ref() == Some(surface);
|
|
||||||
}
|
|
||||||
|
|
||||||
false
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Indicate whether validation found a missing cycle
|
|
||||||
pub fn missing_cycle(&self, cycle: &Cycle<3>) -> bool {
|
|
||||||
if let Self::Structural(StructuralIssues { missing_cycles, .. }) = self
|
|
||||||
{
|
|
||||||
return missing_cycles.contains(cycle);
|
|
||||||
}
|
|
||||||
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use fj_math::{Point, Scalar};
|
use fj_math::{Point, Scalar};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
objects::{Curve, Cycle, Edge, Face, Surface, Vertex, VerticesOfEdge},
|
objects::{Curve, Edge, Vertex, VerticesOfEdge},
|
||||||
shape::{LocalForm, Shape},
|
shape::{LocalForm, Shape},
|
||||||
validation::{validate, ValidationConfig, ValidationError},
|
validation::{validate, ValidationConfig, ValidationError},
|
||||||
};
|
};
|
||||||
|
@ -270,91 +182,6 @@ mod tests {
|
||||||
assert!(result.is_err());
|
assert!(result.is_err());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn structural_cycle() {
|
|
||||||
let mut shape = Shape::new();
|
|
||||||
|
|
||||||
// Trying to refer to edge that is not from the same shape. Should fail.
|
|
||||||
let edge = Edge::line_segment_from_points([[0., 0., 0.], [1., 0., 0.]]);
|
|
||||||
shape.insert(Cycle::new(vec![edge.clone()]));
|
|
||||||
let err =
|
|
||||||
validate(shape.clone(), &ValidationConfig::default()).unwrap_err();
|
|
||||||
assert!(err.missing_edge(&edge));
|
|
||||||
|
|
||||||
// Referring to edge that *is* from the same shape. Should work.
|
|
||||||
let edge = Edge::line_segment_from_points([[0., 0., 0.], [1., 0., 0.]]);
|
|
||||||
shape.insert(Cycle::new(vec![edge]));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn structural_edge() {
|
|
||||||
let mut shape = Shape::new();
|
|
||||||
|
|
||||||
let curve = Curve::x_axis();
|
|
||||||
let a = Vertex::from_point([1., 0., 0.]);
|
|
||||||
let b = Vertex::from_point([2., 0., 0.]);
|
|
||||||
|
|
||||||
let a = LocalForm::new(Point::from([1.]), a);
|
|
||||||
let b = LocalForm::new(Point::from([2.]), b);
|
|
||||||
|
|
||||||
// Shouldn't work. Nothing has been added to `shape`.
|
|
||||||
shape.insert(Edge {
|
|
||||||
curve: LocalForm::canonical_only(curve),
|
|
||||||
vertices: VerticesOfEdge::from_vertices([a.clone(), b.clone()]),
|
|
||||||
});
|
|
||||||
let err =
|
|
||||||
validate(shape.clone(), &ValidationConfig::default()).unwrap_err();
|
|
||||||
assert!(err.missing_curve(&curve));
|
|
||||||
assert!(err.missing_vertex(&a.canonical()));
|
|
||||||
assert!(err.missing_vertex(&b.canonical()));
|
|
||||||
|
|
||||||
let curve = Curve::x_axis();
|
|
||||||
let a = Vertex::from_point([1., 0., 0.]);
|
|
||||||
let b = Vertex::from_point([2., 0., 0.]);
|
|
||||||
|
|
||||||
let a = LocalForm::new(Point::from([1.]), a);
|
|
||||||
let b = LocalForm::new(Point::from([2.]), b);
|
|
||||||
|
|
||||||
// Everything has been added to `shape` now. Should work!
|
|
||||||
shape.insert(Edge {
|
|
||||||
curve: LocalForm::canonical_only(curve),
|
|
||||||
vertices: VerticesOfEdge::from_vertices([a, b]),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn structural_face() {
|
|
||||||
let mut shape = Shape::new();
|
|
||||||
|
|
||||||
let triangle = [[0., 0.], [1., 0.], [0., 1.]];
|
|
||||||
|
|
||||||
let surface = Surface::xy_plane();
|
|
||||||
let cycle = Cycle::polygon_from_points(&surface, triangle);
|
|
||||||
|
|
||||||
// Nothing has been added to `shape`. Should fail.
|
|
||||||
shape.insert(Face::new(
|
|
||||||
surface,
|
|
||||||
vec![cycle.clone()],
|
|
||||||
Vec::new(),
|
|
||||||
[255, 0, 0, 255],
|
|
||||||
));
|
|
||||||
let err =
|
|
||||||
validate(shape.clone(), &ValidationConfig::default()).unwrap_err();
|
|
||||||
assert!(err.missing_surface(&surface));
|
|
||||||
assert!(err.missing_cycle(&cycle.canonical()));
|
|
||||||
|
|
||||||
let surface = Surface::xy_plane();
|
|
||||||
let cycle = Cycle::polygon_from_points(&surface, triangle);
|
|
||||||
|
|
||||||
// Everything has been added to `shape` now. Should work!
|
|
||||||
shape.insert(Face::new(
|
|
||||||
surface,
|
|
||||||
vec![cycle],
|
|
||||||
Vec::new(),
|
|
||||||
[255, 0, 0, 255],
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn uniqueness_vertex() -> anyhow::Result<()> {
|
fn uniqueness_vertex() -> anyhow::Result<()> {
|
||||||
let mut shape = Shape::new();
|
let mut shape = Shape::new();
|
||||||
|
|
|
@ -1,139 +0,0 @@
|
||||||
use std::{collections::HashSet, fmt};
|
|
||||||
|
|
||||||
use crate::objects::{Curve, Cycle, Edge, Face, Surface, Vertex};
|
|
||||||
|
|
||||||
pub fn validate_edge(
|
|
||||||
edge: &Edge<3>,
|
|
||||||
curves: &HashSet<Curve<3>>,
|
|
||||||
vertices: &HashSet<Vertex>,
|
|
||||||
) -> Result<(), StructuralIssues> {
|
|
||||||
let mut missing_curve = None;
|
|
||||||
let mut missing_vertices = HashSet::new();
|
|
||||||
|
|
||||||
if !curves.contains(&edge.curve()) {
|
|
||||||
missing_curve = Some(edge.curve.canonical());
|
|
||||||
}
|
|
||||||
for vertex in edge.vertices().into_iter().flatten() {
|
|
||||||
if !vertices.contains(&vertex) {
|
|
||||||
missing_vertices.insert(vertex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if missing_curve.is_some() || !missing_vertices.is_empty() {
|
|
||||||
return Err(StructuralIssues {
|
|
||||||
missing_curve,
|
|
||||||
missing_vertices,
|
|
||||||
..StructuralIssues::default()
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn validate_cycle(
|
|
||||||
cycle: &Cycle<3>,
|
|
||||||
edges: &HashSet<Edge<3>>,
|
|
||||||
) -> Result<(), StructuralIssues> {
|
|
||||||
let mut missing_edges = HashSet::new();
|
|
||||||
for edge in cycle.edges() {
|
|
||||||
if !edges.contains(&edge) {
|
|
||||||
missing_edges.insert(edge);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if !missing_edges.is_empty() {
|
|
||||||
return Err(StructuralIssues {
|
|
||||||
missing_edges,
|
|
||||||
..StructuralIssues::default()
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn validate_face(
|
|
||||||
face: &Face,
|
|
||||||
cycles: &HashSet<Cycle<3>>,
|
|
||||||
surfaces: &HashSet<Surface>,
|
|
||||||
) -> Result<(), StructuralIssues> {
|
|
||||||
if let Face::Face(face) = face {
|
|
||||||
let mut missing_surface = None;
|
|
||||||
let mut missing_cycles = HashSet::new();
|
|
||||||
|
|
||||||
if !surfaces.contains(&face.surface()) {
|
|
||||||
missing_surface = Some(face.surface);
|
|
||||||
}
|
|
||||||
for cycle in face.all_cycles() {
|
|
||||||
if !cycles.contains(&cycle) {
|
|
||||||
missing_cycles.insert(cycle);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if missing_surface.is_some() || !missing_cycles.is_empty() {
|
|
||||||
return Err(StructuralIssues {
|
|
||||||
missing_surface,
|
|
||||||
missing_cycles,
|
|
||||||
..StructuralIssues::default()
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Structural issues found during validation
|
|
||||||
///
|
|
||||||
/// Used by [`ValidationError`].
|
|
||||||
#[derive(Debug, Default, thiserror::Error)]
|
|
||||||
pub struct StructuralIssues {
|
|
||||||
/// Missing curve found in edge validation
|
|
||||||
pub missing_curve: Option<Curve<3>>,
|
|
||||||
|
|
||||||
/// Missing vertices found in edge validation
|
|
||||||
pub missing_vertices: HashSet<Vertex>,
|
|
||||||
|
|
||||||
/// Missing edges found in cycle validation
|
|
||||||
pub missing_edges: HashSet<Edge<3>>,
|
|
||||||
|
|
||||||
/// Missing surface found in face validation
|
|
||||||
pub missing_surface: Option<Surface>,
|
|
||||||
|
|
||||||
/// Missing cycles found in face validation
|
|
||||||
pub missing_cycles: HashSet<Cycle<3>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for StructuralIssues {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
writeln!(f, "Structural issues found:")?;
|
|
||||||
|
|
||||||
if let Some(curve) = &self.missing_curve {
|
|
||||||
writeln!(f, "- Missing curve: {:?}", curve)?;
|
|
||||||
}
|
|
||||||
if !self.missing_vertices.is_empty() {
|
|
||||||
writeln!(f, "- Missing vertices:")?;
|
|
||||||
|
|
||||||
for vertex in &self.missing_vertices {
|
|
||||||
writeln!(f, " - {:?}", vertex)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !self.missing_edges.is_empty() {
|
|
||||||
writeln!(f, "- Missing edges:")?;
|
|
||||||
|
|
||||||
for edge in &self.missing_edges {
|
|
||||||
writeln!(f, " - {}", edge)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if let Some(surface) = &self.missing_surface {
|
|
||||||
writeln!(f, "- Missing surface: {:?}", surface)?;
|
|
||||||
}
|
|
||||||
if !self.missing_cycles.is_empty() {
|
|
||||||
writeln!(f, "- Missing cycles:")?;
|
|
||||||
|
|
||||||
for cycle in &self.missing_cycles {
|
|
||||||
writeln!(f, " - {:?}", cycle)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue