Skip to content

Commit

Permalink
Merge pull request #1058 from hannobraun/approx
Browse files Browse the repository at this point in the history
Validate approximations before using them for triangulation
  • Loading branch information
hannobraun authored Sep 8, 2022
2 parents e152d3e + f28c7c0 commit a96f0cf
Show file tree
Hide file tree
Showing 8 changed files with 138 additions and 97 deletions.
50 changes: 49 additions & 1 deletion crates/fj-kernel/src/algorithms/approx/face.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,58 @@ use std::collections::BTreeSet;

use fj_interop::mesh::Color;

use crate::objects::Face;
use crate::{
algorithms::validate::ValidationConfig,
objects::{Face, Faces},
};

use super::{cycle::CycleApprox, Approx, ApproxPoint, Tolerance};

impl Approx for &Faces {
type Approximation = BTreeSet<FaceApprox>;

fn approx(self, tolerance: Tolerance) -> Self::Approximation {
let approx = self
.into_iter()
.map(|face| face.approx(tolerance))
.collect();

let min_distance = ValidationConfig::default().distinct_min_distance;
let mut all_points: BTreeSet<ApproxPoint<2>> = BTreeSet::new();

for approx in &approx {
let approx: &FaceApprox = approx;

for point in &approx.points() {
for p in &all_points {
let distance =
(p.global_form - point.global_form).magnitude();

if p.global_form != point.global_form
&& distance < min_distance
{
let a = p;
let b = point;

panic!(
"Invalid approximation: \
Distinct points are too close \
(a: {:?}, b: {:?}, distance: {distance})\n\
source of `a`: {:#?}\n\
source of `b`: {:#?}\n",
a.global_form, b.global_form, a.source, b.source
);
}
}

all_points.insert(point.clone());
}
}

approx
}
}

