use nalgebra::Point2;
pub(super) struct Triangulation {
pub(super) triangles: Vec<usize>,
pub(super) halfedges: Vec<usize>,
}
impl Triangulation {
#[inline]
pub(super) fn num_tri(&self) -> usize {
self.triangles.len() / 3
}
#[inline]
pub(super) fn next_edge(e: usize) -> usize {
if e % 3 == 2 {
e - 2
} else {
e + 1
}
}
#[inline]
pub(super) fn tri_of(e: usize) -> usize {
e / 3
}
}
#[inline]
fn point_to_f64(p: Point2<f32>) -> delaunator::Point {
delaunator::Point {
x: p.x as f64,
y: p.y as f64,
}
}
#[cfg_attr(
feature = "tracing",
tracing::instrument(
name = "delaunay_triangulate",
level = "debug",
skip_all,
fields(num_points = positions.len()),
)
)]
pub(super) fn triangulate(positions: &[Point2<f32>]) -> Triangulation {
let pts: Vec<delaunator::Point> = positions.iter().copied().map(point_to_f64).collect();
let t = delaunator::triangulate(&pts);
Triangulation {
triangles: t.triangles,
halfedges: t.halfedges,
}
}
#[cfg(test)]
mod tests {
use super::*;
fn pt(x: f32, y: f32) -> Point2<f32> {
Point2::new(x, y)
}
#[test]
fn triangulates_square() {
let positions = vec![pt(0.0, 0.0), pt(1.0, 0.0), pt(1.0, 1.0), pt(0.0, 1.0)];
let t = triangulate(&positions);
assert_eq!(t.num_tri(), 2);
for (e, &buddy) in t.halfedges.iter().enumerate() {
if buddy != delaunator::EMPTY {
assert_eq!(t.halfedges[buddy], e);
}
}
}
#[test]
fn next_edge_walks_triangle() {
assert_eq!(Triangulation::next_edge(0), 1);
assert_eq!(Triangulation::next_edge(1), 2);
assert_eq!(Triangulation::next_edge(2), 0);
assert_eq!(Triangulation::next_edge(3), 4);
assert_eq!(Triangulation::next_edge(5), 3);
assert_eq!(Triangulation::tri_of(2), 0);
assert_eq!(Triangulation::tri_of(5), 1);
}
}