diff --git a/iTriangle/src/float/locator.rs b/iTriangle/src/float/locator.rs
new file mode 100644
index 0000000..d44037c
--- /dev/null
+++ b/iTriangle/src/float/locator.rs
@@ -0,0 +1,104 @@
+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::{
+ float::triangulation::Triangulation,
+ int::triangulation::{IndexType, IntTriangulation},
+ location::PointLocationInTriangulation,
+};
+
+pub trait PointInTriangulationLocator
{
+ fn locate_points(&self, points: &[P]) -> Vec
+ where
+ P: FloatPointCompatible,
+ T: FloatNumber;
+}
+
+impl Triangulation
{
+ pub fn locate_points(&self, points: &[P]) -> Vec
+ where
+ P: FloatPointCompatible,
+ {
+ let adapter = FloatPointAdapter::with_iter(self.points.iter().chain(points.iter()));
+
+ let int_triangulation = IntTriangulation {
+ points: self.points.to_int(&adapter),
+ indices: self.indices.clone(),
+ };
+
+ int_triangulation.locate_points(&points.to_int(&adapter))
+ }
+}
+
+impl PointInTriangulationLocator
for Triangulation
{
+ #[inline]
+ fn locate_points(&self, points: &[P]) -> Vec
+ where
+ P: FloatPointCompatible,
+ T: FloatNumber,
+ {
+ Triangulation::locate_points::(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::(&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
+ ));
+ }
+}
diff --git a/iTriangle/src/float/mod.rs b/iTriangle/src/float/mod.rs
index 87f2935..b601b5a 100644
--- a/iTriangle/src/float/mod.rs
+++ b/iTriangle/src/float/mod.rs
@@ -4,6 +4,7 @@ pub mod circumcenter;
pub mod convex;
pub mod custom;
pub mod delaunay;
+pub mod locator;
pub mod triangulatable;
pub mod triangulation;
pub mod triangulator;
diff --git a/iTriangle/src/int/locator.rs b/iTriangle/src/int/locator.rs
new file mode 100644
index 0000000..9e1c16f
--- /dev/null
+++ b/iTriangle/src/int/locator.rs
@@ -0,0 +1,149 @@
+use alloc::vec;
+use alloc::vec::Vec;
+use i_overlay::i_float::triangle::Triangle;
+use i_overlay::i_shape::int::IntPoint;
+
+use crate::{
+ int::triangulation::{IndexType, IntTriangulation},
+ location::{PointLocationInTriangulation, TriangleIndex},
+};
+
+pub trait IntPointInTriangulationLocator {
+ fn locate_points(&self, points: &[IntPoint]) -> Vec;
+}
+
+impl IntTriangulation {
+ pub fn locate_points(&self, points: &[IntPoint]) -> Vec {
+ let mut result = vec![PointLocationInTriangulation::Outside; points.len()];
+
+ for (index, triangle) in self.indices.chunks_exact(3).enumerate() {
+ let vertex0 = self.points[triangle[0].into_usize()];
+ let vertex1 = self.points[triangle[1].into_usize()];
+ let vertex2 = self.points[triangle[2].into_usize()];
+ let triangle_index = TriangleIndex::new(index);
+
+ for (point_index, &point) in points.iter().enumerate() {
+ if point == vertex0 || point == vertex1 || point == vertex2 {
+ match &mut result[point_index] {
+ PointLocationInTriangulation::Outside => {
+ result[point_index] =
+ PointLocationInTriangulation::OnVertex(vec![triangle_index]);
+ }
+ PointLocationInTriangulation::OnVertex(hits) => {
+ hits.push(triangle_index);
+ }
+ // Shouldn't happen.
+ _ => {}
+ }
+
+ continue;
+ }
+
+ if !Triangle::is_contain_point(point, vertex0, vertex1, vertex2) {
+ continue;
+ }
+
+ if Triangle::is_contain_point_exclude_borders(point, vertex0, vertex1, vertex2) {
+ match &result[point_index] {
+ PointLocationInTriangulation::Outside => {
+ result[point_index] =
+ PointLocationInTriangulation::InsideTriangle(triangle_index);
+ }
+ // Shouldn't happen.
+ _ => {}
+ }
+
+ continue;
+ }
+
+ match &result[point_index] {
+ PointLocationInTriangulation::Outside => {
+ result[point_index] =
+ PointLocationInTriangulation::OnExteriorEdge(triangle_index);
+ }
+ PointLocationInTriangulation::OnExteriorEdge(i) => {
+ result[point_index] =
+ PointLocationInTriangulation::OnInteriorEdge(*i, triangle_index);
+ }
+ // Shouldn't happen.
+ _ => {}
+ }
+ }
+ }
+
+ result
+ }
+}
+
+impl IntPointInTriangulationLocator for IntTriangulation {
+ #[inline]
+ fn locate_points(&self, points: &[IntPoint]) -> Vec {
+ IntTriangulation::locate_points(self, points)
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use alloc::vec;
+ use i_overlay::i_shape::int::IntPoint;
+
+ use crate::{
+ int::triangulation::IntTriangulation,
+ location::{PointLocationInTriangulation, TriangleIndex},
+ };
+
+ fn square_triangulation() -> IntTriangulation {
+ IntTriangulation {
+ points: vec![
+ IntPoint::new(0, 0),
+ IntPoint::new(4, 0),
+ IntPoint::new(4, 4),
+ IntPoint::new(0, 4),
+ ],
+ indices: vec![0, 1, 2, 0, 2, 3],
+ }
+ }
+
+ #[test]
+ fn test_locate_points() {
+ let triangulation = square_triangulation();
+ let points_to_locate = vec![
+ IntPoint::new(3, 1),
+ IntPoint::new(1, 3),
+ IntPoint::new(2, 2),
+ IntPoint::new(2, 0),
+ IntPoint::new(0, 0),
+ IntPoint::new(5, 1),
+ ];
+
+ let locations = triangulation.locate_points(&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].clone(),
+ PointLocationInTriangulation::OnVertex(triangles)
+ if triangles.as_slice() == [TriangleIndex::new(0), TriangleIndex::new(1)]
+ ));
+ assert!(matches!(
+ locations[5],
+ PointLocationInTriangulation::Outside
+ ));
+ }
+}
diff --git a/iTriangle/src/int/mod.rs b/iTriangle/src/int/mod.rs
index 68038d6..fd64741 100644
--- a/iTriangle/src/int/mod.rs
+++ b/iTriangle/src/int/mod.rs
@@ -1,6 +1,7 @@
mod binder;
pub mod custom;
pub mod earcut;
+pub mod locator;
mod meta;
pub(crate) mod monotone;
mod solver;
diff --git a/iTriangle/src/lib.rs b/iTriangle/src/lib.rs
index f318f6c..8bb0e90 100644
--- a/iTriangle/src/lib.rs
+++ b/iTriangle/src/lib.rs
@@ -6,6 +6,7 @@ pub mod float;
pub mod geom;
mod index;
pub mod int;
+pub mod location;
pub mod tessellation;
pub use i_overlay;
diff --git a/iTriangle/src/location.rs b/iTriangle/src/location.rs
new file mode 100644
index 0000000..415a2c4
--- /dev/null
+++ b/iTriangle/src/location.rs
@@ -0,0 +1,28 @@
+use alloc::vec::Vec;
+
+#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
+pub struct TriangleIndex(usize);
+
+impl TriangleIndex {
+ pub fn new(index: usize) -> Self {
+ Self(index)
+ }
+
+ pub fn index(&self) -> usize {
+ self.0
+ }
+
+ pub fn to_vertex_indices(&self) -> [usize; 3] {
+ let offset = 3 * self.0;
+ [offset, offset + 1, offset + 2]
+ }
+}
+
+#[derive(Clone, Debug, Eq, PartialEq)]
+pub enum PointLocationInTriangulation {
+ Outside,
+ InsideTriangle(TriangleIndex),
+ OnExteriorEdge(TriangleIndex),
+ OnInteriorEdge(TriangleIndex, TriangleIndex),
+ OnVertex(Vec),
+}