impl Approx for &Face {
type Approximation = FaceApprox;

Expand Down
3 changes: 3 additions & 0 deletions crates/fj-kernel/src/algorithms/approx/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ pub mod curve;
pub mod cycle;
pub mod edge;
pub mod face;
pub mod shell;
pub mod sketch;
pub mod solid;
pub mod tolerance;

use std::{
Expand Down
15 changes: 15 additions & 0 deletions crates/fj-kernel/src/algorithms/approx/shell.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
//! Shell approximation
use std::collections::BTreeSet;

use crate::objects::Shell;

use super::{face::FaceApprox, Approx, Tolerance};

impl Approx for &Shell {
type Approximation = BTreeSet<FaceApprox>;

fn approx(self, tolerance: Tolerance) -> Self::Approximation {
self.faces().approx(tolerance)
}
}
15 changes: 15 additions & 0 deletions crates/fj-kernel/src/algorithms/approx/sketch.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
//! Sketch approximation
use std::collections::BTreeSet;

use crate::objects::Sketch;

use super::{face::FaceApprox, Approx, Tolerance};

impl Approx for &Sketch {
type Approximation = BTreeSet<FaceApprox>;

fn approx(self, tolerance: Tolerance) -> Self::Approximation {
self.faces().approx(tolerance)
}
}
17 changes: 17 additions & 0 deletions crates/fj-kernel/src/algorithms/approx/solid.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
//! Solid approximation
use std::collections::BTreeSet;

use crate::objects::Solid;

use super::{face::FaceApprox, Approx, Tolerance};

impl Approx for &Solid {
type Approximation = BTreeSet<FaceApprox>;

fn approx(self, tolerance: Tolerance) -> Self::Approximation {
self.shells()
.flat_map(|shell| shell.approx(tolerance))
.collect()
}
}
57 changes: 21 additions & 36 deletions crates/fj-kernel/src/algorithms/triangulate/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,19 @@
mod delaunay;
mod polygon;

use fj_interop::{debug::DebugInfo, mesh::Mesh};
use fj_interop::mesh::Mesh;
use fj_math::Point;

use crate::objects::Face;

use self::{delaunay::TriangulationPoint, polygon::Polygon};

use super::approx::{Approx, Tolerance};
use super::approx::{face::FaceApprox, Approx, Tolerance};

/// Triangulate a shape
pub trait Triangulate: Sized {
/// Triangulate the shape
fn triangulate(
self,
tolerance: impl Into<Tolerance>,
debug_info: &mut DebugInfo,
) -> Mesh<Point<3>> {
fn triangulate(self, tolerance: impl Into<Tolerance>) -> Mesh<Point<3>> {
let mut mesh = Mesh::new();
self.triangulate_into_mesh(tolerance, &mut mesh, debug_info);
self.triangulate_into_mesh(tolerance, &mut mesh);
mesh
}

Expand All @@ -33,80 +27,73 @@ pub trait Triangulate: Sized {
self,
tolerance: impl Into<Tolerance>,
mesh: &mut Mesh<Point<3>>,
debug_info: &mut DebugInfo,
);
}

impl<T> Triangulate for T
where
T: IntoIterator<Item = Face>,
T: Approx,
T::Approximation: IntoIterator<Item = FaceApprox>,
{
fn triangulate_into_mesh(
self,
tolerance: impl Into<Tolerance>,
mesh: &mut Mesh<Point<3>>,
debug_info: &mut DebugInfo,
) {
let tolerance = tolerance.into();
let approx = self.approx(tolerance);

for face in self {
face.triangulate_into_mesh(tolerance, mesh, debug_info);
for approx in approx {
approx.triangulate_into_mesh(tolerance, mesh);
}
}
}

impl Triangulate for Face {
impl Triangulate for FaceApprox {
fn triangulate_into_mesh(
self,
tolerance: impl Into<Tolerance>,
_: impl Into<Tolerance>,
mesh: &mut Mesh<Point<3>>,
debug_info: &mut DebugInfo,
) {
let surface = self.surface();
let approx = self.approx(tolerance.into());

let points: Vec<_> = approx
let points: Vec<_> = self
.points()
.into_iter()
.map(|point| TriangulationPoint {
point_surface: point.local_form,
point_global: point.global_form,
})
.collect();
let face_as_polygon = Polygon::new(*surface)
let face_as_polygon = Polygon::new()
.with_exterior(
approx
.exterior
self.exterior
.points()
.into_iter()
.map(|point| point.local_form),
)
.with_interiors(approx.interiors.into_iter().map(|interior| {
.with_interiors(self.interiors.into_iter().map(|interior| {
interior.points().into_iter().map(|point| point.local_form)
}));

let mut triangles = delaunay::triangulate(points);
triangles.retain(|triangle| {
face_as_polygon.contains_triangle(
triangle.map(|point| point.point_surface),
debug_info,
)
face_as_polygon
.contains_triangle(triangle.map(|point| point.point_surface))
});

for triangle in triangles {
let points = triangle.map(|point| point.point_global);
mesh.push_triangle(points, self.color());
mesh.push_triangle(points, self.color);
}
}
}

#[cfg(test)]
mod tests {
use fj_interop::{debug::DebugInfo, mesh::Mesh};
use fj_interop::mesh::Mesh;
use fj_math::{Point, Scalar};

use crate::{
algorithms::approx::Tolerance,
algorithms::approx::{Approx, Tolerance},
objects::{Face, Surface},
};

Expand Down Expand Up @@ -221,8 +208,6 @@ mod tests {

fn triangulate(face: impl Into<Face>) -> anyhow::Result<Mesh<Point<3>>> {
let tolerance = Tolerance::from_scalar(Scalar::ONE)?;

let mut debug_info = DebugInfo::new();
Ok(vec![face.into()].triangulate(tolerance, &mut debug_info))
Ok(face.into().approx(tolerance).triangulate(tolerance))
}
}
Loading

0 comments on commit a96f0cf

Please sign in to comment.