-
Notifications
You must be signed in to change notification settings - Fork 9
Add naive O(n m) point location for int and float triangulation
#7
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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<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 | ||
| )); | ||
| } | ||
| } | ||
|
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 { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think we should write a helper trait for the
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
May I ask, why trait and not just a function? And why in 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 |
||
| 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 | ||
| )); | ||
| } | ||
| } | ||
| 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; | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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; | ||
| 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>), | ||
| } |
Uh oh!
There was an error while loading. Please reload this page.