Skip to content

Commit

Permalink
Merge pull request #709 from hannobraun/validation
Browse files Browse the repository at this point in the history
Move structural validation to new infrastructure
  • Loading branch information
hannobraun authored Jun 21, 2022
2 parents 58730b3 + 0388106 commit 9b27744
Show file tree
Hide file tree
Showing 5 changed files with 153 additions and 127 deletions.
96 changes: 0 additions & 96 deletions crates/fj-kernel/src/shape/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -331,45 +331,6 @@ mod tests {
Ok(())
}

#[test]
fn add_edge() -> anyhow::Result<()> {
let mut shape = Shape::new();
let mut other = Shape::new();

let curve = other.insert(Curve::x_axis())?;
let a = Vertex::builder(&mut other).build_from_point([1., 0., 0.])?;
let b = Vertex::builder(&mut other).build_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`.
let err = shape
.insert(Edge {
curve: LocalForm::canonical_only(curve.clone()),
vertices: VerticesOfEdge::from_vertices([a.clone(), b.clone()]),
})
.unwrap_err();
assert!(err.missing_curve(&curve));
assert!(err.missing_vertex(&a.canonical()));
assert!(err.missing_vertex(&b.canonical()));

let curve = shape.insert(Curve::x_axis())?;
let a = Vertex::builder(&mut shape).build_from_point([1., 0., 0.])?;
let b = Vertex::builder(&mut shape).build_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]),
})?;

Ok(())
}

#[test]
fn add_edge_uniqueness() -> anyhow::Result<()> {
let mut shape = Shape::new();
Expand All @@ -393,61 +354,4 @@ mod tests {

Ok(())
}

#[test]
fn add_cycle() -> anyhow::Result<()> {
let mut shape = Shape::new();
let mut other = Shape::new();

// Trying to refer to edge that is not from the same shape. Should fail.
let edge = Edge::builder(&mut other)
.build_line_segment_from_points([[0., 0., 0.], [1., 0., 0.]])?;
let err = shape.insert(Cycle::new(vec![edge.clone()])).unwrap_err();
assert!(err.missing_edge(&edge));

// Referring to edge that *is* from the same shape. Should work.
let edge = Edge::builder(&mut shape)
.build_line_segment_from_points([[0., 0., 0.], [1., 0., 0.]])?;
shape.insert(Cycle::new(vec![edge]))?;

Ok(())
}

#[test]
fn add_face() -> anyhow::Result<()> {
let mut shape = Shape::new();
let mut other = Shape::new();

let triangle = [[0., 0.], [1., 0.], [0., 1.]];

let surface = other.insert(Surface::xy_plane())?;
let cycle = Cycle::builder(surface.get(), &mut other)
.build_polygon(triangle)?;

// Nothing has been added to `shape`. Should fail.
let err = shape
.insert(Face::new(
surface.clone(),
vec![cycle.clone()],
Vec::new(),
[255, 0, 0, 255],
))
.unwrap_err();
assert!(err.missing_surface(&surface));
assert!(err.missing_cycle(&cycle.canonical()));

let surface = shape.insert(Surface::xy_plane())?;
let cycle = Cycle::builder(surface.get(), &mut shape)
.build_polygon(triangle)?;

// Everything has been added to `shape` now. Should work!
shape.insert(Face::new(
surface,
vec![cycle],
Vec::new(),
[255, 0, 0, 255],
))?;

Ok(())
}
}
4 changes: 1 addition & 3 deletions crates/fj-kernel/src/shape/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,5 @@ pub use self::{
object::Object,
stores::{Handle, Iter},
update::Update,
validate::{
DuplicateEdge, StructuralIssues, UniquenessIssues, ValidationResult,
},
validate::{DuplicateEdge, UniquenessIssues, ValidationResult},
};
13 changes: 3 additions & 10 deletions crates/fj-kernel/src/shape/validate/mod.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
mod structural;
mod uniqueness;

pub use self::{
structural::StructuralIssues,
uniqueness::{DuplicateEdge, UniquenessIssues},
};
pub use self::uniqueness::{DuplicateEdge, UniquenessIssues};

use fj_math::Scalar;

Expand Down Expand Up @@ -74,7 +70,6 @@ impl Validate for Edge<3> {
_: Scalar,
stores: &Stores,
) -> Result<(), ValidationError> {
structural::validate_edge(self, stores)?;
uniqueness::validate_edge(self, handle, &stores.edges)?;

Ok(())
Expand All @@ -94,9 +89,8 @@ impl Validate for Cycle<3> {
&self,
_: Option<&Handle<Self>>,
_: Scalar,
stores: &Stores,
_: &Stores,
) -> Result<(), ValidationError> {
structural::validate_cycle(self, stores)?;
Ok(())
}
}
Expand All @@ -106,9 +100,8 @@ impl Validate for Face {
&self,
_: Option<&Handle<Self>>,
_: Scalar,
stores: &Stores,
_: &Stores,
) -> Result<(), ValidationError> {
structural::validate_face(self, stores)?;
Ok(())
}
}
Expand Down
147 changes: 138 additions & 9 deletions crates/fj-kernel/src/validation/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,25 +25,55 @@
//! [`Shape`]: crate::shape::Shape
mod coherence;
mod structural;

pub use self::coherence::{CoherenceIssues, CoherenceMismatch};
pub use self::{
coherence::{CoherenceIssues, CoherenceMismatch},
structural::StructuralIssues,
};

use std::ops::Deref;
use std::{collections::HashSet, ops::Deref};

use fj_math::Scalar;

use crate::{
objects::{Curve, Cycle, Edge, Surface, Vertex},
shape::{Handle, Shape, StructuralIssues, UniquenessIssues},
shape::{Handle, Shape, UniquenessIssues},
};

/// Validate the given [`Shape`]
pub fn validate(
shape: Shape,
config: &ValidationConfig,
) -> Result<Validated<Shape>, ValidationError> {
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 shape.curves() {
curves.insert(curve);
}
for vertex in shape.vertices() {
vertices.insert(vertex);
}
for edge in shape.edges() {
coherence::validate_edge(&edge.get(), config.identical_max_distance)?;
structural::validate_edge(&edge.get(), &curves, &vertices)?;

edges.insert(edge);
}
for cycle in shape.cycles() {
structural::validate_cycle(&cycle.get(), &edges)?;

cycles.insert(cycle);
}
for surface in shape.surfaces() {
surfaces.insert(surface);
}
for face in shape.faces() {
structural::validate_face(&face.get(), &cycles, &surfaces)?;
}

Ok(Validated(shape))
Expand Down Expand Up @@ -84,6 +114,7 @@ impl Default for ValidationConfig {
/// Wrapper around an object that indicates the object has been validated
///
/// Returned by implementations of `Validate`.
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)]
pub struct Validated<T>(T);

impl<T> Validated<T> {
Expand Down Expand Up @@ -178,16 +209,16 @@ impl ValidationError {

#[cfg(test)]
mod tests {
use fj_math::Scalar;
use fj_math::{Point, Scalar};

use crate::{
objects::Edge,
objects::{Curve, Cycle, Edge, Face, Surface, Vertex, VerticesOfEdge},
shape::{LocalForm, Shape},
validation::ValidationConfig,
validation::{validate, ValidationConfig},
};

#[test]
fn edge_coherence() -> anyhow::Result<()> {
fn coherence_edge() -> anyhow::Result<()> {
let mut shape = Shape::new();
Edge::builder(&mut shape)
.build_line_segment_from_points([[0., 0., 0.], [1., 0., 0.]])?
Expand All @@ -211,7 +242,7 @@ mod tests {
})
.validate()?;

let result = super::validate(
let result = validate(
shape.clone(),
&ValidationConfig {
identical_max_distance: deviation * 2.,
Expand All @@ -220,7 +251,7 @@ mod tests {
);
assert!(result.is_ok());

let result = super::validate(
let result = validate(
shape,
&ValidationConfig {
identical_max_distance: deviation / 2.,
Expand All @@ -231,4 +262,102 @@ mod tests {

Ok(())
}

#[test]
fn structural_cycle() -> anyhow::Result<()> {
let mut shape = Shape::new();
let mut other = Shape::new();

// Trying to refer to edge that is not from the same shape. Should fail.
let edge = Edge::builder(&mut other)
.build_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::builder(&mut shape)
.build_line_segment_from_points([[0., 0., 0.], [1., 0., 0.]])?;
shape.insert(Cycle::new(vec![edge]))?;

Ok(())
}

#[test]
fn structural_edge() -> anyhow::Result<()> {
let mut shape = Shape::new();
let mut other = Shape::new();

let curve = other.insert(Curve::x_axis())?;
let a = Vertex::builder(&mut other).build_from_point([1., 0., 0.])?;
let b = Vertex::builder(&mut other).build_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.clone()),
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 = shape.insert(Curve::x_axis())?;
let a = Vertex::builder(&mut shape).build_from_point([1., 0., 0.])?;
let b = Vertex::builder(&mut shape).build_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]),
})?;

Ok(())
}

#[test]
fn structural_face() -> anyhow::Result<()> {
let mut shape = Shape::new();
let mut other = Shape::new();

let triangle = [[0., 0.], [1., 0.], [0., 1.]];

let surface = other.insert(Surface::xy_plane())?;
let cycle = Cycle::builder(surface.get(), &mut other)
.build_polygon(triangle)?;

// Nothing has been added to `shape`. Should fail.
shape.insert(Face::new(
surface.clone(),
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 = shape.insert(Surface::xy_plane())?;
let cycle = Cycle::builder(surface.get(), &mut shape)
.build_polygon(triangle)?;

// Everything has been added to `shape` now. Should work!
shape.insert(Face::new(
surface,
vec![cycle],
Vec::new(),
[255, 0, 0, 255],
))?;

Ok(())
}
}
Loading

0 comments on commit 9b27744

Please sign in to comment.