mirror of
https://github.com/hannobraun/Fornjot
synced 2025-10-12 10:58:07 +00:00
Merge pull request #2263 from hannobraun/surface
Fully move surface geometry to geometry layer
This commit is contained in:
commit
839e474875
@ -90,13 +90,18 @@ impl Approx for &Face {
|
|||||||
// would need to provide its own approximation, as the edges that bound
|
// would need to provide its own approximation, as the edges that bound
|
||||||
// it have nothing to do with its curvature.
|
// it have nothing to do with its curvature.
|
||||||
|
|
||||||
let exterior =
|
let exterior = (
|
||||||
(self.region().exterior().deref(), &self.surface().geometry())
|
self.region().exterior().deref(),
|
||||||
.approx_with_cache(tolerance, cache, core);
|
&core.layers.geometry.of_surface(self.surface()),
|
||||||
|
)
|
||||||
|
.approx_with_cache(tolerance, cache, core);
|
||||||
|
|
||||||
let mut interiors = BTreeSet::new();
|
let mut interiors = BTreeSet::new();
|
||||||
for cycle in self.region().interiors() {
|
for cycle in self.region().interiors() {
|
||||||
let cycle = (cycle.deref(), &self.surface().geometry())
|
let cycle = (
|
||||||
|
cycle.deref(),
|
||||||
|
&core.layers.geometry.of_surface(self.surface()),
|
||||||
|
)
|
||||||
.approx_with_cache(tolerance, cache, core);
|
.approx_with_cache(tolerance, cache, core);
|
||||||
interiors.insert(cycle);
|
interiors.insert(cycle);
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,14 @@
|
|||||||
use fj_math::Aabb;
|
use fj_math::Aabb;
|
||||||
|
|
||||||
use crate::objects::Cycle;
|
use crate::{geometry::Geometry, objects::Cycle};
|
||||||
|
|
||||||
impl super::BoundingVolume<2> for Cycle {
|
impl super::BoundingVolume<2> for Cycle {
|
||||||
fn aabb(&self) -> Option<Aabb<2>> {
|
fn aabb(&self, geometry: &Geometry) -> Option<Aabb<2>> {
|
||||||
let mut aabb: Option<Aabb<2>> = None;
|
let mut aabb: Option<Aabb<2>> = None;
|
||||||
|
|
||||||
for edge in self.half_edges() {
|
for edge in self.half_edges() {
|
||||||
let new_aabb = edge.aabb().expect("`Edge` can always compute AABB");
|
let new_aabb =
|
||||||
|
edge.aabb(geometry).expect("`Edge` can always compute AABB");
|
||||||
aabb = Some(aabb.map_or(new_aabb, |aabb| aabb.merged(&new_aabb)));
|
aabb = Some(aabb.map_or(new_aabb, |aabb| aabb.merged(&new_aabb)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,9 +1,12 @@
|
|||||||
use fj_math::{Aabb, Vector};
|
use fj_math::{Aabb, Vector};
|
||||||
|
|
||||||
use crate::{geometry::SurfacePath, objects::HalfEdge};
|
use crate::{
|
||||||
|
geometry::{Geometry, SurfacePath},
|
||||||
|
objects::HalfEdge,
|
||||||
|
};
|
||||||
|
|
||||||
impl super::BoundingVolume<2> for HalfEdge {
|
impl super::BoundingVolume<2> for HalfEdge {
|
||||||
fn aabb(&self) -> Option<Aabb<2>> {
|
fn aabb(&self, _: &Geometry) -> Option<Aabb<2>> {
|
||||||
match self.path() {
|
match self.path() {
|
||||||
SurfacePath::Circle(circle) => {
|
SurfacePath::Circle(circle) => {
|
||||||
// Just calculate the AABB of the whole circle. This is not the
|
// Just calculate the AABB of the whole circle. This is not the
|
||||||
|
@ -1,11 +1,14 @@
|
|||||||
use fj_math::Aabb;
|
use fj_math::Aabb;
|
||||||
|
|
||||||
use crate::{geometry::GlobalPath, objects::Face};
|
use crate::{
|
||||||
|
geometry::{Geometry, GlobalPath},
|
||||||
|
objects::Face,
|
||||||
|
};
|
||||||
|
|
||||||
impl super::BoundingVolume<3> for Face {
|
impl super::BoundingVolume<3> for Face {
|
||||||
fn aabb(&self) -> Option<Aabb<3>> {
|
fn aabb(&self, geometry: &Geometry) -> Option<Aabb<3>> {
|
||||||
self.region().exterior().aabb().map(|aabb2| {
|
self.region().exterior().aabb(geometry).map(|aabb2| {
|
||||||
let surface = self.surface().geometry();
|
let surface = geometry.of_surface(self.surface());
|
||||||
|
|
||||||
match surface.u {
|
match surface.u {
|
||||||
GlobalPath::Circle(circle) => {
|
GlobalPath::Circle(circle) => {
|
||||||
|
@ -8,10 +8,12 @@ mod solid;
|
|||||||
|
|
||||||
use fj_math::Aabb;
|
use fj_math::Aabb;
|
||||||
|
|
||||||
|
use crate::geometry::Geometry;
|
||||||
|
|
||||||
/// Compute a bounding volume for an object
|
/// Compute a bounding volume for an object
|
||||||
pub trait BoundingVolume<const D: usize> {
|
pub trait BoundingVolume<const D: usize> {
|
||||||
/// Compute an axis-aligned bounding box (AABB)
|
/// Compute an axis-aligned bounding box (AABB)
|
||||||
///
|
///
|
||||||
/// Return `None`, if no AABB can be computed (if the object is empty).
|
/// Return `None`, if no AABB can be computed (if the object is empty).
|
||||||
fn aabb(&self) -> Option<Aabb<D>>;
|
fn aabb(&self, geometry: &Geometry) -> Option<Aabb<D>>;
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
use fj_math::Aabb;
|
use fj_math::Aabb;
|
||||||
|
|
||||||
use crate::objects::Shell;
|
use crate::{geometry::Geometry, objects::Shell};
|
||||||
|
|
||||||
impl super::BoundingVolume<3> for Shell {
|
impl super::BoundingVolume<3> for Shell {
|
||||||
fn aabb(&self) -> Option<Aabb<3>> {
|
fn aabb(&self, geometry: &Geometry) -> Option<Aabb<3>> {
|
||||||
let mut aabb: Option<Aabb<3>> = None;
|
let mut aabb: Option<Aabb<3>> = None;
|
||||||
|
|
||||||
for face in self.faces() {
|
for face in self.faces() {
|
||||||
let new_aabb = face.aabb();
|
let new_aabb = face.aabb(geometry);
|
||||||
aabb = aabb.map_or(new_aabb, |aabb| match new_aabb {
|
aabb = aabb.map_or(new_aabb, |aabb| match new_aabb {
|
||||||
Some(new_aabb) => Some(aabb.merged(&new_aabb)),
|
Some(new_aabb) => Some(aabb.merged(&new_aabb)),
|
||||||
None => Some(aabb),
|
None => Some(aabb),
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
use fj_math::Aabb;
|
use fj_math::Aabb;
|
||||||
|
|
||||||
use crate::objects::Solid;
|
use crate::{geometry::Geometry, objects::Solid};
|
||||||
|
|
||||||
impl super::BoundingVolume<3> for Solid {
|
impl super::BoundingVolume<3> for Solid {
|
||||||
fn aabb(&self) -> Option<Aabb<3>> {
|
fn aabb(&self, geometry: &Geometry) -> Option<Aabb<3>> {
|
||||||
let mut aabb: Option<Aabb<3>> = None;
|
let mut aabb: Option<Aabb<3>> = None;
|
||||||
|
|
||||||
for shell in self.shells() {
|
for shell in self.shells() {
|
||||||
let new_aabb = shell.aabb();
|
let new_aabb = shell.aabb(geometry);
|
||||||
aabb = aabb.map_or(new_aabb, |aabb| match new_aabb {
|
aabb = aabb.map_or(new_aabb, |aabb| match new_aabb {
|
||||||
Some(new_aabb) => Some(aabb.merged(&new_aabb)),
|
Some(new_aabb) => Some(aabb.merged(&new_aabb)),
|
||||||
None => Some(aabb),
|
None => Some(aabb),
|
||||||
|
@ -161,12 +161,36 @@ mod tests {
|
|||||||
|
|
||||||
let triangles = triangulate(face, &mut core)?;
|
let triangles = triangulate(face, &mut core)?;
|
||||||
|
|
||||||
let a = surface.geometry().point_from_surface_coords(a);
|
let a = core
|
||||||
let b = surface.geometry().point_from_surface_coords(b);
|
.layers
|
||||||
let e = surface.geometry().point_from_surface_coords(e);
|
.geometry
|
||||||
let f = surface.geometry().point_from_surface_coords(f);
|
.of_surface(&surface)
|
||||||
let g = surface.geometry().point_from_surface_coords(g);
|
.point_from_surface_coords(a);
|
||||||
let h = surface.geometry().point_from_surface_coords(h);
|
let b = core
|
||||||
|
.layers
|
||||||
|
.geometry
|
||||||
|
.of_surface(&surface)
|
||||||
|
.point_from_surface_coords(b);
|
||||||
|
let e = core
|
||||||
|
.layers
|
||||||
|
.geometry
|
||||||
|
.of_surface(&surface)
|
||||||
|
.point_from_surface_coords(e);
|
||||||
|
let f = core
|
||||||
|
.layers
|
||||||
|
.geometry
|
||||||
|
.of_surface(&surface)
|
||||||
|
.point_from_surface_coords(f);
|
||||||
|
let g = core
|
||||||
|
.layers
|
||||||
|
.geometry
|
||||||
|
.of_surface(&surface)
|
||||||
|
.point_from_surface_coords(g);
|
||||||
|
let h = core
|
||||||
|
.layers
|
||||||
|
.geometry
|
||||||
|
.of_surface(&surface)
|
||||||
|
.point_from_surface_coords(h);
|
||||||
|
|
||||||
// Let's test that some correct triangles are present. We don't need to
|
// Let's test that some correct triangles are present. We don't need to
|
||||||
// test them all.
|
// test them all.
|
||||||
@ -224,11 +248,31 @@ mod tests {
|
|||||||
|
|
||||||
let triangles = triangulate(face, &mut core)?;
|
let triangles = triangulate(face, &mut core)?;
|
||||||
|
|
||||||
let a = surface.geometry().point_from_surface_coords(a);
|
let a = core
|
||||||
let b = surface.geometry().point_from_surface_coords(b);
|
.layers
|
||||||
let c = surface.geometry().point_from_surface_coords(c);
|
.geometry
|
||||||
let d = surface.geometry().point_from_surface_coords(d);
|
.of_surface(&surface)
|
||||||
let e = surface.geometry().point_from_surface_coords(e);
|
.point_from_surface_coords(a);
|
||||||
|
let b = core
|
||||||
|
.layers
|
||||||
|
.geometry
|
||||||
|
.of_surface(&surface)
|
||||||
|
.point_from_surface_coords(b);
|
||||||
|
let c = core
|
||||||
|
.layers
|
||||||
|
.geometry
|
||||||
|
.of_surface(&surface)
|
||||||
|
.point_from_surface_coords(c);
|
||||||
|
let d = core
|
||||||
|
.layers
|
||||||
|
.geometry
|
||||||
|
.of_surface(&surface)
|
||||||
|
.point_from_surface_coords(d);
|
||||||
|
let e = core
|
||||||
|
.layers
|
||||||
|
.geometry
|
||||||
|
.of_surface(&surface)
|
||||||
|
.point_from_surface_coords(e);
|
||||||
|
|
||||||
assert!(triangles.contains_triangle([a, b, d]));
|
assert!(triangles.contains_triangle([a, b, d]));
|
||||||
assert!(triangles.contains_triangle([a, d, e]));
|
assert!(triangles.contains_triangle([a, d, e]));
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
//! Layer infrastructure for [`Objects`]
|
//! Layer infrastructure for [`Objects`]
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
geometry::Geometry,
|
||||||
objects::{AboutToBeStored, AnyObject, Objects},
|
objects::{AboutToBeStored, AnyObject, Objects},
|
||||||
validation::Validation,
|
validation::Validation,
|
||||||
};
|
};
|
||||||
@ -14,6 +15,7 @@ impl Layer<Objects> {
|
|||||||
pub fn insert(
|
pub fn insert(
|
||||||
&mut self,
|
&mut self,
|
||||||
object: AnyObject<AboutToBeStored>,
|
object: AnyObject<AboutToBeStored>,
|
||||||
|
geometry: &Geometry,
|
||||||
validation: &mut Layer<Validation>,
|
validation: &mut Layer<Validation>,
|
||||||
) {
|
) {
|
||||||
let mut events = Vec::new();
|
let mut events = Vec::new();
|
||||||
@ -22,6 +24,7 @@ impl Layer<Objects> {
|
|||||||
for event in events {
|
for event in events {
|
||||||
let event = ValidateObject {
|
let event = ValidateObject {
|
||||||
object: event.object.into(),
|
object: event.object.into(),
|
||||||
|
geometry,
|
||||||
};
|
};
|
||||||
validation.process(event, &mut Vec::new());
|
validation.process(event, &mut Vec::new());
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
//! Layer infrastructure for [`Validation`]
|
//! Layer infrastructure for [`Validation`]
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
geometry::Geometry,
|
||||||
objects::{AnyObject, Stored},
|
objects::{AnyObject, Stored},
|
||||||
validation::{Validation, ValidationError, ValidationErrors},
|
validation::{Validation, ValidationError, ValidationErrors},
|
||||||
};
|
};
|
||||||
@ -15,18 +16,22 @@ impl Layer<Validation> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Validate an object
|
/// Validate an object
|
||||||
pub struct ValidateObject {
|
pub struct ValidateObject<'r> {
|
||||||
/// The object to validate
|
/// The object to validate
|
||||||
pub object: AnyObject<Stored>,
|
pub object: AnyObject<Stored>,
|
||||||
|
|
||||||
|
/// Reference to `Geometry`, which is required for validation
|
||||||
|
pub geometry: &'r Geometry,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Command<Validation> for ValidateObject {
|
impl Command<Validation> for ValidateObject<'_> {
|
||||||
type Result = ();
|
type Result = ();
|
||||||
type Event = ValidationFailed;
|
type Event = ValidationFailed;
|
||||||
|
|
||||||
fn decide(self, state: &Validation, events: &mut Vec<Self::Event>) {
|
fn decide(self, state: &Validation, events: &mut Vec<Self::Event>) {
|
||||||
let mut errors = Vec::new();
|
let mut errors = Vec::new();
|
||||||
self.object.validate(&state.config, &mut errors);
|
self.object
|
||||||
|
.validate(&state.config, &mut errors, self.geometry);
|
||||||
|
|
||||||
for err in errors {
|
for err in errors {
|
||||||
events.push(ValidationFailed {
|
events.push(ValidationFailed {
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
|
geometry::Geometry,
|
||||||
objects::{
|
objects::{
|
||||||
Curve, Cycle, Face, HalfEdge, Objects, Region, Shell, Sketch, Solid,
|
Curve, Cycle, Face, HalfEdge, Objects, Region, Shell, Sketch, Solid,
|
||||||
Surface, Vertex,
|
Surface, Vertex,
|
||||||
@ -38,10 +39,15 @@ macro_rules! any_object {
|
|||||||
pub fn validate(&self,
|
pub fn validate(&self,
|
||||||
config: &ValidationConfig,
|
config: &ValidationConfig,
|
||||||
errors: &mut Vec<ValidationError>,
|
errors: &mut Vec<ValidationError>,
|
||||||
|
geometry: &Geometry,
|
||||||
) {
|
) {
|
||||||
match self {
|
match self {
|
||||||
$(
|
$(
|
||||||
Self::$ty(object) => object.validate(config, errors),
|
Self::$ty(object) => object.validate(
|
||||||
|
config,
|
||||||
|
errors,
|
||||||
|
geometry,
|
||||||
|
),
|
||||||
)*
|
)*
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@ use fj_math::Winding;
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
objects::{Region, Surface},
|
objects::{Region, Surface},
|
||||||
storage::Handle,
|
storage::{Handle, HandleWrapper},
|
||||||
};
|
};
|
||||||
|
|
||||||
/// A face of a shape
|
/// A face of a shape
|
||||||
@ -31,14 +31,17 @@ use crate::{
|
|||||||
/// [`Shell`]: crate::objects::Shell
|
/// [`Shell`]: crate::objects::Shell
|
||||||
#[derive(Clone, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)]
|
#[derive(Clone, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)]
|
||||||
pub struct Face {
|
pub struct Face {
|
||||||
surface: Handle<Surface>,
|
surface: HandleWrapper<Surface>,
|
||||||
region: Handle<Region>,
|
region: Handle<Region>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Face {
|
impl Face {
|
||||||
/// Construct an instance of `Face`
|
/// Construct an instance of `Face`
|
||||||
pub fn new(surface: Handle<Surface>, region: Handle<Region>) -> Self {
|
pub fn new(surface: Handle<Surface>, region: Handle<Region>) -> Self {
|
||||||
Self { surface, region }
|
Self {
|
||||||
|
surface: surface.into(),
|
||||||
|
region,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Access the surface of the face
|
/// Access the surface of the face
|
||||||
|
@ -1,19 +1,25 @@
|
|||||||
use crate::geometry::SurfaceGeometry;
|
|
||||||
|
|
||||||
/// A two-dimensional shape
|
/// A two-dimensional shape
|
||||||
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)]
|
///
|
||||||
pub struct Surface {
|
///
|
||||||
geometry: SurfaceGeometry,
|
/// ## Equality
|
||||||
}
|
///
|
||||||
|
/// `Surface` contains no data and exists purely to be referenced via a
|
||||||
|
/// `Handle`, where `Handle::id` can be used to compare different instances of
|
||||||
|
/// it.
|
||||||
|
///
|
||||||
|
/// If `Surface` had `Eq`/`PartialEq` implementations, it containing no data
|
||||||
|
/// would mean that all instances of `Surface` would be considered equal. This
|
||||||
|
/// would be very error-prone.
|
||||||
|
///
|
||||||
|
/// If you need to reference a `Surface` from a struct that needs to derive
|
||||||
|
/// `Eq`/`Ord`/..., you can use `HandleWrapper<Vertex>` to do that. It will
|
||||||
|
/// use `Handle::id` to provide those `Eq`/`Ord`/... implementations.
|
||||||
|
#[derive(Clone, Copy, Debug, Default, Hash)]
|
||||||
|
pub struct Surface {}
|
||||||
|
|
||||||
impl Surface {
|
impl Surface {
|
||||||
/// Construct an instance of `Surface`
|
/// Construct an instance of `Surface`
|
||||||
pub fn new(geometry: SurfaceGeometry) -> Self {
|
pub fn new() -> Self {
|
||||||
Self { geometry }
|
Self::default()
|
||||||
}
|
|
||||||
|
|
||||||
/// Access the surface's geometry
|
|
||||||
pub fn geometry(&self) -> SurfaceGeometry {
|
|
||||||
self.geometry
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -68,7 +68,7 @@
|
|||||||
/// ## Equality
|
/// ## Equality
|
||||||
///
|
///
|
||||||
/// `Vertex` contains no data and exists purely to be referenced via a `Handle`,
|
/// `Vertex` contains no data and exists purely to be referenced via a `Handle`,
|
||||||
/// where `Handle::id` can be used to compare different instances of `Vertex`.
|
/// where `Handle::id` can be used to compare different instances of it.
|
||||||
///
|
///
|
||||||
/// If `Vertex` had `Eq`/`PartialEq` implementations, it containing no data
|
/// If `Vertex` had `Eq`/`PartialEq` implementations, it containing no data
|
||||||
/// would mean that all instances of `Vertex` would be considered equal. This
|
/// would mean that all instances of `Vertex` would be considered equal. This
|
||||||
|
@ -1,9 +1,4 @@
|
|||||||
use fj_math::Vector;
|
use crate::storage::{Handle, Store};
|
||||||
|
|
||||||
use crate::{
|
|
||||||
geometry::{GlobalPath, SurfaceGeometry},
|
|
||||||
storage::{Handle, Store},
|
|
||||||
};
|
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
Curve, Cycle, Face, HalfEdge, Region, Shell, Sketch, Solid, Surface, Vertex,
|
Curve, Cycle, Face, HalfEdge, Region, Shell, Sketch, Solid, Surface, Vertex,
|
||||||
@ -92,30 +87,13 @@ impl Default for Surfaces {
|
|||||||
let mut store: Store<Surface> = Store::new();
|
let mut store: Store<Surface> = Store::new();
|
||||||
|
|
||||||
let xy_plane = store.reserve();
|
let xy_plane = store.reserve();
|
||||||
store.insert(
|
store.insert(xy_plane.clone(), Surface::new());
|
||||||
xy_plane.clone(),
|
|
||||||
Surface::new(SurfaceGeometry {
|
|
||||||
u: GlobalPath::x_axis(),
|
|
||||||
v: Vector::unit_y(),
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
|
|
||||||
let xz_plane = store.reserve();
|
let xz_plane = store.reserve();
|
||||||
store.insert(
|
store.insert(xz_plane.clone(), Surface::new());
|
||||||
xz_plane.clone(),
|
|
||||||
Surface::new(SurfaceGeometry {
|
|
||||||
u: GlobalPath::x_axis(),
|
|
||||||
v: Vector::unit_z(),
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
let yz_plane = store.reserve();
|
let yz_plane = store.reserve();
|
||||||
store.insert(
|
store.insert(yz_plane.clone(), Surface::new());
|
||||||
yz_plane.clone(),
|
|
||||||
Surface::new(SurfaceGeometry {
|
|
||||||
u: GlobalPath::y_axis(),
|
|
||||||
v: Vector::unit_z(),
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
store,
|
store,
|
||||||
|
@ -43,15 +43,15 @@ pub trait BuildSurface {
|
|||||||
v: impl Into<Vector<3>>,
|
v: impl Into<Vector<3>>,
|
||||||
core: &mut Core,
|
core: &mut Core,
|
||||||
) -> Handle<Surface> {
|
) -> Handle<Surface> {
|
||||||
let geometry = SurfaceGeometry {
|
let surface = Surface::new().insert(core);
|
||||||
u: u.into(),
|
|
||||||
v: v.into(),
|
|
||||||
};
|
|
||||||
let surface = Surface::new(geometry).insert(core);
|
|
||||||
|
|
||||||
core.layers
|
core.layers.geometry.define_surface(
|
||||||
.geometry
|
surface.clone(),
|
||||||
.define_surface(surface.clone(), geometry);
|
SurfaceGeometry {
|
||||||
|
u: u.into(),
|
||||||
|
v: v.into(),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
surface
|
surface
|
||||||
}
|
}
|
||||||
|
@ -99,10 +99,9 @@ impl AddHole for Shell {
|
|||||||
|
|
||||||
let path = {
|
let path = {
|
||||||
let point = |location: &HoleLocation| {
|
let point = |location: &HoleLocation| {
|
||||||
location
|
core.layers
|
||||||
.face
|
.geometry
|
||||||
.surface()
|
.of_surface(location.face.surface())
|
||||||
.geometry()
|
|
||||||
.point_from_surface_coords(location.position)
|
.point_from_surface_coords(location.position)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -42,6 +42,7 @@ macro_rules! impl_insert {
|
|||||||
let object = (handle.clone(), self).into();
|
let object = (handle.clone(), self).into();
|
||||||
core.layers.objects.insert(
|
core.layers.objects.insert(
|
||||||
object,
|
object,
|
||||||
|
&core.layers.geometry,
|
||||||
&mut core.layers.validation,
|
&mut core.layers.validation,
|
||||||
);
|
);
|
||||||
handle
|
handle
|
||||||
|
@ -55,7 +55,7 @@ impl SweepRegion for Region {
|
|||||||
|
|
||||||
let top_exterior = sweep_cycle(
|
let top_exterior = sweep_cycle(
|
||||||
self.exterior(),
|
self.exterior(),
|
||||||
&surface.geometry(),
|
&core.layers.geometry.of_surface(surface),
|
||||||
color,
|
color,
|
||||||
&mut faces,
|
&mut faces,
|
||||||
path,
|
path,
|
||||||
@ -69,7 +69,7 @@ impl SweepRegion for Region {
|
|||||||
.map(|bottom_cycle| {
|
.map(|bottom_cycle| {
|
||||||
sweep_cycle(
|
sweep_cycle(
|
||||||
bottom_cycle,
|
bottom_cycle,
|
||||||
&surface.geometry(),
|
&core.layers.geometry.of_surface(surface),
|
||||||
color,
|
color,
|
||||||
&mut faces,
|
&mut faces,
|
||||||
path,
|
path,
|
||||||
|
@ -43,14 +43,14 @@ impl SweepSketch for Sketch {
|
|||||||
assert!(region.exterior().winding().is_ccw());
|
assert!(region.exterior().winding().is_ccw());
|
||||||
|
|
||||||
let is_negative_sweep = {
|
let is_negative_sweep = {
|
||||||
let u = match surface.geometry().u {
|
let u = match core.layers.geometry.of_surface(&surface).u {
|
||||||
GlobalPath::Circle(_) => todo!(
|
GlobalPath::Circle(_) => todo!(
|
||||||
"Sweeping sketch from a rounded surfaces is not \
|
"Sweeping sketch from a rounded surfaces is not \
|
||||||
supported"
|
supported"
|
||||||
),
|
),
|
||||||
GlobalPath::Line(line) => line.direction(),
|
GlobalPath::Line(line) => line.direction(),
|
||||||
};
|
};
|
||||||
let v = surface.geometry().v;
|
let v = core.layers.geometry.of_surface(&surface).v;
|
||||||
|
|
||||||
let normal = u.cross(&v);
|
let normal = u.cross(&v);
|
||||||
|
|
||||||
|
@ -16,9 +16,10 @@ impl TransformObject for Handle<Surface> {
|
|||||||
cache
|
cache
|
||||||
.entry(self)
|
.entry(self)
|
||||||
.or_insert_with(|| {
|
.or_insert_with(|| {
|
||||||
let geometry = self.geometry().transform(transform);
|
let surface = Surface::new().insert(core);
|
||||||
let surface = Surface::new(geometry).insert(core);
|
|
||||||
|
|
||||||
|
let geometry =
|
||||||
|
core.layers.geometry.of_surface(self).transform(transform);
|
||||||
core.layers
|
core.layers
|
||||||
.geometry
|
.geometry
|
||||||
.define_surface(surface.clone(), geometry);
|
.define_surface(surface.clone(), geometry);
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
|
geometry::Geometry,
|
||||||
objects::Curve,
|
objects::Curve,
|
||||||
validation::{ValidationConfig, ValidationError},
|
validation::{ValidationConfig, ValidationError},
|
||||||
};
|
};
|
||||||
@ -6,5 +7,11 @@ use crate::{
|
|||||||
use super::Validate;
|
use super::Validate;
|
||||||
|
|
||||||
impl Validate for Curve {
|
impl Validate for Curve {
|
||||||
fn validate(&self, _: &ValidationConfig, _: &mut Vec<ValidationError>) {}
|
fn validate(
|
||||||
|
&self,
|
||||||
|
_: &ValidationConfig,
|
||||||
|
_: &mut Vec<ValidationError>,
|
||||||
|
_: &Geometry,
|
||||||
|
) {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
|
geometry::Geometry,
|
||||||
objects::Cycle,
|
objects::Cycle,
|
||||||
validation::{
|
validation::{
|
||||||
checks::AdjacentHalfEdgesNotConnected, ValidationCheck,
|
checks::AdjacentHalfEdgesNotConnected, ValidationCheck,
|
||||||
@ -13,6 +14,7 @@ impl Validate for Cycle {
|
|||||||
&self,
|
&self,
|
||||||
config: &ValidationConfig,
|
config: &ValidationConfig,
|
||||||
errors: &mut Vec<ValidationError>,
|
errors: &mut Vec<ValidationError>,
|
||||||
|
_: &Geometry,
|
||||||
) {
|
) {
|
||||||
errors.extend(
|
errors.extend(
|
||||||
AdjacentHalfEdgesNotConnected::check(self, config).map(Into::into),
|
AdjacentHalfEdgesNotConnected::check(self, config).map(Into::into),
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
use fj_math::{Point, Scalar};
|
use fj_math::{Point, Scalar};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
geometry::Geometry,
|
||||||
objects::HalfEdge,
|
objects::HalfEdge,
|
||||||
validation::{ValidationConfig, ValidationError},
|
validation::{ValidationConfig, ValidationError},
|
||||||
};
|
};
|
||||||
@ -12,6 +13,7 @@ impl Validate for HalfEdge {
|
|||||||
&self,
|
&self,
|
||||||
config: &ValidationConfig,
|
config: &ValidationConfig,
|
||||||
errors: &mut Vec<ValidationError>,
|
errors: &mut Vec<ValidationError>,
|
||||||
|
_: &Geometry,
|
||||||
) {
|
) {
|
||||||
EdgeValidationError::check_vertex_coincidence(self, config, errors);
|
EdgeValidationError::check_vertex_coincidence(self, config, errors);
|
||||||
}
|
}
|
||||||
@ -95,8 +97,9 @@ mod tests {
|
|||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
valid.validate_and_return_first_error()?;
|
valid.validate_and_return_first_error(&core.layers.geometry)?;
|
||||||
assert_contains_err!(
|
assert_contains_err!(
|
||||||
|
core,
|
||||||
invalid,
|
invalid,
|
||||||
ValidationError::Edge(
|
ValidationError::Edge(
|
||||||
EdgeValidationError::VerticesAreCoincident { .. }
|
EdgeValidationError::VerticesAreCoincident { .. }
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
use fj_math::Winding;
|
use fj_math::Winding;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
geometry::Geometry,
|
||||||
objects::Face,
|
objects::Face,
|
||||||
validation::{ValidationConfig, ValidationError},
|
validation::{ValidationConfig, ValidationError},
|
||||||
};
|
};
|
||||||
@ -12,6 +13,7 @@ impl Validate for Face {
|
|||||||
&self,
|
&self,
|
||||||
_: &ValidationConfig,
|
_: &ValidationConfig,
|
||||||
errors: &mut Vec<ValidationError>,
|
errors: &mut Vec<ValidationError>,
|
||||||
|
_: &Geometry,
|
||||||
) {
|
) {
|
||||||
FaceValidationError::check_boundary(self, errors);
|
FaceValidationError::check_boundary(self, errors);
|
||||||
FaceValidationError::check_interior_winding(self, errors);
|
FaceValidationError::check_interior_winding(self, errors);
|
||||||
@ -123,8 +125,9 @@ mod tests {
|
|||||||
&mut core,
|
&mut core,
|
||||||
);
|
);
|
||||||
|
|
||||||
valid.validate_and_return_first_error()?;
|
valid.validate_and_return_first_error(&core.layers.geometry)?;
|
||||||
assert_contains_err!(
|
assert_contains_err!(
|
||||||
|
core,
|
||||||
invalid,
|
invalid,
|
||||||
ValidationError::Face(FaceValidationError::MissingBoundary)
|
ValidationError::Face(FaceValidationError::MissingBoundary)
|
||||||
);
|
);
|
||||||
@ -181,8 +184,9 @@ mod tests {
|
|||||||
Face::new(valid.surface().clone(), region)
|
Face::new(valid.surface().clone(), region)
|
||||||
};
|
};
|
||||||
|
|
||||||
valid.validate_and_return_first_error()?;
|
valid.validate_and_return_first_error(&core.layers.geometry)?;
|
||||||
assert_contains_err!(
|
assert_contains_err!(
|
||||||
|
core,
|
||||||
invalid,
|
invalid,
|
||||||
ValidationError::Face(
|
ValidationError::Face(
|
||||||
FaceValidationError::InvalidInteriorWinding { .. }
|
FaceValidationError::InvalidInteriorWinding { .. }
|
||||||
|
@ -73,7 +73,10 @@ mod solid;
|
|||||||
mod surface;
|
mod surface;
|
||||||
mod vertex;
|
mod vertex;
|
||||||
|
|
||||||
use crate::validation::{ValidationConfig, ValidationError};
|
use crate::{
|
||||||
|
geometry::Geometry,
|
||||||
|
validation::{ValidationConfig, ValidationError},
|
||||||
|
};
|
||||||
|
|
||||||
pub use self::{
|
pub use self::{
|
||||||
edge::EdgeValidationError, face::FaceValidationError,
|
edge::EdgeValidationError, face::FaceValidationError,
|
||||||
@ -85,12 +88,13 @@ pub use self::{
|
|||||||
/// pattern. This is preferred to matching on [`Validate::validate_and_return_first_error`], since usually we don't care about the order.
|
/// pattern. This is preferred to matching on [`Validate::validate_and_return_first_error`], since usually we don't care about the order.
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! assert_contains_err {
|
macro_rules! assert_contains_err {
|
||||||
($o:tt,$p:pat) => {
|
($core:expr, $o:expr, $p:pat) => {
|
||||||
assert!({
|
assert!({
|
||||||
let mut errors = Vec::new();
|
let mut errors = Vec::new();
|
||||||
$o.validate(
|
$o.validate(
|
||||||
&$crate::validation::ValidationConfig::default(),
|
&$crate::validation::ValidationConfig::default(),
|
||||||
&mut errors,
|
&mut errors,
|
||||||
|
&$core.layers.geometry,
|
||||||
);
|
);
|
||||||
errors.iter().any(|e| matches!(e, $p))
|
errors.iter().any(|e| matches!(e, $p))
|
||||||
})
|
})
|
||||||
@ -103,9 +107,12 @@ macro_rules! assert_contains_err {
|
|||||||
pub trait Validate: Sized {
|
pub trait Validate: Sized {
|
||||||
/// Validate the object using default config and return on first error
|
/// Validate the object using default config and return on first error
|
||||||
#[allow(clippy::result_large_err)]
|
#[allow(clippy::result_large_err)]
|
||||||
fn validate_and_return_first_error(&self) -> Result<(), ValidationError> {
|
fn validate_and_return_first_error(
|
||||||
|
&self,
|
||||||
|
geometry: &Geometry,
|
||||||
|
) -> Result<(), ValidationError> {
|
||||||
let mut errors = Vec::new();
|
let mut errors = Vec::new();
|
||||||
self.validate(&ValidationConfig::default(), &mut errors);
|
self.validate(&ValidationConfig::default(), &mut errors, geometry);
|
||||||
|
|
||||||
if let Some(err) = errors.into_iter().next() {
|
if let Some(err) = errors.into_iter().next() {
|
||||||
return Err(err);
|
return Err(err);
|
||||||
@ -119,5 +126,6 @@ pub trait Validate: Sized {
|
|||||||
&self,
|
&self,
|
||||||
config: &ValidationConfig,
|
config: &ValidationConfig,
|
||||||
errors: &mut Vec<ValidationError>,
|
errors: &mut Vec<ValidationError>,
|
||||||
|
geometry: &Geometry,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,13 @@
|
|||||||
use crate::objects::Region;
|
use crate::{geometry::Geometry, objects::Region};
|
||||||
|
|
||||||
use super::{Validate, ValidationConfig, ValidationError};
|
use super::{Validate, ValidationConfig, ValidationError};
|
||||||
|
|
||||||
impl Validate for Region {
|
impl Validate for Region {
|
||||||
fn validate(&self, _: &ValidationConfig, _: &mut Vec<ValidationError>) {}
|
fn validate(
|
||||||
|
&self,
|
||||||
|
_: &ValidationConfig,
|
||||||
|
_: &mut Vec<ValidationError>,
|
||||||
|
_: &Geometry,
|
||||||
|
) {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@ use std::{collections::BTreeMap, fmt};
|
|||||||
use fj_math::{Point, Scalar};
|
use fj_math::{Point, Scalar};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
geometry::{CurveBoundary, SurfaceGeometry},
|
geometry::{CurveBoundary, Geometry, SurfaceGeometry},
|
||||||
objects::{Curve, HalfEdge, Shell, Vertex},
|
objects::{Curve, HalfEdge, Shell, Vertex},
|
||||||
queries::{
|
queries::{
|
||||||
AllHalfEdgesWithSurface, BoundingVerticesOfHalfEdge, SiblingOfHalfEdge,
|
AllHalfEdgesWithSurface, BoundingVerticesOfHalfEdge, SiblingOfHalfEdge,
|
||||||
@ -18,10 +18,15 @@ impl Validate for Shell {
|
|||||||
&self,
|
&self,
|
||||||
config: &ValidationConfig,
|
config: &ValidationConfig,
|
||||||
errors: &mut Vec<ValidationError>,
|
errors: &mut Vec<ValidationError>,
|
||||||
|
geometry: &Geometry,
|
||||||
) {
|
) {
|
||||||
ShellValidationError::check_curve_coordinates(self, config, errors);
|
ShellValidationError::check_curve_coordinates(
|
||||||
|
self, geometry, config, errors,
|
||||||
|
);
|
||||||
ShellValidationError::check_half_edge_pairs(self, errors);
|
ShellValidationError::check_half_edge_pairs(self, errors);
|
||||||
ShellValidationError::check_half_edge_coincidence(self, config, errors);
|
ShellValidationError::check_half_edge_coincidence(
|
||||||
|
self, geometry, config, errors,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -75,6 +80,7 @@ impl ShellValidationError {
|
|||||||
/// Check that local curve definitions that refer to the same curve match
|
/// Check that local curve definitions that refer to the same curve match
|
||||||
fn check_curve_coordinates(
|
fn check_curve_coordinates(
|
||||||
shell: &Shell,
|
shell: &Shell,
|
||||||
|
geometry: &Geometry,
|
||||||
config: &ValidationConfig,
|
config: &ValidationConfig,
|
||||||
errors: &mut Vec<ValidationError>,
|
errors: &mut Vec<ValidationError>,
|
||||||
) {
|
) {
|
||||||
@ -139,17 +145,17 @@ impl ShellValidationError {
|
|||||||
|
|
||||||
compare_curve_coords(
|
compare_curve_coords(
|
||||||
edge_a,
|
edge_a,
|
||||||
&surface_a.geometry(),
|
&geometry.of_surface(surface_a),
|
||||||
edge_b,
|
edge_b,
|
||||||
&surface_b.geometry(),
|
&geometry.of_surface(surface_b),
|
||||||
config,
|
config,
|
||||||
&mut mismatches,
|
&mut mismatches,
|
||||||
);
|
);
|
||||||
compare_curve_coords(
|
compare_curve_coords(
|
||||||
edge_b,
|
edge_b,
|
||||||
&surface_b.geometry(),
|
&geometry.of_surface(surface_b),
|
||||||
edge_a,
|
edge_a,
|
||||||
&surface_a.geometry(),
|
&geometry.of_surface(surface_a),
|
||||||
config,
|
config,
|
||||||
&mut mismatches,
|
&mut mismatches,
|
||||||
);
|
);
|
||||||
@ -208,6 +214,7 @@ impl ShellValidationError {
|
|||||||
/// Check that non-sibling half-edges are not coincident
|
/// Check that non-sibling half-edges are not coincident
|
||||||
fn check_half_edge_coincidence(
|
fn check_half_edge_coincidence(
|
||||||
shell: &Shell,
|
shell: &Shell,
|
||||||
|
geometry: &Geometry,
|
||||||
config: &ValidationConfig,
|
config: &ValidationConfig,
|
||||||
errors: &mut Vec<ValidationError>,
|
errors: &mut Vec<ValidationError>,
|
||||||
) {
|
) {
|
||||||
@ -235,9 +242,9 @@ impl ShellValidationError {
|
|||||||
// `distinct_min_distance`, that's a problem.
|
// `distinct_min_distance`, that's a problem.
|
||||||
if distances(
|
if distances(
|
||||||
half_edge_a.clone(),
|
half_edge_a.clone(),
|
||||||
&surface_a.geometry(),
|
&geometry.of_surface(surface_a),
|
||||||
half_edge_b.clone(),
|
half_edge_b.clone(),
|
||||||
&surface_b.geometry(),
|
&geometry.of_surface(surface_b),
|
||||||
)
|
)
|
||||||
.all(|d| d < config.distinct_min_distance)
|
.all(|d| d < config.distinct_min_distance)
|
||||||
{
|
{
|
||||||
@ -441,8 +448,11 @@ mod tests {
|
|||||||
&mut core,
|
&mut core,
|
||||||
);
|
);
|
||||||
|
|
||||||
valid.shell.validate_and_return_first_error()?;
|
valid
|
||||||
|
.shell
|
||||||
|
.validate_and_return_first_error(&core.layers.geometry)?;
|
||||||
assert_contains_err!(
|
assert_contains_err!(
|
||||||
|
core,
|
||||||
invalid,
|
invalid,
|
||||||
ValidationError::Shell(
|
ValidationError::Shell(
|
||||||
ShellValidationError::CurveCoordinateSystemMismatch(..)
|
ShellValidationError::CurveCoordinateSystemMismatch(..)
|
||||||
@ -462,8 +472,11 @@ mod tests {
|
|||||||
);
|
);
|
||||||
let invalid = valid.shell.remove_face(&valid.abc.face);
|
let invalid = valid.shell.remove_face(&valid.abc.face);
|
||||||
|
|
||||||
valid.shell.validate_and_return_first_error()?;
|
valid
|
||||||
|
.shell
|
||||||
|
.validate_and_return_first_error(&core.layers.geometry)?;
|
||||||
assert_contains_err!(
|
assert_contains_err!(
|
||||||
|
core,
|
||||||
invalid,
|
invalid,
|
||||||
ValidationError::Shell(
|
ValidationError::Shell(
|
||||||
ShellValidationError::HalfEdgeHasNoSibling { .. }
|
ShellValidationError::HalfEdgeHasNoSibling { .. }
|
||||||
@ -508,8 +521,11 @@ mod tests {
|
|||||||
&mut core,
|
&mut core,
|
||||||
);
|
);
|
||||||
|
|
||||||
valid.shell.validate_and_return_first_error()?;
|
valid
|
||||||
|
.shell
|
||||||
|
.validate_and_return_first_error(&core.layers.geometry)?;
|
||||||
assert_contains_err!(
|
assert_contains_err!(
|
||||||
|
core,
|
||||||
invalid,
|
invalid,
|
||||||
ValidationError::Shell(
|
ValidationError::Shell(
|
||||||
ShellValidationError::CoincidentHalfEdgesAreNotSiblings { .. }
|
ShellValidationError::CoincidentHalfEdgesAreNotSiblings { .. }
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
use crate::geometry::Geometry;
|
||||||
use crate::{objects::Cycle, storage::Handle};
|
use crate::{objects::Cycle, storage::Handle};
|
||||||
use crate::{objects::Sketch, validate_references};
|
use crate::{objects::Sketch, validate_references};
|
||||||
use fj_math::Winding;
|
use fj_math::Winding;
|
||||||
@ -12,6 +13,7 @@ impl Validate for Sketch {
|
|||||||
&self,
|
&self,
|
||||||
config: &ValidationConfig,
|
config: &ValidationConfig,
|
||||||
errors: &mut Vec<ValidationError>,
|
errors: &mut Vec<ValidationError>,
|
||||||
|
_: &Geometry,
|
||||||
) {
|
) {
|
||||||
SketchValidationError::check_object_references(self, config, errors);
|
SketchValidationError::check_object_references(self, config, errors);
|
||||||
SketchValidationError::check_exterior_cycles(self, config, errors);
|
SketchValidationError::check_exterior_cycles(self, config, errors);
|
||||||
@ -130,7 +132,7 @@ mod tests {
|
|||||||
let region = <Region as BuildRegion>::circle([0., 0.], 1., &mut core)
|
let region = <Region as BuildRegion>::circle([0., 0.], 1., &mut core)
|
||||||
.insert(&mut core);
|
.insert(&mut core);
|
||||||
let valid_sketch = Sketch::new(vec![region.clone()]).insert(&mut core);
|
let valid_sketch = Sketch::new(vec![region.clone()]).insert(&mut core);
|
||||||
valid_sketch.validate_and_return_first_error()?;
|
valid_sketch.validate_and_return_first_error(&core.layers.geometry)?;
|
||||||
|
|
||||||
let shared_cycle = region.exterior();
|
let shared_cycle = region.exterior();
|
||||||
let invalid_sketch = Sketch::new(vec![
|
let invalid_sketch = Sketch::new(vec![
|
||||||
@ -138,6 +140,7 @@ mod tests {
|
|||||||
Region::new(shared_cycle.clone(), vec![]).insert(&mut core),
|
Region::new(shared_cycle.clone(), vec![]).insert(&mut core),
|
||||||
]);
|
]);
|
||||||
assert_contains_err!(
|
assert_contains_err!(
|
||||||
|
core,
|
||||||
invalid_sketch,
|
invalid_sketch,
|
||||||
ValidationError::Sketch(SketchValidationError::MultipleReferences(
|
ValidationError::Sketch(SketchValidationError::MultipleReferences(
|
||||||
ReferenceCountError::Cycle { references: _ }
|
ReferenceCountError::Cycle { references: _ }
|
||||||
@ -157,7 +160,7 @@ mod tests {
|
|||||||
)
|
)
|
||||||
.insert(&mut core);
|
.insert(&mut core);
|
||||||
let valid_sketch = Sketch::new(vec![region.clone()]).insert(&mut core);
|
let valid_sketch = Sketch::new(vec![region.clone()]).insert(&mut core);
|
||||||
valid_sketch.validate_and_return_first_error()?;
|
valid_sketch.validate_and_return_first_error(&core.layers.geometry)?;
|
||||||
|
|
||||||
let exterior = region.exterior();
|
let exterior = region.exterior();
|
||||||
let cloned_edges: Vec<_> =
|
let cloned_edges: Vec<_> =
|
||||||
@ -169,6 +172,7 @@ mod tests {
|
|||||||
Region::new(exterior.clone(), vec![interior]).insert(&mut core)
|
Region::new(exterior.clone(), vec![interior]).insert(&mut core)
|
||||||
]);
|
]);
|
||||||
assert_contains_err!(
|
assert_contains_err!(
|
||||||
|
core,
|
||||||
invalid_sketch,
|
invalid_sketch,
|
||||||
ValidationError::Sketch(SketchValidationError::MultipleReferences(
|
ValidationError::Sketch(SketchValidationError::MultipleReferences(
|
||||||
ReferenceCountError::HalfEdge { references: _ }
|
ReferenceCountError::HalfEdge { references: _ }
|
||||||
@ -190,7 +194,7 @@ mod tests {
|
|||||||
Sketch::new(vec![
|
Sketch::new(vec![
|
||||||
Region::new(valid_exterior.clone(), vec![]).insert(&mut core)
|
Region::new(valid_exterior.clone(), vec![]).insert(&mut core)
|
||||||
]);
|
]);
|
||||||
valid_sketch.validate_and_return_first_error()?;
|
valid_sketch.validate_and_return_first_error(&core.layers.geometry)?;
|
||||||
|
|
||||||
let invalid_outer_circle = HalfEdge::from_sibling(
|
let invalid_outer_circle = HalfEdge::from_sibling(
|
||||||
&valid_outer_circle,
|
&valid_outer_circle,
|
||||||
@ -204,6 +208,7 @@ mod tests {
|
|||||||
Region::new(invalid_exterior.clone(), vec![]).insert(&mut core)
|
Region::new(invalid_exterior.clone(), vec![]).insert(&mut core)
|
||||||
]);
|
]);
|
||||||
assert_contains_err!(
|
assert_contains_err!(
|
||||||
|
core,
|
||||||
invalid_sketch,
|
invalid_sketch,
|
||||||
ValidationError::Sketch(
|
ValidationError::Sketch(
|
||||||
SketchValidationError::ClockwiseExteriorCycle { cycle: _ }
|
SketchValidationError::ClockwiseExteriorCycle { cycle: _ }
|
||||||
@ -235,7 +240,7 @@ mod tests {
|
|||||||
vec![valid_interior],
|
vec![valid_interior],
|
||||||
)
|
)
|
||||||
.insert(&mut core)]);
|
.insert(&mut core)]);
|
||||||
valid_sketch.validate_and_return_first_error()?;
|
valid_sketch.validate_and_return_first_error(&core.layers.geometry)?;
|
||||||
|
|
||||||
let invalid_interior =
|
let invalid_interior =
|
||||||
Cycle::new(vec![inner_circle.clone()]).insert(&mut core);
|
Cycle::new(vec![inner_circle.clone()]).insert(&mut core);
|
||||||
@ -245,6 +250,7 @@ mod tests {
|
|||||||
)
|
)
|
||||||
.insert(&mut core)]);
|
.insert(&mut core)]);
|
||||||
assert_contains_err!(
|
assert_contains_err!(
|
||||||
|
core,
|
||||||
invalid_sketch,
|
invalid_sketch,
|
||||||
ValidationError::Sketch(
|
ValidationError::Sketch(
|
||||||
SketchValidationError::CounterClockwiseInteriorCycle {
|
SketchValidationError::CounterClockwiseInteriorCycle {
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
use std::iter::repeat;
|
use std::iter::repeat;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
geometry::Geometry,
|
||||||
objects::{Solid, Vertex},
|
objects::{Solid, Vertex},
|
||||||
storage::Handle,
|
storage::Handle,
|
||||||
validate_references,
|
validate_references,
|
||||||
@ -17,8 +18,9 @@ impl Validate for Solid {
|
|||||||
&self,
|
&self,
|
||||||
config: &ValidationConfig,
|
config: &ValidationConfig,
|
||||||
errors: &mut Vec<ValidationError>,
|
errors: &mut Vec<ValidationError>,
|
||||||
|
geometry: &Geometry,
|
||||||
) {
|
) {
|
||||||
SolidValidationError::check_vertices(self, config, errors);
|
SolidValidationError::check_vertices(self, geometry, config, errors);
|
||||||
SolidValidationError::check_object_references(self, config, errors);
|
SolidValidationError::check_object_references(self, config, errors);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -74,6 +76,7 @@ pub enum SolidValidationError {
|
|||||||
impl SolidValidationError {
|
impl SolidValidationError {
|
||||||
fn check_vertices(
|
fn check_vertices(
|
||||||
solid: &Solid,
|
solid: &Solid,
|
||||||
|
geometry: &Geometry,
|
||||||
config: &ValidationConfig,
|
config: &ValidationConfig,
|
||||||
errors: &mut Vec<ValidationError>,
|
errors: &mut Vec<ValidationError>,
|
||||||
) {
|
) {
|
||||||
@ -85,7 +88,7 @@ impl SolidValidationError {
|
|||||||
face.region()
|
face.region()
|
||||||
.all_cycles()
|
.all_cycles()
|
||||||
.flat_map(|cycle| cycle.half_edges().iter().cloned())
|
.flat_map(|cycle| cycle.half_edges().iter().cloned())
|
||||||
.zip(repeat(face.surface().geometry()))
|
.zip(repeat(geometry.of_surface(face.surface())))
|
||||||
})
|
})
|
||||||
.map(|(h, s)| {
|
.map(|(h, s)| {
|
||||||
(
|
(
|
||||||
@ -225,6 +228,7 @@ mod tests {
|
|||||||
.insert(&mut core);
|
.insert(&mut core);
|
||||||
|
|
||||||
assert_contains_err!(
|
assert_contains_err!(
|
||||||
|
core,
|
||||||
invalid_solid,
|
invalid_solid,
|
||||||
ValidationError::Solid(SolidValidationError::MultipleReferences(
|
ValidationError::Solid(SolidValidationError::MultipleReferences(
|
||||||
ReferenceCountError::Face { references: _ }
|
ReferenceCountError::Face { references: _ }
|
||||||
@ -232,7 +236,7 @@ mod tests {
|
|||||||
);
|
);
|
||||||
|
|
||||||
let valid_solid = Solid::new(vec![]).insert(&mut core);
|
let valid_solid = Solid::new(vec![]).insert(&mut core);
|
||||||
valid_solid.validate_and_return_first_error()?;
|
valid_solid.validate_and_return_first_error(&core.layers.geometry)?;
|
||||||
|
|
||||||
// Ignore remaining validation errors.
|
// Ignore remaining validation errors.
|
||||||
let _ = core.layers.validation.take_errors();
|
let _ = core.layers.validation.take_errors();
|
||||||
@ -277,6 +281,7 @@ mod tests {
|
|||||||
.insert(&mut core);
|
.insert(&mut core);
|
||||||
|
|
||||||
assert_contains_err!(
|
assert_contains_err!(
|
||||||
|
core,
|
||||||
invalid_solid,
|
invalid_solid,
|
||||||
ValidationError::Solid(SolidValidationError::MultipleReferences(
|
ValidationError::Solid(SolidValidationError::MultipleReferences(
|
||||||
ReferenceCountError::Region { references: _ }
|
ReferenceCountError::Region { references: _ }
|
||||||
@ -284,7 +289,7 @@ mod tests {
|
|||||||
);
|
);
|
||||||
|
|
||||||
let valid_solid = Solid::new(vec![]).insert(&mut core);
|
let valid_solid = Solid::new(vec![]).insert(&mut core);
|
||||||
valid_solid.validate_and_return_first_error()?;
|
valid_solid.validate_and_return_first_error(&core.layers.geometry)?;
|
||||||
|
|
||||||
// Ignore remaining validation errors.
|
// Ignore remaining validation errors.
|
||||||
let _ = core.layers.validation.take_errors();
|
let _ = core.layers.validation.take_errors();
|
||||||
@ -326,6 +331,7 @@ mod tests {
|
|||||||
.insert(&mut core);
|
.insert(&mut core);
|
||||||
|
|
||||||
assert_contains_err!(
|
assert_contains_err!(
|
||||||
|
core,
|
||||||
invalid_solid,
|
invalid_solid,
|
||||||
ValidationError::Solid(SolidValidationError::MultipleReferences(
|
ValidationError::Solid(SolidValidationError::MultipleReferences(
|
||||||
ReferenceCountError::Cycle { references: _ }
|
ReferenceCountError::Cycle { references: _ }
|
||||||
@ -333,7 +339,7 @@ mod tests {
|
|||||||
);
|
);
|
||||||
|
|
||||||
let valid_solid = Solid::new(vec![]).insert(&mut core);
|
let valid_solid = Solid::new(vec![]).insert(&mut core);
|
||||||
valid_solid.validate_and_return_first_error()?;
|
valid_solid.validate_and_return_first_error(&core.layers.geometry)?;
|
||||||
|
|
||||||
// Ignore remaining validation errors.
|
// Ignore remaining validation errors.
|
||||||
let _ = core.layers.validation.take_errors();
|
let _ = core.layers.validation.take_errors();
|
||||||
@ -365,6 +371,7 @@ mod tests {
|
|||||||
.insert(&mut core);
|
.insert(&mut core);
|
||||||
|
|
||||||
assert_contains_err!(
|
assert_contains_err!(
|
||||||
|
core,
|
||||||
invalid_solid,
|
invalid_solid,
|
||||||
ValidationError::Solid(SolidValidationError::MultipleReferences(
|
ValidationError::Solid(SolidValidationError::MultipleReferences(
|
||||||
ReferenceCountError::HalfEdge { references: _ }
|
ReferenceCountError::HalfEdge { references: _ }
|
||||||
@ -372,7 +379,7 @@ mod tests {
|
|||||||
);
|
);
|
||||||
|
|
||||||
let valid_solid = Solid::new(vec![]).insert(&mut core);
|
let valid_solid = Solid::new(vec![]).insert(&mut core);
|
||||||
valid_solid.validate_and_return_first_error()?;
|
valid_solid.validate_and_return_first_error(&core.layers.geometry)?;
|
||||||
|
|
||||||
// Ignore remaining validation errors.
|
// Ignore remaining validation errors.
|
||||||
let _ = core.layers.validation.take_errors();
|
let _ = core.layers.validation.take_errors();
|
||||||
|
@ -1,7 +1,13 @@
|
|||||||
use crate::objects::Surface;
|
use crate::{geometry::Geometry, objects::Surface};
|
||||||
|
|
||||||
use super::{Validate, ValidationConfig, ValidationError};
|
use super::{Validate, ValidationConfig, ValidationError};
|
||||||
|
|
||||||
impl Validate for Surface {
|
impl Validate for Surface {
|
||||||
fn validate(&self, _: &ValidationConfig, _: &mut Vec<ValidationError>) {}
|
fn validate(
|
||||||
|
&self,
|
||||||
|
_: &ValidationConfig,
|
||||||
|
_: &mut Vec<ValidationError>,
|
||||||
|
_: &Geometry,
|
||||||
|
) {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,13 @@
|
|||||||
use crate::objects::Vertex;
|
use crate::{geometry::Geometry, objects::Vertex};
|
||||||
|
|
||||||
use super::{Validate, ValidationConfig, ValidationError};
|
use super::{Validate, ValidationConfig, ValidationError};
|
||||||
|
|
||||||
impl Validate for Vertex {
|
impl Validate for Vertex {
|
||||||
fn validate(&self, _: &ValidationConfig, _: &mut Vec<ValidationError>) {}
|
fn validate(
|
||||||
|
&self,
|
||||||
|
_: &ValidationConfig,
|
||||||
|
_: &mut Vec<ValidationError>,
|
||||||
|
_: &Geometry,
|
||||||
|
) {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -60,7 +60,7 @@ impl Instance {
|
|||||||
self.core.layers.validation.take_errors()?;
|
self.core.layers.validation.take_errors()?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let aabb = model.aabb().unwrap_or(Aabb {
|
let aabb = model.aabb(&self.core.layers.geometry).unwrap_or(Aabb {
|
||||||
min: Point::origin(),
|
min: Point::origin(),
|
||||||
max: Point::origin(),
|
max: Point::origin(),
|
||||||
});
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user