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
|
||||
|
||||
mod coherence;
|
||||
mod structural;
|
||||
mod uniqueness;
|
||||
|
||||
pub use self::{
|
||||
coherence::{CoherenceIssues, CoherenceMismatch},
|
||||
structural::StructuralIssues,
|
||||
uniqueness::UniquenessIssues,
|
||||
};
|
||||
|
||||
|
@ -39,10 +37,7 @@ use std::{collections::HashSet, ops::Deref};
|
|||
|
||||
use fj_math::Scalar;
|
||||
|
||||
use crate::{
|
||||
iter::ObjectIters,
|
||||
objects::{Curve, Cycle, Edge, Surface, Vertex},
|
||||
};
|
||||
use crate::iter::ObjectIters;
|
||||
|
||||
/// Validate the given [`Shape`]
|
||||
pub fn validate<T>(
|
||||
|
@ -52,16 +47,8 @@ pub fn validate<T>(
|
|||
where
|
||||
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();
|
||||
|
||||
for curve in object.curve_iter() {
|
||||
curves.insert(curve);
|
||||
}
|
||||
|
||||
for vertex in object.vertex_iter() {
|
||||
uniqueness::validate_vertex(&vertex, &vertices)?;
|
||||
|
||||
|
@ -70,23 +57,6 @@ where
|
|||
|
||||
for edge in object.edge_iter() {
|
||||
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))
|
||||
|
@ -157,75 +127,17 @@ pub enum ValidationError {
|
|||
#[error("Geometric validation failed")]
|
||||
Geometric,
|
||||
|
||||
/// Structural validation failed
|
||||
#[error("Structural validation failed")]
|
||||
Structural(#[from] StructuralIssues),
|
||||
|
||||
/// Uniqueness validation failed
|
||||
#[error("Uniqueness validation failed")]
|
||||
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)]
|
||||
mod tests {
|
||||
use fj_math::{Point, Scalar};
|
||||
|
||||
use crate::{
|
||||
objects::{Curve, Cycle, Edge, Face, Surface, Vertex, VerticesOfEdge},
|
||||
objects::{Curve, Edge, Vertex, VerticesOfEdge},
|
||||
shape::{LocalForm, Shape},
|
||||
validation::{validate, ValidationConfig, ValidationError},
|
||||
};
|
||||
|
@ -270,91 +182,6 @@ mod tests {
|
|||
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]
|
||||
fn uniqueness_vertex() -> anyhow::Result<()> {
|
||||
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