aboutsummaryrefslogtreecommitdiff
path: root/src/math/polygon/triangulate.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/math/polygon/triangulate.rs')
-rw-r--r--src/math/polygon/triangulate.rs59
1 files changed, 34 insertions, 25 deletions
diff --git a/src/math/polygon/triangulate.rs b/src/math/polygon/triangulate.rs
index 8a18cd7..4106095 100644
--- a/src/math/polygon/triangulate.rs
+++ b/src/math/polygon/triangulate.rs
@@ -2,7 +2,8 @@
use super::Polygon;
use crate::math::{self, LineSegment, Surface, Triangle};
-use nalgebra::{RealField, Scalar};
+use float_cmp::ApproxEq;
+use nalgebra::RealField;
/// Type that saves the flags that match a corner in a space efficient manner.
type Flags = u8;
@@ -16,9 +17,10 @@ const FLAG_EAR: Flags = 0b0000_0001;
// used. Consider removing it entirely.
const FLAG_CONVEX: Flags = 0b0000_0010;
-fn flag_corner<T: Scalar + Copy>(polygon: &Polygon<T>, corner: usize) -> Flags
+fn flag_corner<T: RealField, M>(polygon: &Polygon<T>, corner: usize, margin: M) -> Flags
where
- T: RealField,
+ T: ApproxEq<Margin = M>,
+ M: Copy,
{
// First, check if it is convex. If it is not, it can also not be an ear.
let prev = (corner + polygon.corners.len() - 1) % polygon.corners.len();
@@ -31,6 +33,7 @@ where
polygon.corners[prev],
polygon.corners[corner],
polygon.corners[next],
+ margin,
) < T::pi()
{
// The corner is reflex.
@@ -38,10 +41,10 @@ where
}
// The corner is convex, check if it is also an ear.
- if polygon.contains_line_segment(&LineSegment::new(
- polygon.corners[prev],
- polygon.corners[next],
- )) {
+ if polygon.contains_line_segment(
+ &LineSegment::new(polygon.corners[prev], polygon.corners[next]),
+ margin,
+ ) {
// Corner is an ear.
FLAG_EAR | FLAG_CONVEX
} else {
@@ -50,13 +53,14 @@ where
}
}
-/// Uses earclipping algorithm (see https://www.geometrictools.com/Documentation/TriangulationByEarClipping.pdf)
+/// Uses earclipping algorithm (see <https://www.geometrictools.com/Documentation/TriangulationByEarClipping.pdf>)
/// to find an explanation of what exactly is happening.
/// Currently only handles simple polygons, but once the polygon struct supports holes must be
/// extended to also support those.
-pub fn triangulate<T: Scalar + Copy>(mut polygon: Polygon<T>) -> Vec<Triangle<T>>
+pub fn triangulate<T: RealField, M>(mut polygon: Polygon<T>, margin: M) -> Vec<Triangle<T>>
where
- T: RealField,
+ T: ApproxEq<Margin = M>,
+ M: Copy,
{
assert!(polygon.corners.len() >= 3);
/* Information about the corner of the polygon. See the flags constant for information about
@@ -64,7 +68,7 @@ where
*/
let mut flags = Vec::with_capacity(polygon.corners.len());
for c in 0..polygon.corners.len() {
- flags.push(flag_corner(&polygon, c));
+ flags.push(flag_corner(&polygon, c, margin));
}
let mut triangles = Vec::with_capacity(polygon.corners.len() - 2);
@@ -91,6 +95,7 @@ where
polygon.corners[prev],
polygon.corners[ear],
polygon.corners[next],
+ margin,
));
// Remove the ear from the polygon and the flag list.
@@ -107,8 +112,8 @@ where
};
let next = if ear == polygon.corners.len() { 0 } else { ear };
- flags[prev] = flag_corner(&polygon, prev);
- flags[next] = flag_corner(&polygon, next);
+ flags[prev] = flag_corner(&polygon, prev, margin);
+ flags[next] = flag_corner(&polygon, next, margin);
}
// Push the remaining triangle into the list.
@@ -116,6 +121,7 @@ where
polygon.corners[0],
polygon.corners[1],
polygon.corners[2],
+ margin,
));
triangles
@@ -128,18 +134,21 @@ mod test {
#[test]
fn triangulate() {
- let polygon = Polygon::new(vec![
- Vec2::new(0., 0.),
- Vec2::new(0., 4.5),
- Vec2::new(6.5, 4.5),
- Vec2::new(5.5, 0.),
- Vec2::new(5.5, 3.),
- Vec2::new(1.5, 3.),
- Vec2::new(1.5, 1.),
- Vec2::new(2., 0.5),
- Vec2::new(4., 2.),
- Vec2::new(4., 0.),
- ])
+ let polygon = Polygon::new(
+ vec![
+ Vec2::new(0., 0.),
+ Vec2::new(0., 4.5),
+ Vec2::new(6.5, 4.5),
+ Vec2::new(5.5, 0.),
+ Vec2::new(5.5, 3.),
+ Vec2::new(1.5, 3.),
+ Vec2::new(1.5, 1.),
+ Vec2::new(2., 0.5),
+ Vec2::new(4., 2.),
+ Vec2::new(4., 0.),
+ ],
+ (f64::EPSILON, 0),
+ )
.unwrap();
let triangles = super::triangulate(polygon);