Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
104 changes: 104 additions & 0 deletions iTriangle/src/float/locator.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
use alloc::vec::Vec;
Comment thread
mikwielgus marked this conversation as resolved.
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<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_triangulation = IntTriangulation {
points: self.points.to_int(&adapter),
indices: self.indices.clone(),
};

int_triangulation.locate_points(&points.to_int(&adapter))
}
}

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
));
}
}
1 change: 1 addition & 0 deletions iTriangle/src/float/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
149 changes: 149 additions & 0 deletions iTriangle/src/int/locator.rs
Comment thread
mikwielgus marked this conversation as resolved.
Original file line number Diff line number Diff line change
@@ -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<PointLocationInTriangulation>;
}

impl<I: IndexType> IntTriangulation<I> {
pub fn locate_points(&self, points: &[IntPoint]) -> Vec<PointLocationInTriangulation> {
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 {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should write a helper trait for the IntTriangle

fn locate_point(p, a, b, c) -> TriangleLocation (combine code form is_contain_point_exclude_borders and is_contain_point)

enum TriangleLocation {
    Outside,
    Inside,
    OnVertex,
    OnEdge
}

Copy link
Copy Markdown
Author

@mikwielgus mikwielgus May 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

helper trait

May I ask, why trait and not just a function? And why in IntTriangle and not Triangle? It is Triangle that contains is_contain_point_exclude_borders and is_contain_point.

May I suggest skipping this for now? It just would be convenient for me to have this available already. We can follow up in another PR (possibly to i_float instead). It is also likely to be faster and easier for you to implement this yourself -- you have better orientation in your code. (you should be also able to commit directly to this PR's branch).

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<I: IndexType> IntPointInTriangulationLocator for IntTriangulation<I> {
#[inline]
fn locate_points(&self, points: &[IntPoint]) -> Vec<PointLocationInTriangulation> {
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<u16> {
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
));
}
}
1 change: 1 addition & 0 deletions iTriangle/src/int/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
mod binder;
pub mod custom;
pub mod earcut;
pub mod locator;
mod meta;
pub(crate) mod monotone;
mod solver;
Expand Down
1 change: 1 addition & 0 deletions iTriangle/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
28 changes: 28 additions & 0 deletions iTriangle/src/location.rs
Original file line number Diff line number Diff line change
@@ -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<TriangleIndex>),
}