i_triangle 0.44.0

Polygon Triangulation Library: Efficient Delaunay Triangulation for Complex Shapes.
Documentation
use alloc::vec::Vec;
use i_overlay::i_float::float::compatible::FloatPointCompatible;
use i_overlay::i_float::float::number::FloatNumber;
use i_overlay::{i_float::adapter::FloatPointAdapter, i_shape::float::adapter::PathToInt};

use crate::int::locator::IntPointInTriangulationLocator;
use crate::{
    float::triangulation::Triangulation, int::triangulation::IndexType,
    location::PointLocationInTriangulation,
};

pub trait PointInTriangulationLocator<P> {
    fn locate_points<T>(&self, points: &[P]) -> Vec<PointLocationInTriangulation>
    where
        P: FloatPointCompatible<Scalar = T>,
        T: FloatNumber;
}

impl<P, I: IndexType> Triangulation<P, I> {
    pub fn locate_points<T: FloatNumber>(&self, points: &[P]) -> Vec<PointLocationInTriangulation>
    where
        P: FloatPointCompatible<Scalar = T>,
    {
        let adapter = FloatPointAdapter::with_iter(self.points.iter().chain(points.iter()));

        let int_points = points.to_int(&adapter);

        let triangles = self.indices.chunks_exact(3).map(|triangle| {
            let a = adapter.float_to_int(&self.points[triangle[0].into_usize()]);
            let b = adapter.float_to_int(&self.points[triangle[1].into_usize()]);
            let c = adapter.float_to_int(&self.points[triangle[2].into_usize()]);
            [a, b, c]
        });

        triangles.locate_points(&int_points)
    }
}

impl<P, I: IndexType> PointInTriangulationLocator<P> for Triangulation<P, I> {
    #[inline]
    fn locate_points<T>(&self, points: &[P]) -> Vec<PointLocationInTriangulation>
    where
        P: FloatPointCompatible<Scalar = T>,
        T: FloatNumber,
    {
        Triangulation::locate_points::<T>(self, points)
    }
}

#[cfg(test)]
mod tests {
    use alloc::vec;

    use crate::{
        float::triangulation::Triangulation,
        location::{PointLocationInTriangulation, TriangleIndex},
    };

    fn square_triangulation() -> Triangulation<[f64; 2], u16> {
        Triangulation {
            points: vec![[0.0, 0.0], [4.0, 0.0], [4.0, 4.0], [0.0, 4.0]],
            indices: vec![0, 1, 2, 0, 2, 3],
        }
    }

    #[test]
    fn test_locate_points() {
        let triangulation = square_triangulation();
        let points_to_locate = vec![
            [3.0, 1.0],
            [1.0, 3.0],
            [2.0, 2.0],
            [2.0, 0.0],
            [0.0, 0.0],
            [5.0, 1.0],
        ];

        let locations = triangulation.locate_points::<f64>(&points_to_locate);

        assert!(matches!(
            locations[0],
            PointLocationInTriangulation::InsideTriangle(t) if t == TriangleIndex::new(0)
        ));
        assert!(matches!(
            locations[1],
            PointLocationInTriangulation::InsideTriangle(t) if t == TriangleIndex::new(1)
        ));
        assert!(matches!(
            locations[2],
            PointLocationInTriangulation::OnInteriorEdge(a, b)
                if a == TriangleIndex::new(0) && b == TriangleIndex::new(1)
        ));
        assert!(matches!(
            locations[3],
            PointLocationInTriangulation::OnExteriorEdge(t)
                if t == TriangleIndex::new(0)
        ));
        assert!(matches!(
            &locations[4],
            PointLocationInTriangulation::OnVertex(triangles)
                if triangles.as_slice() == [TriangleIndex::new(0), TriangleIndex::new(1)]
        ));
        assert!(matches!(
            locations[5],
            PointLocationInTriangulation::Outside
        ));
    }
}