Skip to content

Commit

Permalink
fix: don’t crash mesh/mesh intersection if some mesh coordinates are …
Browse files Browse the repository at this point in the history
…small denormal numbers (dimforge#214)
  • Loading branch information
sebcrozet authored Jun 27, 2024
1 parent 029429e commit a50d6e2
Show file tree
Hide file tree
Showing 4 changed files with 53 additions and 5 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Change Log

## Unreleased

### Fix

- Fix occasional crash in mesh/mesh intersection if some of the vertex coordinates are very small.

## v0.16.0

### Fix
Expand Down
22 changes: 17 additions & 5 deletions src/transformation/mesh_intersection/mesh_intersection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use super::{MeshIntersectionError, TriangleTriangleIntersection, EPS};
use crate::math::{Isometry, Point, Real, Vector};
use crate::query::{visitors::BoundingVolumeIntersectionsSimultaneousVisitor, PointQuery};
use crate::shape::{FeatureId, TriMesh, Triangle};
use crate::utils::WBasis;
use crate::utils::{self, WBasis};
use na::{Point2, Vector2};
use spade::{handles::FixedVertexHandle, ConstrainedDelaunayTriangulation, Triangulation as _};
use std::collections::{HashMap, HashSet};
Expand Down Expand Up @@ -297,13 +297,22 @@ impl Triangulation {

let vtx_handles = [
delaunay
.insert(spade::Point2::new(ref_proj[0].x, ref_proj[0].y))
.insert(utils::sanitize_point(spade::Point2::new(
ref_proj[0].x,
ref_proj[0].y,
)))
.unwrap(),
delaunay
.insert(spade::Point2::new(ref_proj[1].x, ref_proj[1].y))
.insert(utils::sanitize_point(spade::Point2::new(
ref_proj[1].x,
ref_proj[1].y,
)))
.unwrap(),
delaunay
.insert(spade::Point2::new(ref_proj[2].x, ref_proj[2].y))
.insert(utils::sanitize_point(spade::Point2::new(
ref_proj[2].x,
ref_proj[2].y,
)))
.unwrap(),
];

Expand Down Expand Up @@ -401,7 +410,10 @@ fn cut_and_triangulate_intersections(
.entry(spade_key)
.or_insert_with(|| {
let point2d = triangulations[i].project(pt[i], orig_fid[i]);
let handle = triangulations[i].delaunay.insert(point2d).unwrap();
let handle = triangulations[i]
.delaunay
.insert(utils::sanitize_point(point2d))
.unwrap();
let _ =
spade_handle_to_intersection[i].insert((tri_ids[i], handle), key);
SpadeInfo { handle }
Expand Down
4 changes: 4 additions & 0 deletions src/utils/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ pub use self::segments_intersection::{segments_intersection2d, SegmentsIntersect
pub(crate) use self::sort::sort2;
pub(crate) use self::sort::sort3;
pub use self::sorted_pair::SortedPair;
#[cfg(all(feature = "dim3", feature = "std"))]
pub(crate) use self::spade::sanitize_point;
pub(crate) use self::weighted_value::WeightedValue;
pub(crate) use self::wops::{simd_swap, WBasis, WCross, WSign};

Expand Down Expand Up @@ -59,5 +61,7 @@ mod sdp_matrix;
mod segments_intersection;
mod sort;
mod sorted_pair;
#[cfg(all(feature = "dim3", feature = "std"))]
mod spade;
mod weighted_value;
mod wops;
26 changes: 26 additions & 0 deletions src/utils/spade.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
use crate::math::Real;

/// Ensures the given coordinate doesn’t go out of the bounds of spade’s acceptable values.
///
/// Returns 0.0 if the coordinate is smaller than `spade::MIN_ALLOWED_VALUE`.
/// Returns `spade::MAX_ALLOWED_VALUE` the coordinate is larger than `spade::MAX_ALLOWED_VALUE`.
pub fn sanitize_coord(coord: Real) -> Real {
let abs = coord.abs();

#[allow(clippy::unnecessary_cast)]
if abs as f64 <= spade::MIN_ALLOWED_VALUE {
return 0.0;
}

#[cfg(feature = "f64")]
if abs > spade::MAX_ALLOWED_VALUE {
// This cannot happen in f32 since the max is 3.40282347E+38.
return spade::MAX_ALLOWED_VALUE * coord.signum();
}

coord
}

pub fn sanitize_point(point: spade::Point2<Real>) -> spade::Point2<Real> {
spade::Point2::new(sanitize_coord(point.x), sanitize_coord(point.y))
}

0 comments on commit a50d6e2

Please sign in to comment.