diff --git a/iTriangle/Cargo.toml b/iTriangle/Cargo.toml index 4b63c96..edaced7 100644 --- a/iTriangle/Cargo.toml +++ b/iTriangle/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "i_triangle" -version = "0.44.0" +version = "0.45.0" edition = "2021" authors = ["Nail Sharipov "] description = "Polygon Triangulation Library: Efficient Delaunay Triangulation for Complex Shapes." @@ -24,8 +24,8 @@ serde = { version = "^1.0", default-features = false, features = ["derive"], opt #i_tree = { path = "../../iTree" } #i_key_sort = { path = "../../iKeySort/iKeySort" } -i_overlay = "^6.0.0" -i_tree = "~0.18.0" +i_overlay = "^7.0.0" +i_tree = "~0.19.0" i_key_sort = "~0.10.3" diff --git a/iTriangle/README.md b/iTriangle/README.md index f57af25..5aa0a63 100644 --- a/iTriangle/README.md +++ b/iTriangle/README.md @@ -47,26 +47,7 @@ iTriangle is a high-performance 2D polygon triangulation library for Rust. It so ## Architecture Overview - - -
-Mermaid source - -```mermaid -flowchart TD - A[Input contours] --> B[Normalize and fix self-intersections] - B --> C[Sweep-line triangulation] - C --> D[Raw triangulation] - D -->|Delaunay| E[Delaunay triangulation] - D --> I[Triangles and indices] - E -->|Tessellation| F[Adaptive refinement] - F --> E - E --> G[Convex decomposition] - E --> H[Centroid net] - E --> I -``` - -
+ ## Quick Start @@ -93,6 +74,29 @@ let triangulation = vec![contour].triangulate().to_triangulation::(); println!("triangles: {}", triangulation.indices.len() / 3); ``` +By default, float input is converted to the robust integer core using `i32` +coordinates. If your geometry needs a different integer precision, choose it +explicitly: + +```rust +use i_triangle::float::triangulatable::Triangulatable; +use i_triangle::float::triangulator::Triangulator; + +let shape = vec![vec![ + [0.0, 0.0], + [10.0, 0.0], + [10.0, 10.0], + [0.0, 10.0], +]]; + +// One-shot triangulation with i64 integer coordinates. +let mesh = shape.triangulate_as::().to_triangulation::(); + +// Reusable triangulator: first generic is index type, second is coordinate type. +let mut triangulator = Triangulator::::default(); +let mesh = triangulator.triangulate(&shape); +``` + ## Documentation - [Docs.rs](https://docs.rs/i_triangle) @@ -192,6 +196,7 @@ let contours = vec![ vec![[5.0, 0.0], [9.0, 0.0], [9.0, 4.0], [5.0, 4.0]], ]; +// Uses u32 triangle indices and the default i32 integer coordinate solver. let mut triangulator = Triangulator::::default(); // Enable Delaunay refinement @@ -256,8 +261,8 @@ let contours = vec![ ], ]; -let mut triangulator = IntTriangulator::::default(); -let mut output = IntTriangulation::::default(); +let mut triangulator = IntTriangulator::::default(); +let mut output = IntTriangulation::::default(); for contour in &contours { triangulator.triangulate_contour_into(contour.clone(), &mut output); diff --git a/iTriangle/readme/architecture.png b/iTriangle/readme/architecture.png deleted file mode 100644 index 6820197..0000000 Binary files a/iTriangle/readme/architecture.png and /dev/null differ diff --git a/iTriangle/readme/architecture.svg b/iTriangle/readme/architecture.svg new file mode 100644 index 0000000..3aa236c --- /dev/null +++ b/iTriangle/readme/architecture.svg @@ -0,0 +1,435 @@ + + + + iTriangle architecture overview + Input contours are normalized, sweep-line triangulated, optionally refined into Delaunay, tessellation, convex decomposition, centroid net, and triangle index outputs. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Input + contours + + + + Normalize + fix intersections + + + + Sweep-line + triangulation + + + + Raw + triangulation + + + + Delaunay + triangulation + + + + Tessellation + refinement + + + + Convex + decomposition + + + + Centroid + net + + + + Triangles + and indices + + + + + iTriangle architecture overview + + + + diff --git a/iTriangle/src/advanced/centroid.rs b/iTriangle/src/advanced/centroid.rs index 60362ec..a2fbb09 100644 --- a/iTriangle/src/advanced/centroid.rs +++ b/iTriangle/src/advanced/centroid.rs @@ -2,11 +2,14 @@ use crate::advanced::delaunay::IntDelaunay; use crate::geom::triangle::IntTriangle; use alloc::vec; use alloc::vec::Vec; +use i_overlay::i_float::int::number::int::IntNumber; +use i_overlay::i_float::int::number::uint::UIntNumber; +use i_overlay::i_float::int::number::wide_int::WideIntNumber; use i_overlay::i_float::int::point::IntPoint; use i_overlay::i_shape::int::area::Area; use i_overlay::i_shape::int::shape::IntContour; -impl IntDelaunay { +impl IntDelaunay { /// Constructs a centroid-based polygonal net from the Delaunay triangulation. /// Each polygon surrounds a vertex using adjacent triangle centers and edge midpoints. /// @@ -17,7 +20,7 @@ impl IntDelaunay { /// /// # Returns /// A list of `IntContour` objects forming closed or convex polygonal regions. - pub fn centroid_net(&self, min_area: u64) -> Vec { + pub fn centroid_net(&self, min_area: I::WideUInt) -> Vec> { let two_area = min_area << 1; let n = self.triangles.len(); @@ -33,7 +36,7 @@ impl IntDelaunay { // go in counter-clockwise direction first - let mut contour = IntContour::with_capacity(16); + let mut contour = IntContour::::with_capacity(16); let mut t = &self.triangles[triangle_index]; let (mut next_index, mut mid) = t.left_neighbor_and_mid_edge(v.index); contour.push(t.center()); @@ -76,21 +79,21 @@ impl IntDelaunay { } } -trait SafeAdd { - fn add_area_check(&mut self, contour: IntContour, two_area: u64); +trait SafeAdd { + fn add_area_check(&mut self, contour: IntContour, two_area: I::WideUInt); } -impl SafeAdd for Vec { - fn add_area_check(&mut self, contour: IntContour, two_area: u64) { - if two_area == 0 || contour.area_two().unsigned_abs() > two_area { +impl SafeAdd for Vec> { + fn add_area_check(&mut self, contour: IntContour, two_area: I::WideUInt) { + if two_area == I::WideUInt::ZERO || contour.area_two().unsigned_abs() > two_area { self.push(contour); } } } -impl IntTriangle { +impl IntTriangle { #[inline] - fn right_neighbor_and_mid_edge(&self, vertex_index: usize) -> (usize, IntPoint) { + fn right_neighbor_and_mid_edge(&self, vertex_index: usize) -> (usize, IntPoint) { if self.vertices[0].index == vertex_index { let neighbor = self.neighbors[2]; let mid = middle(self.vertices[0].point, self.vertices[1].point); @@ -107,7 +110,7 @@ impl IntTriangle { } #[inline] - fn left_neighbor_and_mid_edge(&self, vertex_index: usize) -> (usize, IntPoint) { + fn left_neighbor_and_mid_edge(&self, vertex_index: usize) -> (usize, IntPoint) { if self.vertices[0].index == vertex_index { let neighbor = self.neighbors[1]; let mid = middle(self.vertices[0].point, self.vertices[2].point); @@ -124,23 +127,29 @@ impl IntTriangle { } #[inline] - fn center(&self) -> IntPoint { + fn center(&self) -> IntPoint { let a = self.vertices[0].point; let b = self.vertices[1].point; let c = self.vertices[2].point; - let x = a.x as i64 + b.x as i64 + c.x as i64; - let y = a.y as i64 + b.y as i64 + c.y as i64; + let x = a.x.wide() + b.x.wide() + c.x.wide(); + let y = a.y.wide() + b.y.wide() + c.y.wide(); - IntPoint::new((x / 3) as i32, (y / 3) as i32) + IntPoint::new( + I::from_wide(x / I::Wide::from_usize(3)), + I::from_wide(y / I::Wide::from_usize(3)), + ) } } #[inline] -fn middle(a: IntPoint, b: IntPoint) -> IntPoint { - let x = a.x as i64 + b.x as i64; - let y = a.y as i64 + b.y as i64; - IntPoint::new((x / 2) as i32, (y / 2) as i32) +fn middle(a: IntPoint, b: IntPoint) -> IntPoint { + let x = a.x.wide() + b.x.wide(); + let y = a.y.wide() + b.y.wide(); + IntPoint::new( + I::from_wide(x / I::Wide::TWO), + I::from_wide(y / I::Wide::TWO), + ) } #[cfg(test)] @@ -161,7 +170,7 @@ mod tests { let centroids = contour .triangulate_with_steiner_points(&[IntPoint::new(5, 5)]) .into_delaunay() - .centroid_net(0); + .centroid_net(0u64); assert_eq!(centroids.len(), 5); } } diff --git a/iTriangle/src/advanced/convex.rs b/iTriangle/src/advanced/convex.rs index 9d65133..29161de 100644 --- a/iTriangle/src/advanced/convex.rs +++ b/iTriangle/src/advanced/convex.rs @@ -3,16 +3,18 @@ use crate::geom::triangle::IntTriangle; use crate::index::Index; use alloc::vec; use alloc::vec::Vec; +use i_overlay::i_float::int::number::int::IntNumber; +use i_overlay::i_float::int::number::wide_int::WideIntNumber; use i_overlay::i_float::int::point::IntPoint; use i_overlay::i_shape::int::shape::IntContour; use i_overlay::i_shape::int::simple::Simplify; #[derive(Debug, Clone, Copy)] -struct Node { +struct Node { next: usize, index: usize, prev: usize, - point: IntPoint, + point: IntPoint, } #[derive(Debug, Clone, Copy)] @@ -23,12 +25,12 @@ struct Edge { b: usize, } -struct ConvexPolygonBuilder { - nodes: Vec, +struct ConvexPolygonBuilder { + nodes: Vec>, edges: Vec, } -impl ConvexPolygonBuilder { +impl ConvexPolygonBuilder { fn new() -> Self { Self { nodes: Vec::with_capacity(16), @@ -36,7 +38,7 @@ impl ConvexPolygonBuilder { } } - fn to_contour(&self) -> IntContour { + fn to_contour(&self) -> IntContour { let count = self.nodes.len(); let mut contour = Vec::with_capacity(count); @@ -51,7 +53,7 @@ impl ConvexPolygonBuilder { contour } - fn start(&mut self, triangle_index: usize, triangle: &IntTriangle) { + fn start(&mut self, triangle_index: usize, triangle: &IntTriangle) { self.nodes.clear(); self.edges.clear(); @@ -110,7 +112,7 @@ impl ConvexPolygonBuilder { } } - fn add(&mut self, edge: Edge, triangle: &IntTriangle) -> bool { + fn add(&mut self, edge: Edge, triangle: &IntTriangle) -> bool { let v_index = triangle.opposite(edge.triangle_index); let v = triangle.vertices[v_index]; @@ -120,11 +122,11 @@ impl ConvexPolygonBuilder { let va0 = self.nodes[node_a1.prev].point; let va1 = node_a1.point; - let aa = va1.subtract(va0); - let ap = v.point.subtract(va1); + let aa = va1 - va0; + let ap = v.point - va1; let apa = aa.cross_product(ap); - if apa < 0 { + if apa < I::Wide::ZERO { return false; } @@ -134,11 +136,11 @@ impl ConvexPolygonBuilder { let vb0 = self.nodes[node_b1.next].point; let vb1 = node_b1.point; - let bb = vb0.subtract(vb1); - let bp = vb1.subtract(v.point); + let bb = vb0 - vb1; + let bp = vb1 - v.point; let bpb = bp.cross_product(bb); - if bpb < 0 { + if bpb < I::Wide::ZERO { return false; } @@ -185,7 +187,7 @@ impl ConvexPolygonBuilder { } } -impl IntDelaunay { +impl IntDelaunay { /// Groups adjacent triangles into convex polygons in counter-clockwise order. /// /// This method traverses the Delaunay triangulation and greedily merges @@ -209,7 +211,7 @@ impl IntDelaunay { /// let polygons = triangulation.to_convex_polygons(); /// assert!(!polygons.is_empty()); /// ``` - pub fn to_convex_polygons(&self) -> Vec { + pub fn to_convex_polygons(&self) -> Vec> { let mut result = Vec::new(); let n = self.triangles.len(); @@ -250,7 +252,7 @@ mod tests { use i_overlay::i_shape::int::area::Area; use i_overlay::i_shape::int::path::IntPath; - fn path(slice: &[[i32; 2]]) -> IntPath { + fn path(slice: &[[i32; 2]]) -> IntPath { slice.iter().map(|p| IntPoint::new(p[0], p[1])).collect() } @@ -261,8 +263,8 @@ mod tests { assert_eq!(polygons.len(), 2); - assert!(polygons[0].area_two() < 0); - assert!(polygons[1].area_two() < 0); + assert!(polygons[0].area_two() > 0); + assert!(polygons[1].area_two() > 0); } #[test] @@ -272,7 +274,7 @@ mod tests { assert_eq!(polygons.len(), 1); - assert!(polygons[0].area_two() < 0); + assert!(polygons[0].area_two() > 0); } #[test] @@ -295,8 +297,8 @@ mod tests { assert_eq!(polygons.len(), 3); - assert!(polygons[0].area_two() < 0); - assert!(polygons[1].area_two() < 0); - assert!(polygons[2].area_two() < 0); + assert!(polygons[0].area_two() > 0); + assert!(polygons[1].area_two() > 0); + assert!(polygons[2].area_two() > 0); } } diff --git a/iTriangle/src/advanced/delaunay.rs b/iTriangle/src/advanced/delaunay.rs index b0d7619..0ac4266 100644 --- a/iTriangle/src/advanced/delaunay.rs +++ b/iTriangle/src/advanced/delaunay.rs @@ -3,8 +3,11 @@ use crate::advanced::buffer::DelaunayBuffer; use crate::geom::triangle::IntTriangle; use crate::int::triangulation::RawIntTriangulation; use alloc::vec::Vec; +use i_overlay::i_float::int::number::int::IntNumber; +use i_overlay::i_float::int::number::product_uint::UIntProduct; +use i_overlay::i_float::int::number::uint::UIntNumber; +use i_overlay::i_float::int::number::wide_int::WideIntNumber; use i_overlay::i_float::int::point::IntPoint; -use i_overlay::i_float::u128::UInt128; /// A 2D integer-based Delaunay triangulation. /// Each triangle satisfies the Delaunay condition. @@ -13,14 +16,14 @@ use i_overlay::i_float::u128::UInt128; /// - `triangles`: A list of `IntTriangle` elements (triangle vertex indices and neighbors) /// - `points`: A list of `IntPoint` elements (original and inserted points) /// -pub struct IntDelaunay { - pub triangles: Vec, - pub points: Vec, +pub struct IntDelaunay { + pub triangles: Vec>, + pub points: Vec>, } -impl IntDelaunay { +impl IntDelaunay { #[inline] - pub(crate) fn into_raw(self) -> RawIntTriangulation { + pub(crate) fn into_raw(self) -> RawIntTriangulation { RawIntTriangulation { triangles: self.triangles, points: self.points, @@ -28,7 +31,7 @@ impl IntDelaunay { } } -impl RawIntTriangulation { +impl RawIntTriangulation { /// Converts an int triangle mesh into a Delaunay triangulation by applying edge flips. /// /// The mesh is refined in-place by checking local angle conditions and @@ -37,7 +40,7 @@ impl RawIntTriangulation { /// # Returns /// A new [`IntDelaunay`] structure with updated triangle connectivity. #[inline] - pub fn into_delaunay(self) -> IntDelaunay { + pub fn into_delaunay(self) -> IntDelaunay { let mut buffer = DelaunayBuffer::new(); self.into_delaunay_with_buffer(&mut buffer) } @@ -49,7 +52,7 @@ impl RawIntTriangulation { /// # Returns /// A new [`IntDelaunay`] structure with updated triangle connectivity. #[inline] - pub fn into_delaunay_with_buffer(self, buffer: &mut DelaunayBuffer) -> IntDelaunay { + pub fn into_delaunay_with_buffer(self, buffer: &mut DelaunayBuffer) -> IntDelaunay { let mut delaunay = IntDelaunay { triangles: self.triangles, points: self.points, @@ -61,7 +64,7 @@ impl RawIntTriangulation { } } -pub trait DelaunayRefine { +pub trait DelaunayRefine { fn build(&mut self); fn build_with_buffer(&mut self, buffer: &mut DelaunayBuffer); fn fix_triangles(&mut self, buffer: &mut Vec, bitset: &mut IndexBitSet); @@ -70,7 +73,7 @@ pub trait DelaunayRefine { fn swap_triangles(&mut self, abc_index: usize, pcb_index: usize) -> bool; } -impl DelaunayRefine for [IntTriangle] { +impl DelaunayRefine for [IntTriangle] { #[inline] fn build(&mut self) { let mut buffer = DelaunayBuffer::new(); @@ -188,29 +191,34 @@ impl DelaunayCondition { // return true if triangle satisfied condition and do not need flip triangles // more detail explanation and demo https://ishape-rust.github.io/iShape-js/triangle/delaunay.html #[inline] - fn is_flip_not_required(p: IntPoint, a: IntPoint, b: IntPoint, c: IntPoint) -> bool { + fn is_flip_not_required( + p: IntPoint, + a: IntPoint, + b: IntPoint, + c: IntPoint, + ) -> bool { // x, y of all coordinates must be in range of i32 // p is a test point // b and c common points of triangle abc and pcb // alpha (A) is an angle of bpc // beta (B) is an angle of cab - let vbp = b.subtract(p); - let vcp = c.subtract(p); + let vbp = b - p; + let vcp = c - p; - let vba = b.subtract(a); - let vca = c.subtract(a); + let vba = b - a; + let vca = c - a; let cos_a = vbp.dot_product(vcp); let cos_b = vba.dot_product(vca); - if cos_a < 0 && cos_b < 0 { + if cos_a < I::Wide::ZERO && cos_b < I::Wide::ZERO { // A > 90 and B > 90 // A + B > 180 return false; } - if cos_a >= 0 && cos_b >= 0 { + if cos_a >= I::Wide::ZERO && cos_b >= I::Wide::ZERO { // A <= 90 and B <= 90 // A + B <= 180 return true; @@ -219,25 +227,27 @@ impl DelaunayCondition { let sn_a = vbp.cross_product(vcp).unsigned_abs(); // A <= 180 let sn_b = vba.cross_product(vca).unsigned_abs(); // B <= 180 - if cos_a < 0 { + if cos_a < I::Wide::ZERO { // cosA < 0 // cosB >= 0 - let sin_a_cos_b = UInt128::multiply(sn_a, cos_b as u64); // positive - let cos_a_sin_b = UInt128::multiply(cos_a.unsigned_abs(), sn_b); // negative + let sin_a_cos_b = ::Product::multiply(sn_a, cos_b.to_uint()); // positive + let cos_a_sin_b = + ::Product::multiply(cos_a.unsigned_abs(), sn_b); // negative sin_a_cos_b >= cos_a_sin_b } else { // cosA >= 0 // cosB < 0 - let sin_a_cos_b = UInt128::multiply(sn_a, cos_b.unsigned_abs()); // negative - let cos_a_sin_b = UInt128::multiply(cos_a as u64, sn_b); // positive + let sin_a_cos_b = + ::Product::multiply(sn_a, cos_b.unsigned_abs()); // negative + let cos_a_sin_b = ::Product::multiply(cos_a.to_uint(), sn_b); // positive cos_a_sin_b >= sin_a_cos_b } } } -impl IntTriangle { +impl IntTriangle { #[inline] fn update_neighbor(&mut self, old_index: usize, new_index: usize) { if self.neighbors[0] == old_index { @@ -252,7 +262,7 @@ impl IntTriangle { } #[cfg(test)] -impl IntDelaunay { +impl IntDelaunay { fn validate(&self) { use i_overlay::i_float::triangle::Triangle; @@ -260,8 +270,8 @@ impl IntDelaunay { let a = t.vertices[0].point; let b = t.vertices[1].point; let c = t.vertices[2].point; - let area = Triangle::area_two_point(a, b, c); - assert!(area <= 0); + let area = Triangle::area_two(a, b, c); + assert!(area >= I::Wide::ZERO); let n0 = t.neighbors[0]; let n1 = t.neighbors[1]; @@ -279,15 +289,15 @@ impl IntDelaunay { } } - fn area(&self) -> i64 { + fn area(&self) -> I::Wide { use i_overlay::i_float::triangle::Triangle; - let mut s = 0; + let mut s = I::Wide::ZERO; for t in self.triangles.iter() { let a = t.vertices[0].point; let b = t.vertices[1].point; let c = t.vertices[2].point; - s += Triangle::area_two_point(a, b, c); + s = s + Triangle::area_two(a, b, c); } s @@ -312,7 +322,7 @@ mod tests { use i_overlay::i_shape::int::path::IntPath; use rand::RngExt; - fn path(slice: &[[i32; 2]]) -> IntPath { + fn path(slice: &[[i32; 2]]) -> IntPath { slice.iter().map(|p| IntPoint::new(p[0], p[1])).collect() } @@ -504,7 +514,7 @@ mod tests { } } - fn random(radius: i32, n: usize) -> IntPath { + fn random(radius: i32, n: usize) -> IntPath { let a = radius / 2; let mut points = Vec::with_capacity(n); let mut rng = rand::rng(); diff --git a/iTriangle/src/advanced/triangulation.rs b/iTriangle/src/advanced/triangulation.rs index be665a6..69eb3e2 100644 --- a/iTriangle/src/advanced/triangulation.rs +++ b/iTriangle/src/advanced/triangulation.rs @@ -1,24 +1,25 @@ use crate::advanced::delaunay::IntDelaunay; use crate::int::triangulation::{IndexType, IntTriangulation}; use alloc::vec::Vec; +use i_overlay::i_float::int::number::int::IntNumber; use i_overlay::i_float::int::point::IntPoint; -impl IntDelaunay { +impl IntDelaunay { /// Returns the vertex positions in the triangulation. #[inline] - pub fn points(&self) -> &Vec { + pub fn points(&self) -> &Vec> { &self.points } /// Returns indices forming counter-clockwise triangles. #[inline] - pub fn triangle_indices(&self) -> Vec { + pub fn triangle_indices(&self) -> Vec { let mut result = Vec::with_capacity(3 * self.triangles.len()); for t in &self.triangles { let v = &t.vertices; - let i0 = I::try_from(v[0].index).unwrap_or(I::ZERO); - let i1 = I::try_from(v[1].index).unwrap_or(I::ZERO); - let i2 = I::try_from(v[2].index).unwrap_or(I::ZERO); + let i0 = N::try_from(v[0].index).unwrap_or(N::ZERO); + let i1 = N::try_from(v[1].index).unwrap_or(N::ZERO); + let i2 = N::try_from(v[2].index).unwrap_or(N::ZERO); result.extend_from_slice(&[i0, i1, i2]); } @@ -35,7 +36,7 @@ impl IntDelaunay { } #[inline] - pub fn into_triangulation(self) -> IntTriangulation { + pub fn into_triangulation(self) -> IntTriangulation { IntTriangulation { indices: self.triangle_indices(), points: self.points, diff --git a/iTriangle/src/float/centroid_net.rs b/iTriangle/src/float/centroid_net.rs index 938348b..92c3191 100644 --- a/iTriangle/src/float/centroid_net.rs +++ b/iTriangle/src/float/centroid_net.rs @@ -1,13 +1,17 @@ use crate::float::delaunay::Delaunay; use alloc::vec::Vec; use i_overlay::i_float::float::compatible::FloatPointCompatible; +use i_overlay::i_float::int::number::int::IntNumber; +use i_overlay::i_float::int::number::wide_int::WideIntNumber; use i_overlay::i_shape::base::data::Contour; use i_overlay::i_shape::float::adapter::ShapeToFloat; -impl Delaunay

{ +impl Delaunay { #[inline] pub fn to_centroid_net(&self, min_area: P::Scalar) -> Vec> { - let int_area = self.adapter.sqr_float_to_int(min_area); - self.delaunay.centroid_net(int_area).to_float(&self.adapter) + let int_area = self.adapter.round_sqr_len_to_int(min_area); + self.delaunay + .centroid_net(int_area.to_uint()) + .to_float(&self.adapter) } } diff --git a/iTriangle/src/float/circumcenter.rs b/iTriangle/src/float/circumcenter.rs index af98cce..ea62256 100644 --- a/iTriangle/src/float/circumcenter.rs +++ b/iTriangle/src/float/circumcenter.rs @@ -1,7 +1,9 @@ use crate::float::delaunay::Delaunay; use i_overlay::i_float::float::compatible::FloatPointCompatible; +use i_overlay::i_float::int::number::int::IntNumber; +use i_overlay::i_float::int::number::wide_int::WideIntNumber; -impl Delaunay

{ +impl Delaunay { #[inline] pub fn refine_with_circumcenters(mut self, min_area: P::Scalar) -> Self { self.refine_with_circumcenters_mut(min_area); @@ -16,14 +18,15 @@ impl Delaunay

{ #[inline] pub fn refine_with_circumcenters_mut(&mut self, min_area: P::Scalar) { - let int_area = self.adapter.sqr_float_to_int(min_area); - self.delaunay.refine_with_circumcenters_mut(int_area); + let int_area = self.adapter.round_sqr_len_to_int(min_area); + self.delaunay + .refine_with_circumcenters_mut(int_area.to_uint()); } #[inline] pub fn refine_with_circumcenters_by_obtuse_angle_mut(&mut self, min_area: P::Scalar) { - let int_area = self.adapter.sqr_float_to_int(min_area); + let int_area = self.adapter.round_sqr_len_to_int(min_area); self.delaunay - .refine_with_circumcenters_by_obtuse_angle_mut(int_area); + .refine_with_circumcenters_by_obtuse_angle_mut(int_area.to_uint()); } } diff --git a/iTriangle/src/float/convex.rs b/iTriangle/src/float/convex.rs index e1cb7f2..4fd3ac1 100644 --- a/iTriangle/src/float/convex.rs +++ b/iTriangle/src/float/convex.rs @@ -1,10 +1,11 @@ use crate::float::delaunay::Delaunay; use alloc::vec::Vec; use i_overlay::i_float::float::compatible::FloatPointCompatible; +use i_overlay::i_float::int::number::int::IntNumber; use i_overlay::i_shape::base::data::Contour; use i_overlay::i_shape::float::adapter::ShapeToFloat; -impl Delaunay

{ +impl Delaunay { /// Groups triangles into non-overlapping convex polygons in counter-clockwise order. /// /// Returns a list of float-based [`Contour

`]s. diff --git a/iTriangle/src/float/custom.rs b/iTriangle/src/float/custom.rs index 2e3b322..3925327 100644 --- a/iTriangle/src/float/custom.rs +++ b/iTriangle/src/float/custom.rs @@ -2,49 +2,79 @@ use crate::float::triangulation::RawTriangulation; use crate::int::custom::IntCustomTriangulatable; use crate::int::triangulation::RawIntTriangulation; use crate::int::validation::Validation; +use i_key_sort::sort::key::SortKey; use i_overlay::i_float::adapter::FloatPointAdapter; use i_overlay::i_float::float::compatible::FloatPointCompatible; use i_overlay::i_float::float::rect::FloatRect; +use i_overlay::i_float::int::number::int::IntNumber; use i_overlay::i_shape::base::data::{Contour, Shape}; use i_overlay::i_shape::float::adapter::{PathToInt, ShapeToInt, ShapesToInt}; use i_overlay::i_shape::float::rect::RectInit; +use i_tree::{Expiration, LayoutNumber}; /// A trait for triangulating float geometry with user-defined validation rules. /// /// Accepts a custom [`Validation`] object for tuning fill rule, min area, etc. pub trait CustomTriangulatable { /// Performs triangulation using the specified [`Validation`] settings. - fn custom_triangulate(&self, validation: Validation) -> RawTriangulation

; + fn custom_triangulate(&self, validation: Validation) -> RawTriangulation

{ + self.custom_triangulate_as(validation) + } + + /// Performs triangulation using the requested integer coordinate type. + fn custom_triangulate_as(&self, validation: Validation) -> RawTriangulation + where + I: IntNumber + Expiration + LayoutNumber + SortKey; /// Performs triangulation with Steiner points and a custom [`Validation`] config. fn custom_triangulate_with_steiner_points( &self, points: &[P], - validation: Validation, - ) -> RawTriangulation

; + validation: Validation, + ) -> RawTriangulation

{ + self.custom_triangulate_with_steiner_points_as(points, validation) + } + + /// Performs triangulation with Steiner points using the requested integer coordinate type. + fn custom_triangulate_with_steiner_points_as( + &self, + points: &[P], + validation: Validation, + ) -> RawTriangulation + where + I: IntNumber + Expiration + LayoutNumber + SortKey; } -impl CustomTriangulatable

for Contour

{ - fn custom_triangulate(&self, validation: Validation) -> RawTriangulation

{ +impl

CustomTriangulatable

for Contour

+where + P: FloatPointCompatible, +{ + fn custom_triangulate_as(&self, validation: Validation) -> RawTriangulation + where + I: IntNumber + Expiration + LayoutNumber + SortKey, + { if let Some(rect) = FloatRect::with_path(self) { - let adapter = FloatPointAdapter::

::new(rect); + let adapter = FloatPointAdapter::::new(rect); let raw = self.to_int(&adapter).custom_triangulate(validation); RawTriangulation { raw, adapter } } else { RawTriangulation { raw: RawIntTriangulation::default(), - adapter: FloatPointAdapter::

::new(FloatRect::zero()), + adapter: FloatPointAdapter::::new(FloatRect::zero()), } } } - fn custom_triangulate_with_steiner_points( + fn custom_triangulate_with_steiner_points_as( &self, points: &[P], - validation: Validation, - ) -> RawTriangulation

{ + validation: Validation, + ) -> RawTriangulation + where + I: IntNumber + Expiration + LayoutNumber + SortKey, + { if let Some(rect) = FloatRect::with_path(self) { - let adapter = FloatPointAdapter::

::new(rect); + let adapter = FloatPointAdapter::::new(rect); let float_points = points.to_int(&adapter); let raw = self .to_int(&adapter) @@ -53,33 +83,42 @@ impl CustomTriangulatable

for Contour

{ } else { RawTriangulation { raw: RawIntTriangulation::default(), - adapter: FloatPointAdapter::

::new(FloatRect::zero()), + adapter: FloatPointAdapter::::new(FloatRect::zero()), } } } } -impl CustomTriangulatable

for [Contour

] { - fn custom_triangulate(&self, validation: Validation) -> RawTriangulation

{ +impl

CustomTriangulatable

for [Contour

] +where + P: FloatPointCompatible, +{ + fn custom_triangulate_as(&self, validation: Validation) -> RawTriangulation + where + I: IntNumber + Expiration + LayoutNumber + SortKey, + { if let Some(rect) = FloatRect::with_paths(self) { - let adapter = FloatPointAdapter::

::new(rect); + let adapter = FloatPointAdapter::::new(rect); let raw = self.to_int(&adapter).custom_triangulate(validation); RawTriangulation { raw, adapter } } else { RawTriangulation { raw: RawIntTriangulation::default(), - adapter: FloatPointAdapter::

::new(FloatRect::zero()), + adapter: FloatPointAdapter::::new(FloatRect::zero()), } } } - fn custom_triangulate_with_steiner_points( + fn custom_triangulate_with_steiner_points_as( &self, points: &[P], - validation: Validation, - ) -> RawTriangulation

{ + validation: Validation, + ) -> RawTriangulation + where + I: IntNumber + Expiration + LayoutNumber + SortKey, + { if let Some(rect) = FloatRect::with_paths(self) { - let adapter = FloatPointAdapter::

::new(rect); + let adapter = FloatPointAdapter::::new(rect); let float_points = points.to_int(&adapter); let raw = self .to_int(&adapter) @@ -88,33 +127,42 @@ impl CustomTriangulatable

for [Contour

] { } else { RawTriangulation { raw: RawIntTriangulation::default(), - adapter: FloatPointAdapter::

::new(FloatRect::zero()), + adapter: FloatPointAdapter::::new(FloatRect::zero()), } } } } -impl CustomTriangulatable

for [Shape

] { - fn custom_triangulate(&self, validation: Validation) -> RawTriangulation

{ +impl

CustomTriangulatable

for [Shape

] +where + P: FloatPointCompatible, +{ + fn custom_triangulate_as(&self, validation: Validation) -> RawTriangulation + where + I: IntNumber + Expiration + LayoutNumber + SortKey, + { if let Some(rect) = FloatRect::with_list_of_paths(self) { - let adapter = FloatPointAdapter::

::new(rect); + let adapter = FloatPointAdapter::::new(rect); let raw = self.to_int(&adapter).custom_triangulate(validation); RawTriangulation { raw, adapter } } else { RawTriangulation { raw: RawIntTriangulation::default(), - adapter: FloatPointAdapter::

::new(FloatRect::zero()), + adapter: FloatPointAdapter::::new(FloatRect::zero()), } } } - fn custom_triangulate_with_steiner_points( + fn custom_triangulate_with_steiner_points_as( &self, points: &[P], - validation: Validation, - ) -> RawTriangulation

{ + validation: Validation, + ) -> RawTriangulation + where + I: IntNumber + Expiration + LayoutNumber + SortKey, + { if let Some(rect) = FloatRect::with_list_of_paths(self) { - let adapter = FloatPointAdapter::

::new(rect); + let adapter = FloatPointAdapter::::new(rect); let float_points = points.to_int(&adapter); let raw = self .to_int(&adapter) @@ -123,7 +171,7 @@ impl CustomTriangulatable

for [Shape

] { } else { RawTriangulation { raw: RawIntTriangulation::default(), - adapter: FloatPointAdapter::

::new(FloatRect::zero()), + adapter: FloatPointAdapter::::new(FloatRect::zero()), } } } diff --git a/iTriangle/src/float/delaunay.rs b/iTriangle/src/float/delaunay.rs index d1c7478..6a31a62 100644 --- a/iTriangle/src/float/delaunay.rs +++ b/iTriangle/src/float/delaunay.rs @@ -5,26 +5,27 @@ use crate::int::triangulation::IndexType; use alloc::vec::Vec; use i_overlay::i_float::adapter::FloatPointAdapter; use i_overlay::i_float::float::compatible::FloatPointCompatible; +use i_overlay::i_float::int::number::int::IntNumber; use i_overlay::i_shape::float::adapter::PathToFloat; /// A Delaunay-refined triangle mesh with float-mapped geometry. /// /// Produced from [`Triangulation::into_delaunay`] by applying edge flips /// to satisfy the Delaunay condition. -pub struct Delaunay { - pub(super) delaunay: IntDelaunay, - pub(super) adapter: FloatPointAdapter

, +pub struct Delaunay { + pub(super) delaunay: IntDelaunay, + pub(super) adapter: FloatPointAdapter, } -impl RawTriangulation

{ +impl RawTriangulation { #[inline] - pub fn into_delaunay(self) -> Delaunay

{ + pub fn into_delaunay(self) -> Delaunay { let mut buffer = DelaunayBuffer::new(); self.into_delaunay_with_buffer(&mut buffer) } #[inline] - pub fn into_delaunay_with_buffer(self, buffer: &mut DelaunayBuffer) -> Delaunay

{ + pub fn into_delaunay_with_buffer(self, buffer: &mut DelaunayBuffer) -> Delaunay { Delaunay { delaunay: self.raw.into_delaunay_with_buffer(buffer), adapter: self.adapter, @@ -32,7 +33,7 @@ impl RawTriangulation

{ } } -impl Delaunay

{ +impl Delaunay { /// Returns the float-mapped vertex positions in the triangulation. #[inline] pub fn points(&self) -> Vec

{ @@ -41,7 +42,7 @@ impl Delaunay

{ /// Returns indices forming counter-clockwise triangles. #[inline] - pub fn triangle_indices(&self) -> Vec { + pub fn triangle_indices(&self) -> Vec { self.delaunay.triangle_indices() } @@ -53,7 +54,7 @@ impl Delaunay

{ /// Converts this refined mesh into a flat float [`Triangulation`]. #[inline] - pub fn to_triangulation(&self) -> Triangulation { + pub fn to_triangulation(&self) -> Triangulation { Triangulation { indices: self.triangle_indices(), points: self.points(), diff --git a/iTriangle/src/float/locator.rs b/iTriangle/src/float/locator.rs index 254834f..dc3012f 100644 --- a/iTriangle/src/float/locator.rs +++ b/iTriangle/src/float/locator.rs @@ -1,6 +1,8 @@ use alloc::vec::Vec; +use i_key_sort::sort::key::SortKey; use i_overlay::i_float::float::compatible::FloatPointCompatible; use i_overlay::i_float::float::number::FloatNumber; +use i_overlay::i_float::int::number::int::IntNumber; use i_overlay::{i_float::adapter::FloatPointAdapter, i_shape::float::adapter::PathToInt}; use crate::int::locator::IntPointInTriangulationLocator; @@ -9,19 +11,23 @@ use crate::{ location::PointLocationInTriangulation, }; -pub trait PointInTriangulationLocator

{ +pub trait PointInTriangulationLocator { fn locate_points(&self, points: &[P]) -> Vec where P: FloatPointCompatible, + I: SortKey, T: FloatNumber; } -impl Triangulation { - pub fn locate_points(&self, points: &[P]) -> Vec +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 adapter = FloatPointAdapter::::with_iter(self.points.iter().chain(points.iter())); let int_points = points.to_int(&adapter); @@ -36,14 +42,16 @@ impl Triangulation { } } -impl PointInTriangulationLocator

for Triangulation { +impl PointInTriangulationLocator + for Triangulation +{ #[inline] fn locate_points(&self, points: &[P]) -> Vec where P: FloatPointCompatible, T: FloatNumber, { - Triangulation::locate_points::(self, points) + Triangulation::locate_points::(self, points) } } @@ -75,7 +83,7 @@ mod tests { [5.0, 1.0], ]; - let locations = triangulation.locate_points::(&points_to_locate); + let locations = triangulation.locate_points::(&points_to_locate); assert!(matches!( locations[0], diff --git a/iTriangle/src/float/triangulatable.rs b/iTriangle/src/float/triangulatable.rs index a57ff7a..32c057f 100644 --- a/iTriangle/src/float/triangulatable.rs +++ b/iTriangle/src/float/triangulatable.rs @@ -1,12 +1,15 @@ use crate::float::triangulation::RawTriangulation; use crate::int::triangulatable::IntTriangulatable; use crate::int::triangulation::RawIntTriangulation; +use i_key_sort::sort::key::SortKey; use i_overlay::i_float::adapter::FloatPointAdapter; use i_overlay::i_float::float::compatible::FloatPointCompatible; use i_overlay::i_float::float::rect::FloatRect; +use i_overlay::i_float::int::number::int::IntNumber; use i_overlay::i_shape::base::data::{Contour, Shape}; use i_overlay::i_shape::float::adapter::{PathToInt, ShapeToInt, ShapesToInt}; use i_overlay::i_shape::float::rect::RectInit; +use i_tree::{Expiration, LayoutNumber}; /// A trait for triangulating float-based geometry with default validation. /// @@ -21,31 +24,54 @@ pub trait Triangulatable { /// Triangulates the shape(s) using the default [`Triangulator`] configuration. /// /// Validation includes contour simplification, direction correction, and area filtering. - fn triangulate(&self) -> RawTriangulation

; + fn triangulate(&self) -> RawTriangulation

{ + self.triangulate_as::() + } + + /// Triangulates the shape(s) using the requested integer coordinate type. + fn triangulate_as(&self) -> RawTriangulation + where + I: IntNumber + Expiration + LayoutNumber + SortKey; /// Triangulates the shape(s) and inserts the given Steiner points. /// /// Points must lie strictly within the interior of the geometry. - fn triangulate_with_steiner_points(&self, points: &[P]) -> RawTriangulation

; + fn triangulate_with_steiner_points(&self, points: &[P]) -> RawTriangulation

{ + self.triangulate_with_steiner_points_as::(points) + } + + /// Triangulates the shape(s) with Steiner points using the requested integer coordinate type. + fn triangulate_with_steiner_points_as(&self, points: &[P]) -> RawTriangulation + where + I: IntNumber + Expiration + LayoutNumber + SortKey; } -impl Triangulatable

for [P] { - fn triangulate(&self) -> RawTriangulation

{ +impl

Triangulatable

for [P] +where + P: FloatPointCompatible, +{ + fn triangulate_as(&self) -> RawTriangulation + where + I: IntNumber + Expiration + LayoutNumber + SortKey, + { if let Some(rect) = FloatRect::with_path(self) { - let adapter = FloatPointAdapter::

::new(rect); + let adapter = FloatPointAdapter::::new(rect); let raw = self.to_int(&adapter).triangulate(); RawTriangulation { raw, adapter } } else { RawTriangulation { raw: RawIntTriangulation::default(), - adapter: FloatPointAdapter::

::new(FloatRect::zero()), + adapter: FloatPointAdapter::::new(FloatRect::zero()), } } } - fn triangulate_with_steiner_points(&self, points: &[P]) -> RawTriangulation

{ + fn triangulate_with_steiner_points_as(&self, points: &[P]) -> RawTriangulation + where + I: IntNumber + Expiration + LayoutNumber + SortKey, + { if let Some(rect) = FloatRect::with_path(self) { - let adapter = FloatPointAdapter::

::new(rect); + let adapter = FloatPointAdapter::::new(rect); let float_points = points.to_int(&adapter); let raw = self .to_int(&adapter) @@ -54,29 +80,38 @@ impl Triangulatable

for [P] { } else { RawTriangulation { raw: RawIntTriangulation::default(), - adapter: FloatPointAdapter::

::new(FloatRect::zero()), + adapter: FloatPointAdapter::::new(FloatRect::zero()), } } } } -impl Triangulatable

for [Contour

] { - fn triangulate(&self) -> RawTriangulation

{ +impl

Triangulatable

for [Contour

] +where + P: FloatPointCompatible, +{ + fn triangulate_as(&self) -> RawTriangulation + where + I: IntNumber + Expiration + LayoutNumber + SortKey, + { if let Some(rect) = FloatRect::with_paths(self) { - let adapter = FloatPointAdapter::

::new(rect); + let adapter = FloatPointAdapter::::new(rect); let raw = self.to_int(&adapter).triangulate(); RawTriangulation { raw, adapter } } else { RawTriangulation { raw: RawIntTriangulation::default(), - adapter: FloatPointAdapter::

::new(FloatRect::zero()), + adapter: FloatPointAdapter::::new(FloatRect::zero()), } } } - fn triangulate_with_steiner_points(&self, points: &[P]) -> RawTriangulation

{ + fn triangulate_with_steiner_points_as(&self, points: &[P]) -> RawTriangulation + where + I: IntNumber + Expiration + LayoutNumber + SortKey, + { if let Some(rect) = FloatRect::with_paths(self) { - let adapter = FloatPointAdapter::

::new(rect); + let adapter = FloatPointAdapter::::new(rect); let float_points = points.to_int(&adapter); let raw = self .to_int(&adapter) @@ -85,29 +120,38 @@ impl Triangulatable

for [Contour

] { } else { RawTriangulation { raw: RawIntTriangulation::default(), - adapter: FloatPointAdapter::

::new(FloatRect::zero()), + adapter: FloatPointAdapter::::new(FloatRect::zero()), } } } } -impl Triangulatable

for [Shape

] { - fn triangulate(&self) -> RawTriangulation

{ +impl

Triangulatable

for [Shape

] +where + P: FloatPointCompatible, +{ + fn triangulate_as(&self) -> RawTriangulation + where + I: IntNumber + Expiration + LayoutNumber + SortKey, + { if let Some(rect) = FloatRect::with_list_of_paths(self) { - let adapter = FloatPointAdapter::

::new(rect); + let adapter = FloatPointAdapter::::new(rect); let raw = self.to_int(&adapter).triangulate(); RawTriangulation { raw, adapter } } else { RawTriangulation { raw: RawIntTriangulation::default(), - adapter: FloatPointAdapter::

::new(FloatRect::zero()), + adapter: FloatPointAdapter::::new(FloatRect::zero()), } } } - fn triangulate_with_steiner_points(&self, points: &[P]) -> RawTriangulation

{ + fn triangulate_with_steiner_points_as(&self, points: &[P]) -> RawTriangulation + where + I: IntNumber + Expiration + LayoutNumber + SortKey, + { if let Some(rect) = FloatRect::with_list_of_paths(self) { - let adapter = FloatPointAdapter::

::new(rect); + let adapter = FloatPointAdapter::::new(rect); let float_points = points.to_int(&adapter); let raw = self .to_int(&adapter) @@ -116,7 +160,7 @@ impl Triangulatable

for [Shape

] { } else { RawTriangulation { raw: RawIntTriangulation::default(), - adapter: FloatPointAdapter::

::new(FloatRect::zero()), + adapter: FloatPointAdapter::::new(FloatRect::zero()), } } } diff --git a/iTriangle/src/float/triangulation.rs b/iTriangle/src/float/triangulation.rs index dad88e3..822eba7 100644 --- a/iTriangle/src/float/triangulation.rs +++ b/iTriangle/src/float/triangulation.rs @@ -3,6 +3,7 @@ use alloc::vec::Vec; use i_overlay::i_float::adapter::FloatPointAdapter; use i_overlay::i_float::float::compatible::FloatPointCompatible; use i_overlay::i_float::float::number::FloatNumber; +use i_overlay::i_float::int::number::int::IntNumber; use i_overlay::i_shape::float::adapter::PathToFloat; use i_overlay::i_shape::util::reserve::Reserve; @@ -13,9 +14,9 @@ use i_overlay::i_shape::util::reserve::Reserve; /// /// # Parameters /// - `P`: Float point type (e.g., `Vec2`, `[f32; 2]`, etc.) -pub struct RawTriangulation { - pub raw: RawIntTriangulation, - pub adapter: FloatPointAdapter

, +pub struct RawTriangulation { + pub raw: RawIntTriangulation, + pub adapter: FloatPointAdapter, } /// A flat triangulation result consisting of float points and triangle indices. @@ -28,7 +29,7 @@ pub struct Triangulation { pub indices: Vec, } -impl RawTriangulation

{ +impl RawTriangulation { /// Returns the float-mapped points used in the triangulation. /// /// The points are guaranteed to match the input shape geometry within adapter precision. @@ -39,13 +40,13 @@ impl RawTriangulation

{ /// Returns the triangle indices for the mesh, ordered counter-clockwise. #[inline] - pub fn triangle_indices(&self) -> Vec { + pub fn triangle_indices(&self) -> Vec { self.raw.triangle_indices() } /// Converts this flat triangulation into a flat [`Triangulation`] (points + indices). #[inline] - pub fn to_triangulation(&self) -> Triangulation { + pub fn to_triangulation(&self) -> Triangulation { Triangulation { indices: self.triangle_indices(), points: self.points(), @@ -53,7 +54,7 @@ impl RawTriangulation

{ } } -impl Triangulation { +impl Triangulation { #[inline] pub fn with_capacity(capacity: usize) -> Self { Self { @@ -63,10 +64,10 @@ impl Triangulation { } #[inline] - pub fn set_with_int( + pub fn set_with_int( &mut self, - triangulation: &IntTriangulation, - adapter: &FloatPointAdapter

, + triangulation: &IntTriangulation, + adapter: &FloatPointAdapter, ) where P: FloatPointCompatible, { @@ -81,12 +82,12 @@ impl Triangulation { } } -impl IntTriangulation { +impl IntTriangulation { #[inline] pub fn into_float( self, - adapter: &FloatPointAdapter

, - ) -> Triangulation { + adapter: &FloatPointAdapter, + ) -> Triangulation { let points = self .points .iter() @@ -101,8 +102,8 @@ impl IntTriangulation { #[inline] pub fn to_float( &self, - adapter: &FloatPointAdapter

, - ) -> Triangulation { + adapter: &FloatPointAdapter, + ) -> Triangulation { let points = self .points .iter() diff --git a/iTriangle/src/float/triangulator.rs b/iTriangle/src/float/triangulator.rs index 26112e5..c6def4d 100644 --- a/iTriangle/src/float/triangulator.rs +++ b/iTriangle/src/float/triangulator.rs @@ -2,19 +2,29 @@ use crate::float::triangulation::Triangulation; use crate::int::triangulation::{IndexType, IntTriangulation}; use crate::int::triangulator::IntTriangulator; use crate::int::validation::Validation; +use i_key_sort::sort::key::SortKey; use i_overlay::core::solver::Solver; use i_overlay::i_float::float::compatible::FloatPointCompatible; +use i_overlay::i_float::int::number::int::IntNumber; use i_overlay::i_shape::flat::buffer::FlatContoursBuffer; use i_overlay::i_shape::source::resource::ShapeResource; +use i_tree::{Expiration, LayoutNumber}; /// A reusable triangulator that converts float-based shapes into triangle meshes. -pub struct Triangulator { - flat_buffer: Option, - int_buffer: Option>, - int_triangulator: IntTriangulator, +pub struct Triangulator +where + I: IntNumber + Expiration + LayoutNumber + SortKey, +{ + flat_buffer: Option>, + int_buffer: Option>, + int_triangulator: IntTriangulator, } -impl Triangulator { +impl Triangulator +where + I: IntNumber + Expiration + LayoutNumber + SortKey, + N: IndexType, +{ /// Enables or disables Delaunay refinement for triangulation. /// /// When enabled, the triangulator will attempt to generate a mesh that satisfies the @@ -52,7 +62,7 @@ impl Triangulator { /// /// Uses internal buffers to minimize allocations and speed up repeated calls. #[inline] - pub fn new(max_points_count: usize, validation: Validation, solver: Solver) -> Self { + pub fn new(max_points_count: usize, validation: Validation, solver: Solver) -> Self { Self { flat_buffer: Some(FlatContoursBuffer::with_capacity(max_points_count)), int_buffer: Some(IntTriangulation::with_capacity(max_points_count)), @@ -61,14 +71,22 @@ impl Triangulator { } } -impl Default for Triangulator { +impl Default for Triangulator +where + I: IntNumber + Expiration + LayoutNumber + SortKey, + N: IndexType, +{ #[inline] fn default() -> Self { Self::new(64, Default::default(), Default::default()) } } -impl Triangulator { +impl Triangulator +where + I: IntNumber + Expiration + LayoutNumber + SortKey, + N: IndexType, +{ /// Performs triangulation on the provided shape resource and returns a new `Triangulation`. /// /// - `resource`: A `ShapeResource` that define contours. @@ -79,7 +97,7 @@ impl Triangulator { /// /// Uses internal buffers to reduce allocations and preserve performance. #[inline] - pub fn triangulate(&mut self, resource: &R) -> Triangulation + pub fn triangulate(&mut self, resource: &R) -> Triangulation where R: ShapeResource

+ ?Sized, P: FloatPointCompatible, @@ -113,7 +131,7 @@ impl Triangulator { /// /// Uses internal buffers to reduce allocations and preserve performance. #[inline] - pub fn triangulate_into(&mut self, resource: &R, triangulation: &mut Triangulation) + pub fn triangulate_into(&mut self, resource: &R, triangulation: &mut Triangulation) where R: ShapeResource

+ ?Sized, P: FloatPointCompatible, @@ -145,7 +163,7 @@ impl Triangulator { /// /// Uses internal buffers to reduce allocations and preserve performance. #[inline] - pub fn uncheck_triangulate(&mut self, resource: &R) -> Triangulation + pub fn uncheck_triangulate(&mut self, resource: &R) -> Triangulation where R: ShapeResource

+ ?Sized, P: FloatPointCompatible, @@ -184,7 +202,7 @@ impl Triangulator { pub fn uncheck_triangulate_into( &mut self, resource: &R, - triangulation: &mut Triangulation, + triangulation: &mut Triangulation, ) where R: ShapeResource

+ ?Sized, P: FloatPointCompatible, diff --git a/iTriangle/src/float/unchecked.rs b/iTriangle/src/float/unchecked.rs index bf2074e..4356aaa 100644 --- a/iTriangle/src/float/unchecked.rs +++ b/iTriangle/src/float/unchecked.rs @@ -1,12 +1,15 @@ use crate::float::triangulation::RawTriangulation; use crate::int::triangulation::RawIntTriangulation; use crate::int::unchecked::IntUncheckedTriangulatable; +use i_key_sort::sort::key::SortKey; use i_overlay::i_float::adapter::FloatPointAdapter; use i_overlay::i_float::float::compatible::FloatPointCompatible; use i_overlay::i_float::float::rect::FloatRect; +use i_overlay::i_float::int::number::int::IntNumber; use i_overlay::i_shape::base::data::{Contour, Shape}; use i_overlay::i_shape::float::adapter::{PathToInt, ShapeToInt, ShapesToInt}; use i_overlay::i_shape::float::rect::RectInit; +use i_tree::Expiration; /// A trait for triangulating already valid float-based geometry. /// @@ -18,28 +21,58 @@ use i_overlay::i_shape::float::rect::RectInit; /// - Steiner points must lie strictly within the shape pub trait UncheckedTriangulatable { /// Triangulates float geometry without validation or simplification. - fn unchecked_triangulate(&self) -> RawTriangulation

; + fn unchecked_triangulate(&self) -> RawTriangulation

{ + self.unchecked_triangulate_as::() + } + + /// Triangulates float geometry without validation using the requested integer coordinate type. + fn unchecked_triangulate_as(&self) -> RawTriangulation + where + I: IntNumber + Expiration + SortKey; + /// Same as `unchecked_triangulate`, but inserts user-defined Steiner points. - fn unchecked_triangulate_with_steiner_points(&self, points: &[P]) -> RawTriangulation

; + fn unchecked_triangulate_with_steiner_points(&self, points: &[P]) -> RawTriangulation

{ + self.unchecked_triangulate_with_steiner_points_as::(points) + } + + /// Same as `unchecked_triangulate_as`, but inserts user-defined Steiner points. + fn unchecked_triangulate_with_steiner_points_as( + &self, + points: &[P], + ) -> RawTriangulation + where + I: IntNumber + Expiration + SortKey; } -impl UncheckedTriangulatable

for [P] { - fn unchecked_triangulate(&self) -> RawTriangulation

{ +impl

UncheckedTriangulatable

for [P] +where + P: FloatPointCompatible, +{ + fn unchecked_triangulate_as(&self) -> RawTriangulation + where + I: IntNumber + Expiration + SortKey, + { if let Some(rect) = FloatRect::with_path(self) { - let adapter = FloatPointAdapter::

::new(rect); + let adapter = FloatPointAdapter::::new(rect); let raw = self.to_int(&adapter).uncheck_triangulate(); RawTriangulation { raw, adapter } } else { RawTriangulation { raw: RawIntTriangulation::default(), - adapter: FloatPointAdapter::

::new(FloatRect::zero()), + adapter: FloatPointAdapter::::new(FloatRect::zero()), } } } - fn unchecked_triangulate_with_steiner_points(&self, points: &[P]) -> RawTriangulation

{ + fn unchecked_triangulate_with_steiner_points_as( + &self, + points: &[P], + ) -> RawTriangulation + where + I: IntNumber + Expiration + SortKey, + { if let Some(rect) = FloatRect::with_path(self) { - let adapter = FloatPointAdapter::

::new(rect); + let adapter = FloatPointAdapter::::new(rect); let float_points = points.to_int(&adapter); let raw = self .to_int(&adapter) @@ -48,29 +81,41 @@ impl UncheckedTriangulatable

for [P] { } else { RawTriangulation { raw: RawIntTriangulation::default(), - adapter: FloatPointAdapter::

::new(FloatRect::zero()), + adapter: FloatPointAdapter::::new(FloatRect::zero()), } } } } -impl UncheckedTriangulatable

for [Contour

] { - fn unchecked_triangulate(&self) -> RawTriangulation

{ +impl

UncheckedTriangulatable

for [Contour

] +where + P: FloatPointCompatible, +{ + fn unchecked_triangulate_as(&self) -> RawTriangulation + where + I: IntNumber + Expiration + SortKey, + { if let Some(rect) = FloatRect::with_paths(self) { - let adapter = FloatPointAdapter::

::new(rect); + let adapter = FloatPointAdapter::::new(rect); let raw = self.to_int(&adapter).uncheck_triangulate(); RawTriangulation { raw, adapter } } else { RawTriangulation { raw: RawIntTriangulation::default(), - adapter: FloatPointAdapter::

::new(FloatRect::zero()), + adapter: FloatPointAdapter::::new(FloatRect::zero()), } } } - fn unchecked_triangulate_with_steiner_points(&self, points: &[P]) -> RawTriangulation

{ + fn unchecked_triangulate_with_steiner_points_as( + &self, + points: &[P], + ) -> RawTriangulation + where + I: IntNumber + Expiration + SortKey, + { if let Some(rect) = FloatRect::with_paths(self) { - let adapter = FloatPointAdapter::

::new(rect); + let adapter = FloatPointAdapter::::new(rect); let float_points = points.to_int(&adapter); let raw = self .to_int(&adapter) @@ -79,29 +124,41 @@ impl UncheckedTriangulatable

for [Contour

] { } else { RawTriangulation { raw: RawIntTriangulation::default(), - adapter: FloatPointAdapter::

::new(FloatRect::zero()), + adapter: FloatPointAdapter::::new(FloatRect::zero()), } } } } -impl UncheckedTriangulatable

for [Shape

] { - fn unchecked_triangulate(&self) -> RawTriangulation

{ +impl

UncheckedTriangulatable

for [Shape

] +where + P: FloatPointCompatible, +{ + fn unchecked_triangulate_as(&self) -> RawTriangulation + where + I: IntNumber + Expiration + SortKey, + { if let Some(rect) = FloatRect::with_list_of_paths(self) { - let adapter = FloatPointAdapter::

::new(rect); + let adapter = FloatPointAdapter::::new(rect); let raw = self.to_int(&adapter).uncheck_triangulate(); RawTriangulation { raw, adapter } } else { RawTriangulation { raw: RawIntTriangulation::default(), - adapter: FloatPointAdapter::

::new(FloatRect::zero()), + adapter: FloatPointAdapter::::new(FloatRect::zero()), } } } - fn unchecked_triangulate_with_steiner_points(&self, points: &[P]) -> RawTriangulation

{ + fn unchecked_triangulate_with_steiner_points_as( + &self, + points: &[P], + ) -> RawTriangulation + where + I: IntNumber + Expiration + SortKey, + { if let Some(rect) = FloatRect::with_list_of_paths(self) { - let adapter = FloatPointAdapter::

::new(rect); + let adapter = FloatPointAdapter::::new(rect); let float_points = points.to_int(&adapter); let raw = self .to_int(&adapter) @@ -110,7 +167,7 @@ impl UncheckedTriangulatable

for [Shape

] { } else { RawTriangulation { raw: RawIntTriangulation::default(), - adapter: FloatPointAdapter::

::new(FloatRect::zero()), + adapter: FloatPointAdapter::::new(FloatRect::zero()), } } } diff --git a/iTriangle/src/geom/point.rs b/iTriangle/src/geom/point.rs index d08ed57..c94bed6 100644 --- a/iTriangle/src/geom/point.rs +++ b/iTriangle/src/geom/point.rs @@ -1,14 +1,15 @@ +use i_overlay::i_float::int::number::int::IntNumber; use i_overlay::i_float::int::point::IntPoint; #[derive(Debug, Clone, Copy)] -pub struct IndexPoint { +pub struct IndexPoint { pub index: usize, - pub point: IntPoint, + pub point: IntPoint, } -impl IndexPoint { +impl IndexPoint { #[inline] - pub fn new(index: usize, point: IntPoint) -> Self { + pub fn new(index: usize, point: IntPoint) -> Self { Self { index, point } } @@ -21,7 +22,7 @@ impl IndexPoint { } } -impl Default for IndexPoint { +impl Default for IndexPoint { #[inline] fn default() -> Self { IndexPoint::empty() diff --git a/iTriangle/src/geom/triangle.rs b/iTriangle/src/geom/triangle.rs index 3b64fa9..1599a94 100644 --- a/iTriangle/src/geom/triangle.rs +++ b/iTriangle/src/geom/triangle.rs @@ -1,28 +1,29 @@ use crate::geom::point::IndexPoint; +use i_overlay::i_float::int::number::int::IntNumber; #[derive(Debug, Clone)] -pub struct Abc { - pub v0: ABCVertex, - pub v1: ABCVertex, - pub v2: ABCVertex, +pub struct Abc { + pub v0: ABCVertex, + pub v1: ABCVertex, + pub v2: ABCVertex, } #[derive(Debug, Clone, Copy)] -pub struct ABCVertex { - pub vertex: IndexPoint, +pub struct ABCVertex { + pub vertex: IndexPoint, pub position: usize, pub neighbor: usize, } #[derive(Debug, Clone)] -pub struct IntTriangle { - pub vertices: [IndexPoint; 3], +pub struct IntTriangle { + pub vertices: [IndexPoint; 3], pub neighbors: [usize; 3], } -impl IntTriangle { +impl IntTriangle { #[inline] - pub fn abc(a: IndexPoint, b: IndexPoint, c: IndexPoint) -> Self { + pub fn abc(a: IndexPoint, b: IndexPoint, c: IndexPoint) -> Self { Self { vertices: [a, b, c], neighbors: [usize::MAX; 3], @@ -81,7 +82,7 @@ impl IntTriangle { } #[inline] - pub(crate) fn abc_by_neighbor(&self, neighbor: usize) -> Abc { + pub(crate) fn abc_by_neighbor(&self, neighbor: usize) -> Abc { if neighbor == self.neighbors[0] { self.abc_by_a() } else if neighbor == self.neighbors[1] { @@ -92,7 +93,7 @@ impl IntTriangle { } #[inline] - pub(crate) fn abc_by_a(&self) -> Abc { + pub(crate) fn abc_by_a(&self) -> Abc { let a = ABCVertex { vertex: self.vertices[0], position: 0, @@ -116,7 +117,7 @@ impl IntTriangle { } #[inline] - pub(crate) fn abc_by_b(&self) -> Abc { + pub(crate) fn abc_by_b(&self) -> Abc { let a = ABCVertex { vertex: self.vertices[1], position: 1, @@ -140,7 +141,7 @@ impl IntTriangle { } #[inline] - pub(crate) fn abc_by_c(&self) -> Abc { + pub(crate) fn abc_by_c(&self) -> Abc { let a = ABCVertex { vertex: self.vertices[2], position: 2, diff --git a/iTriangle/src/int/binder.rs b/iTriangle/src/int/binder.rs index 6e1fe36..7897542 100644 --- a/iTriangle/src/int/binder.rs +++ b/iTriangle/src/int/binder.rs @@ -1,51 +1,52 @@ use crate::int::monotone::v_segment::VSegment; use alloc::vec; use alloc::vec::Vec; +use i_overlay::i_float::int::number::int::IntNumber; use i_overlay::i_float::int::point::IntPoint; use i_overlay::i_float::triangle::Triangle; use i_overlay::i_shape::int::shape::IntShape; use i_tree::key::exp::KeyExpCollection; use i_tree::key::tree::KeyExpTree; -use i_tree::ExpiredKey; +use i_tree::{Expiration, ExpiredKey}; #[derive(Debug, Clone, Copy)] -struct ShapeEdge { - a: IntPoint, - b: IntPoint, +struct ShapeEdge { + a: IntPoint, + b: IntPoint, shape_index: usize, } #[derive(Debug, Clone, Copy)] -struct VEdge { - min_y: i32, - max_y: i32, - x: i32, +struct VEdge { + min_y: I, + max_y: I, + x: I, } #[derive(Debug, Clone, Copy)] -struct TargetSegment { - edge: ShapeEdge, - v_segment: VSegment, +struct TargetSegment { + edge: ShapeEdge, + v_segment: VSegment, } -impl ExpiredKey for VSegment { - fn expiration(&self) -> i32 { +impl ExpiredKey for VSegment { + fn expiration(&self) -> I { self.b.x } } -pub(super) trait SteinerInference { - fn group_by_shapes(&self, points: &[IntPoint]) -> Vec>; +pub(super) trait SteinerInference { + fn group_by_shapes(&self, points: &[IntPoint]) -> Vec>>; } -impl SteinerInference for [IntShape] { - fn group_by_shapes(&self, points: &[IntPoint]) -> Vec> { +impl SteinerInference for [IntShape] { + fn group_by_shapes(&self, points: &[IntPoint]) -> Vec>> { if points.is_empty() { return vec![Vec::new(); self.len()]; } let mut points = points.to_vec(); - points.sort_unstable_by(|a, b| a.x.cmp(&b.x)); + points.sort_unstable_by_key(|p| p.x); points.dedup(); let x_min = points[0].x; @@ -91,9 +92,9 @@ impl SteinerInference for [IntShape] { return vec![Vec::new(); self.len()]; } - segments.sort_unstable_by(|s0, s1| s0.v_segment.a.cmp(&s1.v_segment.a)); - v_edges.sort_unstable_by(|e0, e1| e0.x.cmp(&e1.x)); - x_points.sort_unstable_by(|p0, p1| p0.x.cmp(&p1.x)); + segments.sort_unstable_by_key(|s| s.v_segment.a); + v_edges.sort_unstable_by_key(|e| e.x); + x_points.sort_unstable_by_key(|p| p.x); let mut groups = vec![Vec::new(); self.len()]; let capacity = segments.len().ilog2() as usize; @@ -168,10 +169,10 @@ impl SteinerInference for [IntShape] { } } -impl ShapeEdge { +impl ShapeEdge { #[inline] - fn not_contains(&self, p: IntPoint) -> bool { - Triangle::is_not_line_point(self.a, p, self.b) + fn not_contains(&self, p: IntPoint) -> bool { + Triangle::is_not_line(self.a, p, self.b) } #[inline] @@ -180,9 +181,9 @@ impl ShapeEdge { } } -impl VEdge { +impl VEdge { #[inline] - fn new(a: IntPoint, b: IntPoint) -> Self { + fn new(a: IntPoint, b: IntPoint) -> Self { let (min_y, max_y) = if a.y < b.y { (a.y, b.y) } else { (b.y, a.y) }; Self { @@ -193,7 +194,7 @@ impl VEdge { } #[inline] - fn contains(&self, y: i32) -> bool { + fn contains(&self, y: I) -> bool { self.min_y <= y && y <= self.max_y } } @@ -205,7 +206,7 @@ mod tests { use i_overlay::i_float::int::point::IntPoint; use i_overlay::i_shape::int::path::IntPath; - fn path(slice: &[[i32; 2]]) -> IntPath { + fn path(slice: &[[i32; 2]]) -> IntPath { slice.iter().map(|p| IntPoint::new(p[0], p[1])).collect() } diff --git a/iTriangle/src/int/custom.rs b/iTriangle/src/int/custom.rs index b4b3384..3976467 100644 --- a/iTriangle/src/int/custom.rs +++ b/iTriangle/src/int/custom.rs @@ -2,8 +2,11 @@ use crate::int::solver::ShapesSolver; use crate::int::solver::{ContourSolver, ShapeSolver}; use crate::int::triangulation::RawIntTriangulation; use crate::int::validation::Validation; +use i_key_sort::sort::key::SortKey; +use i_overlay::i_float::int::number::int::IntNumber; use i_overlay::i_float::int::point::IntPoint; use i_overlay::i_shape::int::shape::{IntContour, IntShape, IntShapes}; +use i_tree::{Expiration, LayoutNumber}; /// A trait for performing triangulation with custom validation settings. /// @@ -14,62 +17,68 @@ use i_overlay::i_shape::int::shape::{IntContour, IntShape, IntShapes}; /// - [`IntContour`] /// - [`IntShape`] /// - [`IntShapes`] -pub trait IntCustomTriangulatable { +pub trait IntCustomTriangulatable { /// Triangulates the shape(s) using the given [`Validation`] settings. - fn custom_triangulate(&self, validation: Validation) -> RawIntTriangulation; + fn custom_triangulate(&self, validation: Validation) -> RawIntTriangulation; /// Triangulates the shape(s), injecting Steiner points and using the specified [`Validation`] settings. fn custom_triangulate_with_steiner_points( &self, - points: &[IntPoint], - validation: Validation, - ) -> RawIntTriangulation; + points: &[IntPoint], + validation: Validation, + ) -> RawIntTriangulation; } -impl IntCustomTriangulatable for IntContour { +impl IntCustomTriangulatable + for IntContour +{ #[inline] - fn custom_triangulate(&self, validation: Validation) -> RawIntTriangulation { + fn custom_triangulate(&self, validation: Validation) -> RawIntTriangulation { ContourSolver::triangulate(validation, self) } #[inline] fn custom_triangulate_with_steiner_points( &self, - points: &[IntPoint], - validation: Validation, - ) -> RawIntTriangulation { + points: &[IntPoint], + validation: Validation, + ) -> RawIntTriangulation { ContourSolver::triangulate_with_steiner_points(validation, self, points) } } -impl IntCustomTriangulatable for IntShape { +impl IntCustomTriangulatable + for IntShape +{ #[inline] - fn custom_triangulate(&self, validation: Validation) -> RawIntTriangulation { + fn custom_triangulate(&self, validation: Validation) -> RawIntTriangulation { ShapeSolver::triangulate(validation, self) } #[inline] fn custom_triangulate_with_steiner_points( &self, - points: &[IntPoint], - validation: Validation, - ) -> RawIntTriangulation { + points: &[IntPoint], + validation: Validation, + ) -> RawIntTriangulation { ShapeSolver::triangulate_with_steiner_points(validation, self, points) } } -impl IntCustomTriangulatable for IntShapes { +impl IntCustomTriangulatable + for IntShapes +{ #[inline] - fn custom_triangulate(&self, validation: Validation) -> RawIntTriangulation { + fn custom_triangulate(&self, validation: Validation) -> RawIntTriangulation { ShapesSolver::triangulate(validation, self) } #[inline] fn custom_triangulate_with_steiner_points( &self, - points: &[IntPoint], - validation: Validation, - ) -> RawIntTriangulation { + points: &[IntPoint], + validation: Validation, + ) -> RawIntTriangulation { ShapesSolver::triangulate_with_steiner_points(validation, self, points) } } diff --git a/iTriangle/src/int/earcut/earcut_64.rs b/iTriangle/src/int/earcut/earcut_64.rs index 01abc4f..de03319 100644 --- a/iTriangle/src/int/earcut/earcut_64.rs +++ b/iTriangle/src/int/earcut/earcut_64.rs @@ -5,18 +5,23 @@ use crate::int::earcut::util::{ABCExcludeResult, Abc, AB}; use crate::int::meta::TrianglesCount; use crate::int::triangulation::{IndexType, IntTriangulation, RawIntTriangulation}; use core::cmp::Ordering; +use i_overlay::i_float::int::number::int::IntNumber; +use i_overlay::i_float::int::number::wide_int::WideIntNumber; use i_overlay::i_float::int::point::IntPoint; use i_overlay::i_float::int::rect::IntRect; use i_overlay::i_shape::util::reserve::Reserve; -pub(super) trait EarcutStore { - fn collect_triangles(&mut self, contour: &[IntPoint], start: usize, bits: u64, count: u32); +pub(super) trait EarcutStore { + fn collect_triangles(&mut self, contour: &[IntPoint], start: usize, bits: u64, count: u32); } -pub trait Earcut64 { - fn earcut_flat_triangulate_into(&self, triangulation: &mut IntTriangulation); +pub trait Earcut64 { + fn earcut_flat_triangulate_into( + &self, + triangulation: &mut IntTriangulation, + ); - fn earcut_net_triangulate_into(&self, triangulation: &mut RawIntTriangulation); + fn earcut_net_triangulate_into(&self, triangulation: &mut RawIntTriangulation); } /// Implements ear clipping triangulation for contours (max 64 points) @@ -26,8 +31,11 @@ pub trait Earcut64 { /// 2. Validate ears against inner points /// 3. Clip valid ears and triangulate /// 4. Repeat until 3 points remain -impl Earcut64 for [IntPoint] { - fn earcut_flat_triangulate_into(&self, triangulation: &mut IntTriangulation) { +impl Earcut64 for [IntPoint] { + fn earcut_flat_triangulate_into( + &self, + triangulation: &mut IntTriangulation, + ) { debug_assert!(self.len() <= 64); triangulation @@ -41,7 +49,7 @@ impl Earcut64 for [IntPoint] { triangulation.points.extend_from_slice(self); } - fn earcut_net_triangulate_into(&self, triangulation: &mut RawIntTriangulation) { + fn earcut_net_triangulate_into(&self, triangulation: &mut RawIntTriangulation) { debug_assert!(self.len() <= 64); triangulation @@ -62,14 +70,14 @@ enum ConvexSearchResult { None, } -struct EarcutSolver<'a, S> { +struct EarcutSolver<'a, I: IntNumber, S> { store: S, - contour: &'a [IntPoint], + contour: &'a [IntPoint], available: u64, } -impl<'a, S: EarcutStore> EarcutSolver<'a, S> { - fn new(contour: &'a [IntPoint], store: S) -> Self { +impl<'a, I: IntNumber, S: EarcutStore> EarcutSolver<'a, I, S> { + fn new(contour: &'a [IntPoint], store: S) -> Self { Self { store, contour, @@ -78,7 +86,7 @@ impl<'a, S: EarcutStore> EarcutSolver<'a, S> { } #[inline(always)] - fn point(&self, index: usize) -> &IntPoint { + fn point(&self, index: usize) -> &IntPoint { unsafe { self.contour.get_unchecked(index) } } @@ -146,16 +154,16 @@ impl<'a, S: EarcutStore> EarcutSolver<'a, S> { let mut bi = self.available.next_wrapped_index(ai); let mut b = *self.point(bi); - let mut ab = b.subtract(a); + let mut ab = b - a; for _ in 0..max_count { let ci = self.available.next_wrapped_index(bi); let c = *self.point(ci); - let bc = c.subtract(b); + let bc = c - b; let cross = ab.cross_product(bc); - if cross > 0 { + if cross > I::Wide::ZERO { return ai; } @@ -177,7 +185,7 @@ impl<'a, S: EarcutStore> EarcutSolver<'a, S> { let b = *self.point(i1); let mut i = i1; - let ab = b.subtract(a); + let ab = b - a; let mut ce = ab; // the prev vector let mut cj = *self.point(i); @@ -187,10 +195,10 @@ impl<'a, S: EarcutStore> EarcutSolver<'a, S> { cj = *self.point(j); // appended edge - let cc = cj.subtract(ci); + let cc = cj - ci; // ca - slice edge - let ca = a.subtract(cj); + let ca = a - cj; // cab < 180 let cross_a = ab.cross_product(ca); @@ -201,7 +209,7 @@ impl<'a, S: EarcutStore> EarcutSolver<'a, S> { // cce <= 180 let cross_v = cc.cross_product(ce); - if cross_a >= 0 || cross_c <= 0 || cross_v > 0 { + if cross_a >= I::Wide::ZERO || cross_c <= I::Wide::ZERO || cross_v > I::Wide::ZERO { if i == i1 { // empty ear return ConvexSearchResult::None; @@ -209,7 +217,7 @@ impl<'a, S: EarcutStore> EarcutSolver<'a, S> { return ConvexSearchResult::Circle; } - if cross_a == 0 && a == cj { + if cross_a == I::Wide::ZERO && a == cj { return ConvexSearchResult::Index(j, true); } @@ -290,9 +298,9 @@ impl<'a, S: EarcutStore> EarcutSolver<'a, S> { #[inline(always)] fn triangle_contains( &self, - a: IntPoint, - b: IntPoint, - c: IntPoint, + a: IntPoint, + b: IntPoint, + c: IntPoint, ear_indices: u64, same_point: bool, ) -> bool { @@ -318,25 +326,25 @@ impl<'a, S: EarcutStore> EarcutSolver<'a, S> { #[inline(always)] fn fast_filter( &self, - a: IntPoint, - b: IntPoint, - c: IntPoint, - e: IntPoint, + a: IntPoint, + b: IntPoint, + c: IntPoint, + e: IntPoint, ear_indices: u64, same_point: bool, - ) -> Option { + ) -> Option> { // filter by bounding box and first triangle // return None if first triangle is not possible let rect = self.bounding_box(ear_indices); // first triangle - let ab = b.subtract(a); - let bc = c.subtract(b); - let ac = c.subtract(a); + let ab = b - a; + let bc = c - b; + let ac = c - a; // last edge - let ee = a.subtract(e); + let ee = a - e; let mut bits = self.available & !ear_indices; let mut heap = ClockOrderHeap::with_center(a); @@ -350,11 +358,11 @@ impl<'a, S: EarcutStore> EarcutSolver<'a, S> { continue; } - let ap = p.subtract(a); + let ap = p - a; // check last edge let cross = ap.cross_product(ee); - match cross.cmp(&0) { + match cross.cmp(&I::Wide::ZERO) { Ordering::Less => {} Ordering::Equal => { if same_point || !AB::contains(a, e, p) { @@ -366,23 +374,23 @@ impl<'a, S: EarcutStore> EarcutSolver<'a, S> { // check ab let cross = ap.cross_product(ab); - if cross >= 0 { + if cross >= I::Wide::ZERO { continue; } - let cp = p.subtract(c); + let cp = p - c; // check bc let cross = cp.cross_product(bc); - if cross >= 0 { + if cross >= I::Wide::ZERO { continue; } // check ac let cross = ap.cross_product(ac); - match cross.cmp(&0) { + match cross.cmp(&I::Wide::ZERO) { Ordering::Less => {} Ordering::Equal => { if AB::contains(a, c, p) { @@ -401,7 +409,7 @@ impl<'a, S: EarcutStore> EarcutSolver<'a, S> { } #[inline(always)] - fn bounding_box(&self, indices: u64) -> IntRect { + fn bounding_box(&self, indices: u64) -> IntRect { let mut bits = indices; let i0 = bits.trailing_zeros() as usize; bits &= !(1 << i0); @@ -415,38 +423,38 @@ impl<'a, S: EarcutStore> EarcutSolver<'a, S> { } } -struct Ear { - a: IntPoint, +struct Ear { + a: IntPoint, active_index: usize, - active_point: IntPoint, + active_point: IntPoint, start: usize, indices: u64, } -impl Ear { +impl Ear { #[inline(always)] - fn cut(&mut self, p: IntPoint, contour: &[IntPoint]) -> bool { + fn cut(&mut self, p: IntPoint, contour: &[IntPoint]) -> bool { let mut i = self.active_index; - let pa = p.subtract(self.a); + let pa = p - self.a; while i != self.start { i = self.indices.next_wrapped_index(i); let c = *unsafe { contour.get_unchecked(i) }; - let ac = c.subtract(self.a); + let ac = c - self.a; let cross = ac.cross_product(pa); - match cross.cmp(&0) { + match cross.cmp(&I::Wide::ZERO) { Ordering::Less => { - let pc = c.subtract(p); - let bc = c.subtract(self.active_point); - return bc.cross_product(pc) < 0; + let pc = c - p; + let bc = c - self.active_point; + return bc.cross_product(pc) < I::Wide::ZERO; } Ordering::Equal => { - let pc = c.subtract(p); - let bc = c.subtract(self.active_point); - let inside = bc.cross_product(pc) < 0; + let pc = c - p; + let bc = c - self.active_point; + let inside = bc.cross_product(pc) < I::Wide::ZERO; return inside && AB::contains(self.a, c, p); } Ordering::Greater => {} @@ -663,7 +671,7 @@ mod tests { IntPoint::new(5, 1), // inside first triangle ]; - let mut triangulation = IntTriangulation::::empty(); + let mut triangulation = IntTriangulation::::empty(); let solver = EarcutSolver::new(&contour, FlatEarcutStore::new(&mut triangulation)); let queue = solver.fast_filter( @@ -683,7 +691,7 @@ mod tests { IntPoint::new(5, 5), // inside AC ]; - let mut triangulation = IntTriangulation::::empty(); + let mut triangulation = IntTriangulation::::empty(); let solver = EarcutSolver::new(&contour, FlatEarcutStore::new(&mut triangulation)); let queue = solver.fast_filter( @@ -703,7 +711,7 @@ mod tests { IntPoint::new(0, 0), // P == A ]; - let mut triangulation = IntTriangulation::::empty(); + let mut triangulation = IntTriangulation::::empty(); let solver = EarcutSolver::new(&contour, FlatEarcutStore::new(&mut triangulation)); let queue = solver @@ -725,7 +733,7 @@ mod tests { IntPoint::new(15, 15), // on AC but outside ]; - let mut triangulation = IntTriangulation::::empty(); + let mut triangulation = IntTriangulation::::empty(); let solver = EarcutSolver::new(&contour, FlatEarcutStore::new(&mut triangulation)); let queue = solver @@ -747,7 +755,7 @@ mod tests { IntPoint::new(1, 9), // inside second triangle ]; - let mut triangulation = IntTriangulation::::empty(); + let mut triangulation = IntTriangulation::::empty(); let solver = EarcutSolver::new(&contour, FlatEarcutStore::new(&mut triangulation)); let queue = solver @@ -774,7 +782,7 @@ mod tests { IntPoint::new(-15, 5), ]; - fn new_ear() -> Ear { + fn new_ear() -> Ear { Ear { a: IntPoint::new(-15, -5), active_index: 2, @@ -972,7 +980,7 @@ mod tests { IntPoint::new(-5, 20), ]; - let mut triangulation = IntTriangulation::::empty(); + let mut triangulation = IntTriangulation::::empty(); let solver = EarcutSolver::new(&contour, FlatEarcutStore::new(&mut triangulation)); let end = solver.validate_and_shrink_ear(0, 4, false).unwrap(); assert_eq!(end, 4); @@ -1668,9 +1676,9 @@ mod tests { } } - fn single_test(contour: &IntContour) { + fn single_test(contour: &IntContour) { // flat - let mut flat = IntTriangulation::::default(); + let mut flat = IntTriangulation::::default(); contour.earcut_flat_triangulate_into(&mut flat); flat.validate(contour.area_two()); @@ -1685,8 +1693,8 @@ mod tests { assert!(net.triangles.len() / 3 <= contour.len() - 2); } - fn roll_test(contour: &IntContour) { - let mut triangulation = IntTriangulation::::default(); + fn roll_test(contour: &IntContour) { + let mut triangulation = IntTriangulation::::default(); let mut path = contour.to_vec(); for _ in 0..path.len() { @@ -1705,7 +1713,7 @@ mod tests { } } - fn random(radius: i32, n: usize) -> IntPath { + fn random(radius: i32, n: usize) -> IntPath { let a = radius / 2; let mut points = Vec::with_capacity(n); let mut rng = rand::rng(); diff --git a/iTriangle/src/int/earcut/flat.rs b/iTriangle/src/int/earcut/flat.rs index f8da09e..8680276 100644 --- a/iTriangle/src/int/earcut/flat.rs +++ b/iTriangle/src/int/earcut/flat.rs @@ -1,29 +1,30 @@ use crate::int::earcut::earcut_64::{Bit, EarcutStore}; use crate::int::triangulation::{IndexType, IntTriangulation}; +use i_overlay::i_float::int::number::int::IntNumber; use i_overlay::i_float::int::point::IntPoint; -pub(super) struct FlatEarcutStore<'a, I> { - triangulation: &'a mut IntTriangulation, +pub(super) struct FlatEarcutStore<'a, I: IntNumber, N: IndexType> { + triangulation: &'a mut IntTriangulation, } -impl<'a, I: IndexType> FlatEarcutStore<'a, I> { +impl<'a, I: IntNumber, N: IndexType> FlatEarcutStore<'a, I, N> { #[inline] - pub(super) fn new(triangulation: &'a mut IntTriangulation) -> Self { + pub(super) fn new(triangulation: &'a mut IntTriangulation) -> Self { Self { triangulation } } } -impl EarcutStore for FlatEarcutStore<'_, I> { +impl EarcutStore for FlatEarcutStore<'_, I, N> { #[inline] - fn collect_triangles(&mut self, _: &[IntPoint], start: usize, bits: u64, count: u32) { + fn collect_triangles(&mut self, _: &[IntPoint], start: usize, bits: u64, count: u32) { let mut i = start; - let a = unsafe { I::try_from(i).unwrap_unchecked() }; + let a = unsafe { N::try_from(i).unwrap_unchecked() }; i = bits.next_wrapped_index(i); - let mut b = unsafe { I::try_from(i).unwrap_unchecked() }; + let mut b = unsafe { N::try_from(i).unwrap_unchecked() }; for _ in 0..count { i = bits.next_wrapped_index(i); - let c = unsafe { I::try_from(i).unwrap_unchecked() }; + let c = unsafe { N::try_from(i).unwrap_unchecked() }; self.triangulation.indices.push(a); self.triangulation.indices.push(b); self.triangulation.indices.push(c); diff --git a/iTriangle/src/int/earcut/heap.rs b/iTriangle/src/int/earcut/heap.rs index 75e1070..c929df8 100644 --- a/iTriangle/src/int/earcut/heap.rs +++ b/iTriangle/src/int/earcut/heap.rs @@ -1,16 +1,18 @@ use core::cmp::Ordering; use core::ptr; +use i_overlay::i_float::int::number::int::IntNumber; use i_overlay::i_float::int::point::IntPoint; use i_overlay::i_float::triangle::Triangle; const CLOCK_ORDER_HEAP_LEN: usize = 3; -pub(super) type ClockOrderHeap = FixedHeap; +pub(super) type ClockOrderHeap = + FixedHeap, ClockOrderCompare, CLOCK_ORDER_HEAP_LEN>; -impl ClockOrderHeap { +impl ClockOrderHeap { #[inline(always)] - pub(super) fn with_center(center: IntPoint) -> Self { - Self::new(ClockOrderCompare { center }) + pub(super) fn with_center(center: IntPoint) -> Self { + Self::new(ClockOrderCompare { center }, IntPoint::ZERO) } } @@ -18,14 +20,14 @@ pub(super) trait Compare { fn compare(&self, a: &T, b: &T) -> Ordering; } -pub(super) struct ClockOrderCompare { - center: IntPoint, +pub(super) struct ClockOrderCompare { + center: IntPoint, } -impl Compare for ClockOrderCompare { +impl Compare> for ClockOrderCompare { #[inline(always)] - fn compare(&self, a: &IntPoint, b: &IntPoint) -> Ordering { - Triangle::clock_order_point(self.center, *a, *b) + fn compare(&self, a: &IntPoint, b: &IntPoint) -> Ordering { + Triangle::clock_order(self.center, *a, *b) } } @@ -36,13 +38,13 @@ pub(super) struct FixedHeap, const N: usize> { buffer: [T; N], } -impl, const N: usize> FixedHeap { +impl, const N: usize> FixedHeap { #[inline(always)] - pub(super) fn new(comparator: C) -> Self { + pub(super) fn new(comparator: C, empty: T) -> Self { Self { count: 0, overflow: false, - buffer: [T::default(); N], + buffer: [empty; N], comparator, } } @@ -174,7 +176,7 @@ mod tests { #[test] fn test_min_heap_0() { - let mut heap = FixedHeap::::new(Min); + let mut heap = FixedHeap::::new(Min, 0); for &v in &[30, 10, 50, 20] { heap.add(v); } @@ -185,7 +187,7 @@ mod tests { #[test] fn test_min_heap_1() { - let mut heap = FixedHeap::::new(Min); + let mut heap = FixedHeap::::new(Min, 0); for &v in &[5, 5, 4, 4, 3, 2, 1, 0, 0, 0] { heap.add(v); } @@ -196,7 +198,7 @@ mod tests { #[test] fn test_max_heap() { - let mut heap = FixedHeap::::new(Max); + let mut heap = FixedHeap::::new(Max, 0); for &v in &[30, 10, 50, 20] { heap.add(v); } @@ -224,7 +226,7 @@ mod tests { heap.sort_in_place(); - points.sort_unstable_by(|a, b| Triangle::clock_order_point(c, *b, *a)); + points.sort_unstable_by(|a, b| Triangle::clock_order(c, *b, *a)); assert_eq!( heap.buffer[0..CLOCK_ORDER_HEAP_LEN], @@ -251,7 +253,7 @@ mod tests { heap.sort_in_place(); - points.sort_unstable_by(|a, b| Triangle::clock_order_point(c, *b, *a)); + points.sort_unstable_by(|a, b| Triangle::clock_order(c, *b, *a)); assert_eq!( heap.buffer[0..CLOCK_ORDER_HEAP_LEN], @@ -268,7 +270,7 @@ mod tests { heap.add(points[1]); heap.sort_in_place(); - points.sort_unstable_by(|a, b| Triangle::clock_order_point(c, *b, *a)); + points.sort_unstable_by(|a, b| Triangle::clock_order(c, *b, *a)); assert_eq!(heap.buffer[0..2], points); } @@ -294,7 +296,7 @@ mod tests { heap.sort_in_place(); - points.sort_unstable_by(|a, b| Triangle::clock_order_point(c, *b, *a)); + points.sort_unstable_by(|a, b| Triangle::clock_order(c, *b, *a)); assert_eq!( heap.buffer[0..CLOCK_ORDER_HEAP_LEN], diff --git a/iTriangle/src/int/earcut/net.rs b/iTriangle/src/int/earcut/net.rs index a1deb1f..88410ad 100644 --- a/iTriangle/src/int/earcut/net.rs +++ b/iTriangle/src/int/earcut/net.rs @@ -3,6 +3,7 @@ use crate::geom::triangle::IntTriangle; use crate::int::earcut::earcut_64::{Bit, EarcutStore}; use crate::int::triangulation::RawIntTriangulation; use alloc::vec::Vec; +use i_overlay::i_float::int::number::int::IntNumber; use i_overlay::i_float::int::point::IntPoint; struct TriangleHandler { @@ -51,15 +52,15 @@ impl EdgePool { } } -pub(super) struct NetEarcutStore<'a> { - triangulation: &'a mut RawIntTriangulation, +pub(super) struct NetEarcutStore<'a, I: IntNumber> { + triangulation: &'a mut RawIntTriangulation, pool: EdgePool, last: usize, } -impl<'a> NetEarcutStore<'a> { +impl<'a, I: IntNumber> NetEarcutStore<'a, I> { #[inline] - pub(super) fn new(count: usize, triangulation: &'a mut RawIntTriangulation) -> Self { + pub(super) fn new(count: usize, triangulation: &'a mut RawIntTriangulation) -> Self { Self { last: count - 1, triangulation, @@ -70,9 +71,9 @@ impl<'a> NetEarcutStore<'a> { } } -impl EarcutStore for NetEarcutStore<'_> { +impl EarcutStore for NetEarcutStore<'_, I> { #[inline] - fn collect_triangles(&mut self, contour: &[IntPoint], start: usize, bits: u64, count: u32) { + fn collect_triangles(&mut self, contour: &[IntPoint], start: usize, bits: u64, count: u32) { let ai = start; let a = IndexPoint::new(ai, contour[ai]); @@ -97,7 +98,7 @@ impl EarcutStore for NetEarcutStore<'_> { } } -impl NetEarcutStore<'_> { +impl NetEarcutStore<'_, I> { #[inline] fn get_or_put(&mut self, i0: usize, i1: usize, t: usize, v: usize) -> usize { // is edge inner or outer diff --git a/iTriangle/src/int/earcut/util.rs b/iTriangle/src/int/earcut/util.rs index 42a1e96..cdb42af 100644 --- a/iTriangle/src/int/earcut/util.rs +++ b/iTriangle/src/int/earcut/util.rs @@ -1,6 +1,8 @@ use core::cmp::Ordering; -use i_overlay::i_float::fix_vec::FixVec; +use i_overlay::i_float::int::number::int::IntNumber; +use i_overlay::i_float::int::number::wide_int::WideIntNumber; use i_overlay::i_float::int::point::IntPoint; +use i_overlay::i_float::int::vector::IntVector as FixVec; #[derive(PartialEq, Eq)] pub(super) enum ABCExcludeResult { @@ -10,21 +12,21 @@ pub(super) enum ABCExcludeResult { } // a, b, c - counter clock wised points -pub(super) struct Abc { - a: IntPoint, - b: IntPoint, - c: IntPoint, - ab: FixVec, - bc: FixVec, - ca: FixVec, +pub(super) struct Abc { + a: IntPoint, + b: IntPoint, + c: IntPoint, + ab: FixVec, + bc: FixVec, + ca: FixVec, } -impl Abc { +impl Abc { #[inline(always)] - pub(super) fn new(a: IntPoint, b: IntPoint, c: IntPoint) -> Self { - let ab = b.subtract(a); - let bc = c.subtract(b); - let ca = a.subtract(c); + pub(super) fn new(a: IntPoint, b: IntPoint, c: IntPoint) -> Self { + let ab = b - a; + let bc = c - b; + let ca = a - c; Self { a, b, @@ -36,43 +38,43 @@ impl Abc { } #[inline(always)] - pub(super) fn contains(&self, p: IntPoint) -> bool { - let ap = p.subtract(self.a); + pub(super) fn contains(&self, p: IntPoint) -> bool { + let ap = p - self.a; let a_cross = ap.cross_product(self.ab); - if a_cross >= 0 { + if a_cross >= I::Wide::ZERO { return false; } - let bp = p.subtract(self.b); + let bp = p - self.b; let b_cross = bp.cross_product(self.bc); - if b_cross >= 0 { + if b_cross >= I::Wide::ZERO { return false; } - let cp = p.subtract(self.c); + let cp = p - self.c; let c_cross = cp.cross_product(self.ca); - c_cross < 0 + c_cross < I::Wide::ZERO } #[inline(always)] - pub(super) fn contains_exclude_ca(&self, p: IntPoint) -> ABCExcludeResult { - let ap = p.subtract(self.a); + pub(super) fn contains_exclude_ca(&self, p: IntPoint) -> ABCExcludeResult { + let ap = p - self.a; let a_cross = ap.cross_product(self.ab); - if a_cross >= 0 { + if a_cross >= I::Wide::ZERO { return ABCExcludeResult::Outside; } - let bp = p.subtract(self.b); + let bp = p - self.b; let b_cross = bp.cross_product(self.bc); - if b_cross >= 0 { + if b_cross >= I::Wide::ZERO { return ABCExcludeResult::Outside; } - let cp = p.subtract(self.c); + let cp = p - self.c; let c_cross = cp.cross_product(self.ca); - match c_cross.cmp(&0) { + match c_cross.cmp(&I::Wide::ZERO) { Ordering::Less => ABCExcludeResult::Inside, Ordering::Equal => { if AB::contains(self.a, self.c, p) { @@ -90,13 +92,13 @@ pub(super) struct AB; impl AB { #[inline(always)] - pub(super) fn contains(a: IntPoint, b: IntPoint, p: IntPoint) -> bool { + pub(super) fn contains(a: IntPoint, b: IntPoint, p: IntPoint) -> bool { // a, b, p already on one line // not including ends - let ap = a.subtract(p); - let bp = b.subtract(p); + let ap = a - p; + let bp = b - p; // must have opposite direction - ap.dot_product(bp) < 0 + ap.dot_product(bp) < I::Wide::ZERO } } diff --git a/iTriangle/src/int/locator.rs b/iTriangle/src/int/locator.rs index 63de362..b17d0de 100644 --- a/iTriangle/src/int/locator.rs +++ b/iTriangle/src/int/locator.rs @@ -1,6 +1,9 @@ use alloc::vec; use alloc::vec::Vec; +use i_key_sort::sort::key::SortKey; use i_key_sort::sort::two_keys::TwoKeysSort; +use i_overlay::i_float::int::number::int::IntNumber; +use i_overlay::i_float::int::number::wide_int::WideIntNumber; use i_overlay::i_float::int::rect::IntRect; use i_overlay::i_shape::int::IntPoint; @@ -9,22 +12,23 @@ use crate::{ location::{PointLocationInTriangulation, TriangleIndex}, }; -pub trait IntPointInTriangulationLocator { - fn locate_points(&self, points: &[IntPoint]) -> Vec; +pub trait IntPointInTriangulationLocator { + fn locate_points(&self, points: &[IntPoint]) -> Vec; } -impl IntPointInTriangulationLocator for I +impl IntPointInTriangulationLocator for T where - I: Iterator + Clone, + I: IntNumber + SortKey, + T: Iterator; 3]> + Clone, { - fn locate_points(&self, points: &[IntPoint]) -> Vec { + fn locate_points(&self, points: &[IntPoint]) -> Vec { locate_points_in_triangles(self.clone(), points) } } -fn locate_points_in_triangles( - triangles: impl Iterator, - points: &[IntPoint], +fn locate_points_in_triangles( + triangles: impl Iterator; 3]>, + points: &[IntPoint], ) -> Vec { let mut result = vec![PointLocationInTriangulation::Outside; points.len()]; let mut sorted_points: Vec<_> = points @@ -97,9 +101,9 @@ fn locate_points_in_triangles( } #[derive(Clone, Copy)] -struct IndexedPoint { +struct IndexedPoint { index: usize, - point: IntPoint, + point: IntPoint, } #[derive(Clone, Copy, Debug, Eq, PartialEq)] @@ -111,39 +115,33 @@ enum PointLocationInTriangle { } trait IntPointInTriangleLocator { - fn locate_point(&self, point: IntPoint) -> PointLocationInTriangle; + type Int: IntNumber; + fn locate_point(&self, point: IntPoint) -> PointLocationInTriangle; - fn boundary(&self) -> IntRect; + fn boundary(&self) -> IntRect; } -impl IntPointInTriangleLocator for [IntPoint; 3] { +impl IntPointInTriangleLocator for [IntPoint; 3] { + type Int = I; + #[inline] - fn locate_point(&self, point: IntPoint) -> PointLocationInTriangle { + fn locate_point(&self, point: IntPoint) -> PointLocationInTriangle { let [p0, p1, p2] = *self; if point == p0 || point == p1 || point == p2 { return PointLocationInTriangle::OnVertex; } - let px = point.x as i64; - let py = point.y as i64; - let x0 = p0.x as i64; - let y0 = p0.y as i64; - let x1 = p1.x as i64; - let y1 = p1.y as i64; - let x2 = p2.x as i64; - let y2 = p2.y as i64; - - let q0 = (px - x1) * (y0 - y1) - (py - y1) * (x0 - x1); - let q1 = (px - x2) * (y1 - y2) - (py - y2) * (x1 - x2); - let q2 = (px - x0) * (y2 - y0) - (py - y0) * (x2 - x0); + let q0 = (point - p1).cross_product(p0 - p1); + let q1 = (point - p2).cross_product(p1 - p2); + let q2 = (point - p0).cross_product(p2 - p0); - let has_neg = q0 < 0 || q1 < 0 || q2 < 0; - let has_pos = q0 > 0 || q1 > 0 || q2 > 0; + let has_neg = q0 < I::Wide::ZERO || q1 < I::Wide::ZERO || q2 < I::Wide::ZERO; + let has_pos = q0 > I::Wide::ZERO || q1 > I::Wide::ZERO || q2 > I::Wide::ZERO; if has_neg && has_pos { PointLocationInTriangle::Outside - } else if q0 == 0 || q1 == 0 || q2 == 0 { + } else if q0 == I::Wide::ZERO || q1 == I::Wide::ZERO || q2 == I::Wide::ZERO { PointLocationInTriangle::OnEdge } else { PointLocationInTriangle::Inside @@ -151,7 +149,7 @@ impl IntPointInTriangleLocator for [IntPoint; 3] { } #[inline] - fn boundary(&self) -> IntRect { + fn boundary(&self) -> IntRect { let mut rect = IntRect::with_point(self[0]); rect.unsafe_add_point(&self[1]); rect.unsafe_add_point(&self[2]); @@ -159,16 +157,18 @@ impl IntPointInTriangleLocator for [IntPoint; 3] { } } -impl IntTriangulation { +impl IntTriangulation { #[inline] - pub fn locate_points(&self, points: &[IntPoint]) -> Vec { + pub fn locate_points(&self, points: &[IntPoint]) -> Vec { locate_points_in_triangles(self.triangles(), points) } } -impl IntPointInTriangulationLocator for IntTriangulation { +impl IntPointInTriangulationLocator + for IntTriangulation +{ #[inline] - fn locate_points(&self, points: &[IntPoint]) -> Vec { + fn locate_points(&self, points: &[IntPoint]) -> Vec { IntTriangulation::locate_points(self, points) } } @@ -184,7 +184,7 @@ mod tests { use i_overlay::i_shape::int::IntPoint; use i_overlay::i_shape::int_path; - fn square_triangulation() -> IntTriangulation { + fn square_triangulation() -> IntTriangulation { IntTriangulation { points: vec![ IntPoint::new(0, 0), @@ -225,7 +225,7 @@ mod tests { fill_rule: Default::default(), options: IntOverlayOptions::keep_all_points(), }; - let mut triangulator = IntTriangulator::::new(32, validation, Default::default()); + let mut triangulator = IntTriangulator::::new(32, validation, Default::default()); triangulator.delaunay = true; let triangulation = triangulator.triangulate_contour(&path); diff --git a/iTriangle/src/int/meta.rs b/iTriangle/src/int/meta.rs index 5732d1b..29a5764 100644 --- a/iTriangle/src/int/meta.rs +++ b/iTriangle/src/int/meta.rs @@ -1,3 +1,4 @@ +use i_overlay::i_float::int::number::int::IntNumber; use i_overlay::i_float::int::point::IntPoint; use i_overlay::i_shape::flat::buffer::FlatContoursBuffer; use i_overlay::i_shape::int::shape::IntContour; @@ -11,7 +12,7 @@ pub(crate) trait TrianglesCount { fn triangles_count(&self, points_count: usize) -> usize; } -impl TrianglesCount for FlatContoursBuffer { +impl TrianglesCount for FlatContoursBuffer { #[inline] fn triangles_count(&self, points_count: usize) -> usize { let mut count = 2 * points_count; @@ -21,7 +22,7 @@ impl TrianglesCount for FlatContoursBuffer { } } -impl TrianglesCount for [IntContour] { +impl TrianglesCount for [IntContour] { #[inline] fn triangles_count(&self, points_count: usize) -> usize { let mut count = 2 * points_count; @@ -32,7 +33,7 @@ impl TrianglesCount for [IntContour] { } } -impl TrianglesCount for [IntPoint] { +impl TrianglesCount for [IntPoint] { #[inline] fn triangles_count(&self, points_count: usize) -> usize { self.len() - 2 + 2 * points_count @@ -43,7 +44,7 @@ pub(crate) trait MeshMetaProvider { fn meta(&self, points_count: usize) -> MeshMeta; } -impl MeshMetaProvider for [IntPoint] { +impl MeshMetaProvider for [IntPoint] { #[inline] fn meta(&self, points_count: usize) -> MeshMeta { MeshMeta { @@ -53,7 +54,7 @@ impl MeshMetaProvider for [IntPoint] { } } -impl MeshMetaProvider for [IntContour] { +impl MeshMetaProvider for [IntContour] { #[inline] fn meta(&self, points_count: usize) -> MeshMeta { let mut triangles_count = 2 * points_count; diff --git a/iTriangle/src/int/monotone/chain/builder.rs b/iTriangle/src/int/monotone/chain/builder.rs index 68b1957..aab4eab 100644 --- a/iTriangle/src/int/monotone/chain/builder.rs +++ b/iTriangle/src/int/monotone/chain/builder.rs @@ -1,6 +1,8 @@ use crate::int::monotone::chain::vertex::ChainVertex; use alloc::vec::Vec; +use i_key_sort::sort::key::SortKey; use i_key_sort::sort::two_keys::TwoKeysSort; +use i_overlay::i_float::int::number::int::IntNumber; use i_overlay::i_float::int::point::IntPoint; use i_overlay::i_float::triangle::Triangle; use i_overlay::i_shape::flat::buffer::FlatContoursBuffer; @@ -10,7 +12,10 @@ use i_overlay::i_shape::util::reserve::Reserve; pub(crate) struct ChainBuilder; impl ChainBuilder { - pub(crate) fn flat_to_vertices(flat: &FlatContoursBuffer, vertices: &mut Vec) { + pub(crate) fn flat_to_vertices( + flat: &FlatContoursBuffer, + vertices: &mut Vec>, + ) { vertices.clear(); for range in flat.ranges.iter() { let contour = &flat.points[range.clone()]; @@ -19,10 +24,10 @@ impl ChainBuilder { vertices.sort_by_swipe_line(); } - pub(crate) fn shape_to_vertices( - shape: &IntShape, - points: Option<&[IntPoint]>, - vertices: &mut Vec, + pub(crate) fn shape_to_vertices( + shape: &IntShape, + points: Option<&[IntPoint]>, + vertices: &mut Vec>, ) { vertices.clear(); for contour in shape.iter() { @@ -34,10 +39,10 @@ impl ChainBuilder { vertices.sort_by_swipe_line(); } - pub(crate) fn contour_to_vertices( - contour: &IntContour, - points: Option<&[IntPoint]>, - vertices: &mut Vec, + pub(crate) fn contour_to_vertices( + contour: &IntContour, + points: Option<&[IntPoint]>, + vertices: &mut Vec>, ) { vertices.clear(); vertices.add_contour(contour); @@ -54,19 +59,19 @@ enum DirectionType { Prev, } -struct Direction { - point: IntPoint, +struct Direction { + point: IntPoint, kind: DirectionType, } -trait ChainVertexVec { - fn add_contour(&mut self, contour: &[IntPoint]); - fn add_steiner_points(&mut self, points: &[IntPoint]); +trait ChainVertexVec { + fn add_contour(&mut self, contour: &[IntPoint]); + fn add_steiner_points(&mut self, points: &[IntPoint]); } -impl ChainVertexVec for Vec { +impl ChainVertexVec for Vec> { #[inline] - fn add_contour(&mut self, contour: &[IntPoint]) { + fn add_contour(&mut self, contour: &[IntPoint]) { let mut prev = contour[contour.len() - 2]; let mut this = contour[contour.len() - 1]; @@ -78,7 +83,7 @@ impl ChainVertexVec for Vec { } #[inline] - fn add_steiner_points(&mut self, points: &[IntPoint]) { + fn add_steiner_points(&mut self, points: &[IntPoint]) { for &this in points { self.push(ChainVertex::implant(this)); } @@ -86,11 +91,14 @@ impl ChainVertexVec for Vec { } pub(crate) trait ChainVertexExport { - fn feed_points(&self, points: &mut Vec); + type Int: IntNumber; + fn feed_points(&self, points: &mut Vec>); } -impl ChainVertexExport for [ChainVertex] { +impl ChainVertexExport for [ChainVertex] { + type Int = I; + #[inline] - fn feed_points(&self, points: &mut Vec) { + fn feed_points(&self, points: &mut Vec>) { points.reserve_capacity(self.len()); points.clear(); let mut index = usize::MAX; @@ -108,7 +116,7 @@ trait ChainVertexSort { fn sort_node_in_clockwise_order(&mut self); } -impl ChainVertexSort for [ChainVertex] { +impl ChainVertexSort for [ChainVertex] { #[inline] fn sort_by_swipe_line(&mut self) { self.sort_by_two_keys(false, |v| v.this.x, |v| v.this.y); @@ -161,7 +169,7 @@ impl ChainVertexSort for [ChainVertex] { if (a.x < c.x || a.x == c.x && a.y < c.y) && (b.x < c.x || b.x == c.x && b.y < c.y) || (a.x > c.x || a.x == c.x && a.y > c.y) && (b.x > c.x || b.x == c.x && b.y > c.y) { - Triangle::clock_order_point(a, b, c) + Triangle::clock_order(a, b, c) } else if a.x == c.x && b.x == c.x { a.y.cmp(&b.y) } else { diff --git a/iTriangle/src/int/monotone/chain/vertex.rs b/iTriangle/src/int/monotone/chain/vertex.rs index 77f3dcd..a43aad7 100644 --- a/iTriangle/src/int/monotone/chain/vertex.rs +++ b/iTriangle/src/int/monotone/chain/vertex.rs @@ -1,4 +1,5 @@ use crate::geom::point::IndexPoint; +use i_overlay::i_float::int::number::int::IntNumber; use i_overlay::i_float::int::point::IntPoint; use i_overlay::i_float::triangle::Triangle; @@ -13,16 +14,16 @@ pub(crate) enum VertexType { } #[derive(Debug, Clone, Copy, Default)] -pub(crate) struct ChainVertex { +pub(crate) struct ChainVertex { pub(crate) index: usize, - pub(crate) this: IntPoint, - pub(crate) next: IntPoint, - pub(crate) prev: IntPoint, + pub(crate) this: IntPoint, + pub(crate) next: IntPoint, + pub(crate) prev: IntPoint, } -impl ChainVertex { +impl ChainVertex { #[inline] - pub(super) fn new(this: IntPoint, next: IntPoint, prev: IntPoint) -> Self { + pub(super) fn new(this: IntPoint, next: IntPoint, prev: IntPoint) -> Self { Self { index: 0, this, @@ -32,7 +33,7 @@ impl ChainVertex { } #[inline] - pub(crate) fn implant(this: IntPoint) -> Self { + pub(crate) fn implant(this: IntPoint) -> Self { Self { index: 0, this, @@ -43,7 +44,7 @@ impl ChainVertex { #[inline] pub(crate) fn get_type(&self) -> VertexType { - let clock_wise = Triangle::is_clockwise_point(self.prev, self.this, self.next); + let clock_wise = Triangle::is_clockwise(self.prev, self.this, self.next); if self.prev == IntPoint::EMPTY && self.next == IntPoint::EMPTY { VertexType::Steiner } else if self.prev < self.this && self.next < self.this { @@ -64,7 +65,7 @@ impl ChainVertex { } #[inline] - pub(crate) fn index_point(&self) -> IndexPoint { + pub(crate) fn index_point(&self) -> IndexPoint { IndexPoint::new(self.index, self.this) } } diff --git a/iTriangle/src/int/monotone/flat/section.rs b/iTriangle/src/int/monotone/flat/section.rs index 3132c7d..bc45ecd 100644 --- a/iTriangle/src/int/monotone/flat/section.rs +++ b/iTriangle/src/int/monotone/flat/section.rs @@ -1,15 +1,16 @@ use crate::geom::point::IndexPoint; use crate::int::monotone::v_segment::VSegment; use alloc::vec::Vec; +use i_overlay::i_float::int::number::int::IntNumber; use i_tree::set::sort::KeyValue; #[derive(Debug, Clone)] -pub(super) struct FlatSection { - pub(super) sort: VSegment, - pub(super) points: Vec, +pub(super) struct FlatSection { + pub(super) sort: VSegment, + pub(super) points: Vec>, } -impl Default for FlatSection { +impl Default for FlatSection { #[inline] fn default() -> Self { Self { @@ -19,9 +20,9 @@ impl Default for FlatSection { } } -impl KeyValue for FlatSection { +impl KeyValue> for FlatSection { #[inline] - fn key(&self) -> &VSegment { + fn key(&self) -> &VSegment { &self.sort } } diff --git a/iTriangle/src/int/monotone/flat/triangulator.rs b/iTriangle/src/int/monotone/flat/triangulator.rs index 69d7749..cb9fe0b 100644 --- a/iTriangle/src/int/monotone/flat/triangulator.rs +++ b/iTriangle/src/int/monotone/flat/triangulator.rs @@ -6,29 +6,30 @@ use crate::int::triangulation::{IndexType, IntTriangulation}; use alloc::vec; use alloc::vec::Vec; use core::cmp::Ordering; +use i_overlay::i_float::int::number::int::IntNumber; use i_overlay::i_float::triangle::Triangle; use i_overlay::i_shape::util::reserve::Reserve; use i_tree::set::list::SetList; use i_tree::set::sort::SetCollection; use i_tree::set::tree::SetTree; -struct FlatBuilder<'a, I> { - triangulation: &'a mut IntTriangulation, +struct FlatBuilder<'a, I: IntNumber, N: IndexType> { + triangulation: &'a mut IntTriangulation, } -pub(crate) trait FlatTriangulation { - fn flat_triangulate_into( +pub(crate) trait FlatTriangulation { + fn flat_triangulate_into( &self, triangles_count: usize, - triangulation: &mut IntTriangulation, + triangulation: &mut IntTriangulation, ); } -impl FlatTriangulation for [ChainVertex] { - fn flat_triangulate_into( +impl FlatTriangulation for [ChainVertex] { + fn flat_triangulate_into( &self, triangles_count: usize, - triangulation: &mut IntTriangulation, + triangulation: &mut IntTriangulation, ) { triangulation.indices.reserve_capacity(triangles_count); triangulation.indices.clear(); @@ -47,17 +48,17 @@ impl FlatTriangulation for [ChainVertex] { } } -impl<'a, I> FlatBuilder<'a, I> { - fn new(triangulation: &'a mut IntTriangulation) -> Self { +impl<'a, I: IntNumber, N: IndexType> FlatBuilder<'a, I, N> { + fn new(triangulation: &'a mut IntTriangulation) -> Self { Self { triangulation } } } -impl FlatBuilder<'_, I> { +impl FlatBuilder<'_, I, N> { #[inline] - fn triangulate>( + fn triangulate, FlatSection>>( &mut self, - vertices: &[ChainVertex], + vertices: &[ChainVertex], mut store: S, ) { for v in vertices.iter() { @@ -73,7 +74,11 @@ impl FlatBuilder<'_, I> { } #[inline] - fn join>(&mut self, v: &ChainVertex, tree: &mut S) { + fn join, FlatSection>>( + &mut self, + v: &ChainVertex, + tree: &mut S, + ) { let index = tree.find_section(v); let section = unsafe { tree.value_by_index_mut(index) }; if section.sort.b == v.this { @@ -84,7 +89,11 @@ impl FlatBuilder<'_, I> { } #[inline] - fn start>(&mut self, v: &ChainVertex, tree: &mut S) { + fn start, FlatSection>>( + &mut self, + v: &ChainVertex, + tree: &mut S, + ) { let section = FlatSection { sort: VSegment { a: v.this, @@ -96,7 +105,11 @@ impl FlatBuilder<'_, I> { } #[inline] - fn end>(&mut self, v: &ChainVertex, tree: &mut S) { + fn end, FlatSection>>( + &mut self, + v: &ChainVertex, + tree: &mut S, + ) { let index = tree.find_section(v); let section = unsafe { tree.value_by_index_mut(index) }; section.add_as_last(v, &mut self.triangulation.indices); @@ -104,14 +117,22 @@ impl FlatBuilder<'_, I> { } #[inline] - fn split>(&mut self, v: &ChainVertex, tree: &mut S) { + fn split, FlatSection>>( + &mut self, + v: &ChainVertex, + tree: &mut S, + ) { let index = tree.find_section(v); let section = unsafe { tree.value_by_index_mut(index) }; let new_section = section.add_to_middle(v, &mut self.triangulation.indices); tree.insert(new_section); } - fn merge>(&mut self, v: &ChainVertex, tree: &mut S) { + fn merge, FlatSection>>( + &mut self, + v: &ChainVertex, + tree: &mut S, + ) { let prev_index = tree.find_section(v); let next_index = tree.index_before(prev_index); let next = unsafe { tree.value_by_index_mut(next_index) }; @@ -137,9 +158,9 @@ impl FlatBuilder<'_, I> { } } -impl FlatSection { +impl FlatSection { #[inline] - fn add_as_last(&mut self, v: &ChainVertex, triangles: &mut Vec) { + fn add_as_last(&mut self, v: &ChainVertex, triangles: &mut Vec) { debug_assert!(self.points.len() >= 2); let a = v.index_point(); @@ -149,12 +170,12 @@ impl FlatSection { } #[inline] - fn add_to_top(&mut self, v: &ChainVertex, triangles: &mut Vec) { + fn add_to_top(&mut self, v: &ChainVertex, triangles: &mut Vec) { self.add_from_start(v, triangles); } #[inline] - fn add_to_bottom(&mut self, v: &ChainVertex, triangles: &mut Vec) { + fn add_to_bottom(&mut self, v: &ChainVertex, triangles: &mut Vec) { self.sort = VSegment { a: v.this, b: v.next, @@ -162,11 +183,11 @@ impl FlatSection { self.add_from_end(v, triangles); } - fn add_to_middle( + fn add_to_middle( &mut self, - v: &ChainVertex, - triangles: &mut Vec, - ) -> FlatSection { + v: &ChainVertex, + triangles: &mut Vec, + ) -> FlatSection { debug_assert!(!self.points.is_empty()); let a = v.index_point(); let mut b = self.points[0]; @@ -191,7 +212,7 @@ impl FlatSection { let mut i = 1; while i < self.points.len() { let c = self.points[i]; - if Triangle::is_cw_or_line_point(a.point, b.point, c.point) { + if Triangle::is_cw_or_line(a.point, b.point, c.point) { i += 1; b = c; continue; @@ -204,11 +225,11 @@ impl FlatSection { // we still must split section // peak the closest point by x to a.x let mut split_index = 0; - let mut min_dist = i32::MAX; + let mut min_dist = None; for (i, v) in self.points.iter().enumerate() { - let dist = a.point.x - v.point.x; - if dist < min_dist { - min_dist = dist; + let dist = a.point.x.wide() - v.point.x.wide(); + if min_dist.is_none_or(|min_dist| dist < min_dist) { + min_dist = Some(dist); split_index = i; } } @@ -236,7 +257,7 @@ impl FlatSection { let mut n = 0; while i < bottom_points.len() { let c = bottom_points[i]; - if Triangle::is_cw_or_line_point(a.point, b.point, c.point) { + if Triangle::is_cw_or_line(a.point, b.point, c.point) { break; } triangles.add_abc(a.index, b.index, bottom_points[i].index); @@ -267,7 +288,7 @@ impl FlatSection { } } - fn add_from_start(&mut self, v: &ChainVertex, triangles: &mut Vec) { + fn add_from_start(&mut self, v: &ChainVertex, triangles: &mut Vec) { let a = v.index_point(); debug_assert!(!self.points.is_empty()); if self.points.len() <= 1 { @@ -278,7 +299,7 @@ impl FlatSection { let mut n = 0; let mut b = *self.points.first().unwrap(); for &c in self.points.iter().skip(1) { - if Triangle::is_cw_or_line_point(a.point, b.point, c.point) { + if Triangle::is_cw_or_line(a.point, b.point, c.point) { break; } n += 1; @@ -296,7 +317,7 @@ impl FlatSection { } } - fn add_from_end(&mut self, v: &ChainVertex, triangles: &mut Vec) { + fn add_from_end(&mut self, v: &ChainVertex, triangles: &mut Vec) { let a = v.index_point(); debug_assert!(!self.points.is_empty()); if self.points.len() <= 1 { @@ -307,7 +328,7 @@ impl FlatSection { let mut n = 0; let mut c = *self.points.last().unwrap(); for &b in self.points.iter().rev().skip(1) { - if Triangle::is_cw_or_line_point(a.point, b.point, c.point) { + if Triangle::is_cw_or_line(a.point, b.point, c.point) { break; } n += 1; @@ -334,16 +355,17 @@ impl AddTriangle for Vec { } } -trait FindSection { - fn find_section(&self, v: &ChainVertex) -> u32; +trait FindSection { + fn find_section(&self, v: &ChainVertex) -> u32; } -impl FindSection for C +impl FindSection for C where - C: SetCollection, + I: IntNumber, + C: SetCollection, FlatSection>, { #[inline] - fn find_section(&self, v: &ChainVertex) -> u32 { + fn find_section(&self, v: &ChainVertex) -> u32 { self.first_index_less_by(|s| { let point_search = s.is_under_point_order(v.this); match point_search { @@ -351,7 +373,7 @@ where if v.prev == s.a { Ordering::Equal } else { - Triangle::clock_order_point(s.a, v.next, s.b) + Triangle::clock_order(s.a, v.next, s.b) } } _ => point_search, @@ -376,7 +398,7 @@ mod tests { use i_overlay::i_shape::int::path::IntPath; use rand::RngExt; - fn path(slice: &[[i32; 2]]) -> IntPath { + fn path(slice: &[[i32; 2]]) -> IntPath { slice.iter().map(|p| IntPoint::new(p[0], p[1])).collect() } @@ -390,7 +412,7 @@ mod tests { ]]; let shape_area = shape.area_two(); - let mut raw = IntTriangulation::::default(); + let mut raw = IntTriangulation::::default(); MonotoneTriangulator::default().shape_into_flat_triangulation(&shape, &mut raw); assert_eq!(raw.indices.len() / 3, 2); @@ -407,7 +429,7 @@ mod tests { ]]; let shape_area = shape.area_two(); - let mut raw = IntTriangulation::::default(); + let mut raw = IntTriangulation::::default(); MonotoneTriangulator::default().shape_into_flat_triangulation(&shape, &mut raw); assert_eq!(raw.indices.len() / 3, 2); @@ -424,7 +446,7 @@ mod tests { ]]; let shape_area = shape.area_two(); - let mut raw = IntTriangulation::::default(); + let mut raw = IntTriangulation::::default(); MonotoneTriangulator::default().shape_into_flat_triangulation(&shape, &mut raw); assert_eq!(raw.indices.len() / 3, 2); @@ -441,7 +463,7 @@ mod tests { ]]; let shape_area = shape.area_two(); - let mut raw = IntTriangulation::::default(); + let mut raw = IntTriangulation::::default(); MonotoneTriangulator::default().shape_into_flat_triangulation(&shape, &mut raw); assert_eq!(raw.indices.len() / 3, 2); @@ -458,7 +480,7 @@ mod tests { ]]; let shape_area = shape.area_two(); - let mut raw = IntTriangulation::::default(); + let mut raw = IntTriangulation::::default(); MonotoneTriangulator::default().shape_into_flat_triangulation(&shape, &mut raw); assert_eq!(raw.indices.len() / 3, 2); @@ -477,7 +499,7 @@ mod tests { ]]; let shape_area = shape.area_two(); - let mut raw = IntTriangulation::::default(); + let mut raw = IntTriangulation::::default(); MonotoneTriangulator::default().shape_into_flat_triangulation(&shape, &mut raw); assert_eq!(raw.indices.len() / 3, 4); @@ -497,7 +519,7 @@ mod tests { ]]; let shape_area = shape.area_two(); - let mut raw = IntTriangulation::::default(); + let mut raw = IntTriangulation::::default(); MonotoneTriangulator::default().shape_into_flat_triangulation(&shape, &mut raw); assert_eq!(raw.indices.len() / 3, 5); @@ -515,7 +537,7 @@ mod tests { ]]; let shape_area = shape.area_two(); - let mut raw = IntTriangulation::::default(); + let mut raw = IntTriangulation::::default(); MonotoneTriangulator::default().shape_into_flat_triangulation(&shape, &mut raw); assert_eq!(raw.indices.len() / 3, 3); @@ -536,7 +558,7 @@ mod tests { ]]; let shape_area = shape.area_two(); - let mut raw = IntTriangulation::::default(); + let mut raw = IntTriangulation::::default(); MonotoneTriangulator::default().shape_into_flat_triangulation(&shape, &mut raw); assert_eq!(raw.indices.len() / 3, 6); @@ -559,7 +581,7 @@ mod tests { ]]; let shape_area = shape.area_two(); - let mut raw = IntTriangulation::::default(); + let mut raw = IntTriangulation::::default(); MonotoneTriangulator::default().shape_into_flat_triangulation(&shape, &mut raw); assert_eq!(raw.indices.len() / 3, 8); @@ -577,7 +599,7 @@ mod tests { ]; let shape_area = shape.area_two(); - let mut raw = IntTriangulation::::default(); + let mut raw = IntTriangulation::::default(); MonotoneTriangulator::default().shape_into_flat_triangulation(&shape, &mut raw); assert_eq!(raw.indices.len() / 3, 16); @@ -596,7 +618,7 @@ mod tests { ]; let shape_area = shape.area_two(); - let mut raw = IntTriangulation::::default(); + let mut raw = IntTriangulation::::default(); MonotoneTriangulator::default().shape_into_flat_triangulation(&shape, &mut raw); assert_eq!(raw.indices.len() / 3, 24); @@ -629,7 +651,7 @@ mod tests { ]; let shape_area = shape.area_two(); - let mut raw = IntTriangulation::::default(); + let mut raw = IntTriangulation::::default(); MonotoneTriangulator::default().shape_into_flat_triangulation(&shape, &mut raw); assert_eq!(raw.indices.len() / 3, 16); @@ -650,7 +672,7 @@ mod tests { ])]; let shape_area = shape.area_two(); - let mut raw = IntTriangulation::::default(); + let mut raw = IntTriangulation::::default(); MonotoneTriangulator::default().shape_into_flat_triangulation(&shape, &mut raw); assert_eq!(raw.indices.len() / 3, 6); @@ -664,7 +686,7 @@ mod tests { let shape_area = s.area_two(); - let mut raw = IntTriangulation::::default(); + let mut raw = IntTriangulation::::default(); MonotoneTriangulator::default().shape_into_flat_triangulation(&shape, &mut raw); assert_eq!(raw.indices.len() / 3, 3); @@ -676,7 +698,7 @@ mod tests { let shape = vec![path(&[[0, 2], [2, 0], [5, 0], [4, 6]])]; let shape_area = shape.area_two(); - let mut raw = IntTriangulation::::default(); + let mut raw = IntTriangulation::::default(); MonotoneTriangulator::default().shape_into_flat_triangulation(&shape, &mut raw); assert_eq!(raw.indices.len() / 3, 2); @@ -688,7 +710,7 @@ mod tests { let shape = vec![path(&[[0, 4], [-4, -3], [-2, -2], [1, -2], [0, -1]])]; let shape_area = shape.area_two(); - let mut raw = IntTriangulation::::default(); + let mut raw = IntTriangulation::::default(); MonotoneTriangulator::default().shape_into_flat_triangulation(&shape, &mut raw); assert_eq!(raw.indices.len() / 3, 3); @@ -709,7 +731,7 @@ mod tests { ])]; let shape_area = shape.area_two(); - let mut raw = IntTriangulation::::default(); + let mut raw = IntTriangulation::::default(); MonotoneTriangulator::default().shape_into_flat_triangulation(&shape, &mut raw); assert_eq!(raw.indices.len() / 3, 6); @@ -729,7 +751,7 @@ mod tests { ])]; let shape_area = shape.area_two(); - let mut raw = IntTriangulation::::default(); + let mut raw = IntTriangulation::::default(); MonotoneTriangulator::default().shape_into_flat_triangulation(&shape, &mut raw); assert_eq!(raw.indices.len() / 3, 5); @@ -748,7 +770,7 @@ mod tests { ])]; let shape_area = shape.area_two(); - let mut raw = IntTriangulation::::default(); + let mut raw = IntTriangulation::::default(); MonotoneTriangulator::default().shape_into_flat_triangulation(&shape, &mut raw); assert_eq!(raw.indices.len() / 3, 4); @@ -768,7 +790,7 @@ mod tests { ])]; let shape_area = shape.area_two(); - let mut raw = IntTriangulation::::default(); + let mut raw = IntTriangulation::::default(); MonotoneTriangulator::default().shape_into_flat_triangulation(&shape, &mut raw); assert_eq!(raw.indices.len() / 3, 5); @@ -789,7 +811,7 @@ mod tests { ])]; let shape_area = shape.area_two(); - let mut raw = IntTriangulation::::default(); + let mut raw = IntTriangulation::::default(); MonotoneTriangulator::default().shape_into_flat_triangulation(&shape, &mut raw); assert_eq!(raw.indices.len() / 3, 6); @@ -798,7 +820,7 @@ mod tests { #[test] fn test_random_0() { - let mut raw = IntTriangulation::::default(); + let mut raw = IntTriangulation::::default(); for _ in 0..100_000 { let path = random(8, 5); let shape = vec![path]; @@ -817,7 +839,7 @@ mod tests { #[test] fn test_random_1() { - let mut raw = IntTriangulation::::default(); + let mut raw = IntTriangulation::::default(); for _ in 0..100_000 { let path = random(10, 6); let shape = vec![path]; @@ -836,7 +858,7 @@ mod tests { #[test] fn test_random_2() { - let mut raw = IntTriangulation::::default(); + let mut raw = IntTriangulation::::default(); for _ in 0..100_000 { let path = random(10, 12); let shape = vec![path]; @@ -855,7 +877,7 @@ mod tests { #[test] fn test_random_3() { - let mut raw = IntTriangulation::::default(); + let mut raw = IntTriangulation::::default(); for _ in 0..50_000 { let path = random(20, 20); let shape = vec![path]; @@ -874,7 +896,7 @@ mod tests { #[test] fn test_random_4() { - let mut raw = IntTriangulation::::default(); + let mut raw = IntTriangulation::::default(); for _ in 0..5_000 { let path = random(30, 50); let shape = vec![path]; @@ -893,7 +915,7 @@ mod tests { #[test] fn test_random_5() { - let mut raw = IntTriangulation::::default(); + let mut raw = IntTriangulation::::default(); for _ in 0..2_000 { let main = random(50, 20); let mut shape = vec![main]; @@ -914,7 +936,7 @@ mod tests { } } - fn random(radius: i32, n: usize) -> IntPath { + fn random(radius: i32, n: usize) -> IntPath { let a = radius / 2; let mut points = Vec::with_capacity(n); let mut rng = rand::rng(); diff --git a/iTriangle/src/int/monotone/net/section.rs b/iTriangle/src/int/monotone/net/section.rs index 9c26789..4fb0447 100644 --- a/iTriangle/src/int/monotone/net/section.rs +++ b/iTriangle/src/int/monotone/net/section.rs @@ -1,6 +1,7 @@ use crate::geom::point::IndexPoint; use crate::int::monotone::v_segment::VSegment; use alloc::vec::Vec; +use i_overlay::i_float::int::number::int::IntNumber; use i_tree::set::sort::KeyValue; #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -9,25 +10,25 @@ pub(crate) enum EdgeType { Phantom(usize), // keep index to itself(edge) in phantom store } #[derive(Debug, Clone, Copy)] -pub(crate) struct TriangleEdge { - pub(crate) a: IndexPoint, - pub(crate) b: IndexPoint, +pub(crate) struct TriangleEdge { + pub(crate) a: IndexPoint, + pub(crate) b: IndexPoint, pub(crate) kind: EdgeType, } #[derive(Debug, Clone)] -pub(crate) enum Content { - Point(IndexPoint), - Edges(Vec), +pub(crate) enum Content { + Point(IndexPoint), + Edges(Vec>), } #[derive(Debug, Clone)] -pub(crate) struct Section { - pub(crate) sort: VSegment, - pub(crate) content: Content, +pub(crate) struct Section { + pub(crate) sort: VSegment, + pub(crate) content: Content, } -impl Default for Section { +impl Default for Section { #[inline] fn default() -> Self { Self { @@ -37,16 +38,16 @@ impl Default for Section { } } -impl KeyValue for Section { +impl KeyValue> for Section { #[inline] - fn key(&self) -> &VSegment { + fn key(&self) -> &VSegment { &self.sort } } -impl TriangleEdge { +impl TriangleEdge { #[inline] - pub(crate) fn border(a: IndexPoint, b: IndexPoint) -> Self { + pub(crate) fn border(a: IndexPoint, b: IndexPoint) -> Self { Self { a, b, @@ -55,7 +56,7 @@ impl TriangleEdge { } #[inline] - pub(crate) fn phantom(a: IndexPoint, b: IndexPoint, index: usize) -> Self { + pub(crate) fn phantom(a: IndexPoint, b: IndexPoint, index: usize) -> Self { Self { a, b, @@ -64,7 +65,7 @@ impl TriangleEdge { } #[inline] - pub(crate) fn regular(a: IndexPoint, b: IndexPoint, index: usize) -> Self { + pub(crate) fn regular(a: IndexPoint, b: IndexPoint, index: usize) -> Self { Self { a, b, @@ -83,8 +84,8 @@ mod tests { use i_tree::set::tree::SetTree; use i_tree::EMPTY_REF; - impl Section { - fn with_sort(sort: VSegment) -> Section { + impl Section { + fn with_sort(sort: VSegment) -> Section { Section { sort, content: Content::Point(IndexPoint::empty()), diff --git a/iTriangle/src/int/monotone/net/triangulator.rs b/iTriangle/src/int/monotone/net/triangulator.rs index 5c38c47..b8f53f0 100644 --- a/iTriangle/src/int/monotone/net/triangulator.rs +++ b/iTriangle/src/int/monotone/net/triangulator.rs @@ -10,26 +10,31 @@ use alloc::vec; use alloc::vec::Vec; use core::cmp::Ordering; use core::mem::swap; +use i_overlay::i_float::int::number::int::IntNumber; use i_overlay::i_float::triangle::Triangle; use i_overlay::i_shape::util::reserve::Reserve; use i_tree::set::list::SetList; use i_tree::set::sort::SetCollection; use i_tree::set::tree::SetTree; -struct NetBuilder<'a> { - triangulation: &'a mut RawIntTriangulation, +struct NetBuilder<'a, I: IntNumber> { + triangulation: &'a mut RawIntTriangulation, phantom_store: PhantomEdgePool, } -pub(crate) trait NetTriangulation { - fn net_triangulate_into(&self, triangles_count: usize, triangulation: &mut RawIntTriangulation); +pub(crate) trait NetTriangulation { + fn net_triangulate_into( + &self, + triangles_count: usize, + triangulation: &mut RawIntTriangulation, + ); } -impl NetTriangulation for [ChainVertex] { +impl NetTriangulation for [ChainVertex] { fn net_triangulate_into( &self, triangles_count: usize, - triangulation: &mut RawIntTriangulation, + triangulation: &mut RawIntTriangulation, ) { triangulation.triangles.reserve_capacity(triangles_count); triangulation.triangles.clear(); @@ -47,8 +52,8 @@ impl NetTriangulation for [ChainVertex] { } } -impl<'a> NetBuilder<'a> { - fn new(triangulation: &'a mut RawIntTriangulation) -> Self { +impl<'a, I: IntNumber> NetBuilder<'a, I> { + fn new(triangulation: &'a mut RawIntTriangulation) -> Self { Self { triangulation, phantom_store: PhantomEdgePool::new(), @@ -56,11 +61,11 @@ impl<'a> NetBuilder<'a> { } } -impl NetBuilder<'_> { +impl NetBuilder<'_, I> { #[inline] - fn triangulate>( + fn triangulate, Section>>( &mut self, - vertices: &[ChainVertex], + vertices: &[ChainVertex], mut store: S, ) { for v in vertices.iter() { @@ -88,9 +93,9 @@ impl NetBuilder<'_> { #[inline] fn insert_triangle_with_neighbor_link( &mut self, - edge: &TriangleEdge, + edge: &TriangleEdge, vertex: usize, - mut new_triangle: IntTriangle, + mut new_triangle: IntTriangle, ) -> usize { let new_index = self.next_triangle_index(); match edge.kind { @@ -129,7 +134,11 @@ impl NetBuilder<'_> { } #[inline] - fn join>(&mut self, v: &ChainVertex, tree: &mut S) { + fn join, Section>>( + &mut self, + v: &ChainVertex, + tree: &mut S, + ) { let index = tree.find_section(v); let section = unsafe { tree.value_by_index_mut(index) }; if section.sort.b == v.this { @@ -140,7 +149,11 @@ impl NetBuilder<'_> { } #[inline] - fn start>(&mut self, v: &ChainVertex, tree: &mut S) { + fn start, Section>>( + &mut self, + v: &ChainVertex, + tree: &mut S, + ) { let section = Section { sort: VSegment { a: v.this, @@ -152,21 +165,29 @@ impl NetBuilder<'_> { } #[inline] - fn end>(&mut self, v: &ChainVertex, tree: &mut S) { + fn end, Section>>(&mut self, v: &ChainVertex, tree: &mut S) { let index = tree.find_section(v); let section = unsafe { tree.value_by_index_mut(index) }; section.add_as_last(v, self); tree.delete_by_index(index); } - fn split>(&mut self, v: &ChainVertex, tree: &mut S) { + fn split, Section>>( + &mut self, + v: &ChainVertex, + tree: &mut S, + ) { let index = tree.find_section(v); let section = unsafe { tree.value_by_index_mut(index) }; let new_section = section.add_to_middle(v, self); tree.insert(new_section); } - fn merge>(&mut self, v: &ChainVertex, tree: &mut S) { + fn merge, Section>>( + &mut self, + v: &ChainVertex, + tree: &mut S, + ) { let prev_index = tree.find_section(v); let next_index = tree.index_before(prev_index); let next = unsafe { tree.value_by_index_mut(next_index) }; @@ -193,16 +214,20 @@ impl NetBuilder<'_> { tree.delete_by_index(next_index); } - fn steiner>(&mut self, v: &ChainVertex, tree: &mut S) { + fn steiner, Section>>( + &mut self, + v: &ChainVertex, + tree: &mut S, + ) { let index = tree.find_section(v); let section = unsafe { tree.value_by_index_mut(index) }; section.add_steiner(v.index_point(), self); } } -impl Section { +impl Section { #[inline] - fn add_as_last(&mut self, v: &ChainVertex, net_builder: &mut NetBuilder) { + fn add_as_last(&mut self, v: &ChainVertex, net_builder: &mut NetBuilder) { let edges = match &mut self.content { Content::Edges(edges) => edges, Content::Point(_) => unreachable!("Section with less then 3 points not possible"), @@ -229,12 +254,12 @@ impl Section { } #[inline] - fn add_to_top(&mut self, v: &ChainVertex, net_builder: &mut NetBuilder) { + fn add_to_top(&mut self, v: &ChainVertex, net_builder: &mut NetBuilder) { self.add_from_start(v, net_builder); } #[inline] - fn add_to_bottom(&mut self, v: &ChainVertex, net_builder: &mut NetBuilder) { + fn add_to_bottom(&mut self, v: &ChainVertex, net_builder: &mut NetBuilder) { self.sort = VSegment { a: v.this, b: v.next, @@ -243,7 +268,7 @@ impl Section { } #[inline] - fn add_to_middle(&mut self, v: &ChainVertex, net_builder: &mut NetBuilder) -> Section { + fn add_to_middle(&mut self, v: &ChainVertex, net_builder: &mut NetBuilder) -> Section { let edges = match &mut self.content { Content::Point(point) => { let phantom_index = net_builder.get_unique_phantom_edge_index(); @@ -273,7 +298,7 @@ impl Section { while i < edges.len() { let ei = &edges[i]; // skip first not valid triangles - if Triangle::is_cw_or_line_point(v.this, ei.a.point, ei.b.point) { + if Triangle::is_cw_or_line(v.this, ei.a.point, ei.b.point) { i += 1; continue; } @@ -284,9 +309,9 @@ impl Section { if i >= edges.len() { let last = edges[edges.len() - 1].b; let mut index = edges.len(); - let mut min_dist = vp.point.x - last.point.x; + let mut min_dist = vp.point.x.wide() - last.point.x.wide(); for (ei, e) in edges.iter().enumerate() { - let dist = vp.point.x - e.a.point.x; + let dist = vp.point.x.wide() - e.a.point.x.wide(); if dist < min_dist { min_dist = dist; index = ei; @@ -360,7 +385,7 @@ impl Section { i = 1; while i < edges.len() { let ei = &edges[i]; - if Triangle::is_cw_or_line_point(v.this, ei.a.point, ei.b.point) { + if Triangle::is_cw_or_line(v.this, ei.a.point, ei.b.point) { break; } let mut triangle = IntTriangle::abc(vp, ei.a, ei.b); @@ -381,7 +406,7 @@ impl Section { top_section } - fn add_from_start(&mut self, v: &ChainVertex, net_builder: &mut NetBuilder) { + fn add_from_start(&mut self, v: &ChainVertex, net_builder: &mut NetBuilder) { let vp = v.index_point(); let edges = match &mut self.content { @@ -397,7 +422,7 @@ impl Section { let e0 = unsafe { edges.get_unchecked(0) }; - if Triangle::is_cw_or_line_point(v.this, e0.a.point, e0.b.point) { + if Triangle::is_cw_or_line(v.this, e0.a.point, e0.b.point) { edges.insert(0, TriangleEdge::border(vp, e0.a)); return; } @@ -408,7 +433,7 @@ impl Section { let mut n = 1; let mut eb = e0.b; for ei in edges.iter().skip(1) { - if Triangle::is_cw_or_line_point(vp.point, ei.a.point, ei.b.point) { + if Triangle::is_cw_or_line(vp.point, ei.a.point, ei.b.point) { break; } eb = ei.b; @@ -437,7 +462,7 @@ impl Section { ); } - fn add_from_end(&mut self, v: &ChainVertex, net_builder: &mut NetBuilder) { + fn add_from_end(&mut self, v: &ChainVertex, net_builder: &mut NetBuilder) { let vp = v.index_point(); let edges = match &mut self.content { Content::Point(point) => { @@ -449,7 +474,7 @@ impl Section { let el = edges.last().unwrap(); - if Triangle::is_cw_or_line_point(v.this, el.a.point, el.b.point) { + if Triangle::is_cw_or_line(v.this, el.a.point, el.b.point) { edges.push(TriangleEdge::border(el.b, vp)); return; } @@ -459,7 +484,7 @@ impl Section { let mut ea = el.a; let mut n = 1; for ei in edges.iter().rev().skip(1) { - if Triangle::is_cw_or_line_point(v.this, ei.a.point, ei.b.point) { + if Triangle::is_cw_or_line(v.this, ei.a.point, ei.b.point) { break; } ea = ei.a; @@ -477,7 +502,7 @@ impl Section { } #[inline] - fn add_steiner(&mut self, vp: IndexPoint, net_builder: &mut NetBuilder) { + fn add_steiner(&mut self, vp: IndexPoint, net_builder: &mut NetBuilder) { let edges = match &mut self.content { Content::Point(point) => { let phantom_index = net_builder.get_unique_phantom_edge_index(); @@ -495,7 +520,7 @@ impl Section { while i < edges.len() { let ei = &edges[i]; // skip first not valid triangles - if Triangle::is_cw_or_line_point(vp.point, ei.a.point, ei.b.point) { + if Triangle::is_cw_or_line(vp.point, ei.a.point, ei.b.point) { i += 1; continue; } @@ -505,9 +530,9 @@ impl Section { if i >= edges.len() { let last = edges[edges.len() - 1].b; let mut index = edges.len(); - let mut min_dist = vp.point.x - last.point.x; + let mut min_dist = vp.point.x.wide() - last.point.x.wide(); for (ei, e) in edges.iter().enumerate() { - let dist = vp.point.x - e.a.point.x; + let dist = vp.point.x.wide() - e.a.point.x.wide(); if dist < min_dist { min_dist = dist; index = ei; @@ -547,7 +572,7 @@ impl Section { i = 1; while i < edges.len() { let ei = &edges[i]; - if Triangle::is_cw_or_line_point(vp.point, ei.a.point, ei.b.point) { + if Triangle::is_cw_or_line(vp.point, ei.a.point, ei.b.point) { break; } let mut triangle = IntTriangle::abc(vp, ei.a, ei.b); @@ -571,16 +596,17 @@ impl Section { } } -trait FindSection { - fn find_section(&self, v: &ChainVertex) -> u32; +trait FindSection { + fn find_section(&self, v: &ChainVertex) -> u32; } -impl FindSection for C +impl FindSection for C where - C: SetCollection, + I: IntNumber, + C: SetCollection, Section>, { #[inline] - fn find_section(&self, v: &ChainVertex) -> u32 { + fn find_section(&self, v: &ChainVertex) -> u32 { self.first_index_less_by(|s| { let point_search = s.is_under_point_order(v.this); match point_search { @@ -588,7 +614,7 @@ where if v.prev == s.a { Ordering::Equal } else { - Triangle::clock_order_point(s.a, v.next, s.b) + Triangle::clock_order(s.a, v.next, s.b) } } _ => point_search, @@ -615,7 +641,7 @@ mod tests { use rand::RngExt; use std::collections::HashSet; - fn path(slice: &[[i32; 2]]) -> IntPath { + fn path(slice: &[[i32; 2]]) -> IntPath { slice.iter().map(|p| IntPoint::new(p[0], p[1])).collect() } @@ -1547,7 +1573,7 @@ mod tests { } } - fn random(radius: i32, n: usize) -> IntPath { + fn random(radius: i32, n: usize) -> IntPath { let a = radius / 2; let mut points = Vec::with_capacity(n); let mut rng = rand::rng(); diff --git a/iTriangle/src/int/monotone/triangulator.rs b/iTriangle/src/int/monotone/triangulator.rs index c94ba3f..930722e 100644 --- a/iTriangle/src/int/monotone/triangulator.rs +++ b/iTriangle/src/int/monotone/triangulator.rs @@ -5,22 +5,29 @@ use crate::int::monotone::flat::triangulator::FlatTriangulation; use crate::int::monotone::net::triangulator::NetTriangulation; use crate::int::triangulation::{IndexType, IntTriangulation, RawIntTriangulation}; use alloc::vec::Vec; +use i_key_sort::sort::key::SortKey; +use i_overlay::i_float::int::number::int::IntNumber; use i_overlay::i_float::int::point::IntPoint; use i_overlay::i_shape::flat::buffer::FlatContoursBuffer; use i_overlay::i_shape::int::shape::{IntContour, IntShape}; -#[derive(Default)] -pub(crate) struct MonotoneTriangulator { - vertices: Option>, +pub(crate) struct MonotoneTriangulator { + vertices: Option>>, } -impl MonotoneTriangulator { +impl Default for MonotoneTriangulator { + fn default() -> Self { + Self { vertices: None } + } +} + +impl MonotoneTriangulator { #[inline] pub(crate) fn shape_into_net_triangulation( &mut self, - shape: &IntShape, - points: Option<&[IntPoint]>, - triangulation: &mut RawIntTriangulation, + shape: &IntShape, + points: Option<&[IntPoint]>, + triangulation: &mut RawIntTriangulation, ) { let points_count = points.map(|points| points.len()).unwrap_or(0); @@ -35,9 +42,9 @@ impl MonotoneTriangulator { #[inline] pub(crate) fn contour_into_net_triangulation( &mut self, - contour: &IntContour, - points: Option<&[IntPoint]>, - triangulation: &mut RawIntTriangulation, + contour: &IntContour, + points: Option<&[IntPoint]>, + triangulation: &mut RawIntTriangulation, ) { let points_count = points.map(|points| points.len()).unwrap_or(0); @@ -52,8 +59,8 @@ impl MonotoneTriangulator { #[inline] pub(crate) fn flat_into_net_triangulation( &mut self, - flat: &FlatContoursBuffer, - triangulation: &mut RawIntTriangulation, + flat: &FlatContoursBuffer, + triangulation: &mut RawIntTriangulation, ) { let mut vertices = self.vertices.take().unwrap_or_default(); ChainBuilder::flat_to_vertices(flat, &mut vertices); @@ -64,10 +71,10 @@ impl MonotoneTriangulator { } #[inline] - pub(crate) fn shape_into_flat_triangulation( + pub(crate) fn shape_into_flat_triangulation( &mut self, - shape: &IntShape, - triangulation: &mut IntTriangulation, + shape: &IntShape, + triangulation: &mut IntTriangulation, ) { let mut vertices = self.vertices.take().unwrap_or_default(); ChainBuilder::shape_to_vertices(shape, None, &mut vertices); @@ -78,10 +85,10 @@ impl MonotoneTriangulator { } #[inline] - pub(crate) fn contour_into_flat_triangulation( + pub(crate) fn contour_into_flat_triangulation( &mut self, - contour: &IntContour, - triangulation: &mut IntTriangulation, + contour: &IntContour, + triangulation: &mut IntTriangulation, ) { let mut vertices = self.vertices.take().unwrap_or_default(); ChainBuilder::contour_to_vertices(contour, None, &mut vertices); @@ -92,10 +99,10 @@ impl MonotoneTriangulator { } #[inline] - pub(crate) fn flat_into_flat_triangulation( + pub(crate) fn flat_into_flat_triangulation( &mut self, - flat: &FlatContoursBuffer, - triangulation: &mut IntTriangulation, + flat: &FlatContoursBuffer, + triangulation: &mut IntTriangulation, ) { let mut vertices = self.vertices.take().unwrap_or_default(); ChainBuilder::flat_to_vertices(flat, &mut vertices); diff --git a/iTriangle/src/int/monotone/v_segment.rs b/iTriangle/src/int/monotone/v_segment.rs index 7b80942..7322b20 100644 --- a/iTriangle/src/int/monotone/v_segment.rs +++ b/iTriangle/src/int/monotone/v_segment.rs @@ -1,45 +1,46 @@ use core::cmp::Ordering; +use i_overlay::i_float::int::number::int::IntNumber; use i_overlay::i_float::int::point::IntPoint; use i_overlay::i_float::triangle::Triangle; #[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub(crate) struct VSegment { - pub(crate) a: IntPoint, - pub(crate) b: IntPoint, +pub(crate) struct VSegment { + pub(crate) a: IntPoint, + pub(crate) b: IntPoint, } -impl VSegment { +impl VSegment { #[inline] - fn is_under_segment_order(&self, other: &VSegment) -> Ordering { + fn is_under_segment_order(&self, other: &VSegment) -> Ordering { match self.b.cmp(&other.b) { - Ordering::Less => Triangle::clock_order_point(self.b, other.a, other.b), - Ordering::Equal => Triangle::clock_order_point(self.b, self.a, other.a), - Ordering::Greater => Triangle::clock_order_point(other.b, self.b, self.a), + Ordering::Less => Triangle::clock_order(self.b, other.a, other.b), + Ordering::Equal => Triangle::clock_order(self.b, self.a, other.a), + Ordering::Greater => Triangle::clock_order(other.b, self.b, self.a), } } #[inline] - pub(crate) fn is_under_point_order(&self, p: IntPoint) -> Ordering { + pub(crate) fn is_under_point_order(&self, p: IntPoint) -> Ordering { debug_assert!(self.a.x <= p.x && p.x <= self.b.x); - Triangle::clock_order_point(self.a, p, self.b) + Triangle::clock_order(self.a, p, self.b) } } -impl PartialOrd for VSegment { +impl PartialOrd for VSegment { #[inline] fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } } -impl Ord for VSegment { +impl Ord for VSegment { #[inline] fn cmp(&self, other: &Self) -> Ordering { self.is_under_segment_order(other) } } -impl Default for VSegment { +impl Default for VSegment { #[inline] fn default() -> Self { Self { diff --git a/iTriangle/src/int/solver.rs b/iTriangle/src/int/solver.rs index 2d49bc9..631541d 100644 --- a/iTriangle/src/int/solver.rs +++ b/iTriangle/src/int/solver.rs @@ -4,9 +4,12 @@ use crate::int::triangulation::RawIntTriangulation; use crate::int::unchecked::IntUncheckedTriangulatable; use crate::int::validation::Validation; use alloc::vec::Vec; +use i_key_sort::sort::key::SortKey; use i_overlay::core::simplify::Simplify; +use i_overlay::i_float::int::number::int::IntNumber; use i_overlay::i_float::int::point::IntPoint; use i_overlay::i_shape::int::shape::{IntContour, IntShape, IntShapes}; +use i_tree::{Expiration, LayoutNumber}; pub(super) struct ShapesSolver; pub(super) struct ShapeSolver; @@ -14,12 +17,17 @@ pub(super) struct ContourSolver; impl ShapesSolver { #[inline] - pub(super) fn triangulate(validation: Validation, shapes: &IntShapes) -> RawIntTriangulation { + pub(super) fn triangulate( + validation: Validation, + shapes: &IntShapes, + ) -> RawIntTriangulation { let shapes = shapes.simplify(validation.fill_rule, validation.options); Self::uncheck_triangulate(&shapes) } - pub(super) fn uncheck_triangulate(shapes: &IntShapes) -> RawIntTriangulation { + pub(super) fn uncheck_triangulate( + shapes: &IntShapes, + ) -> RawIntTriangulation { if shapes.len() <= 1 { return if let Some(first) = shapes.first() { first.uncheck_triangulate() @@ -60,20 +68,22 @@ impl ShapesSolver { } #[inline] - pub(super) fn triangulate_with_steiner_points( - validation: Validation, - shapes: &IntShapes, - points: &[IntPoint], - ) -> RawIntTriangulation { + pub(super) fn triangulate_with_steiner_points< + I: IntNumber + Expiration + LayoutNumber + SortKey, + >( + validation: Validation, + shapes: &IntShapes, + points: &[IntPoint], + ) -> RawIntTriangulation { shapes .simplify(validation.fill_rule, validation.options) .uncheck_triangulate_with_steiner_points(points) } - pub(super) fn uncheck_triangulate_with_steiner_points( - shapes: &IntShapes, - groups: &[Vec], - ) -> RawIntTriangulation { + pub(super) fn uncheck_triangulate_with_steiner_points( + shapes: &IntShapes, + groups: &[Vec>], + ) -> RawIntTriangulation { if shapes.len() <= 1 { return if let Some(first) = shapes.first() { first.uncheck_triangulate_with_steiner_points(&groups[0]) @@ -123,34 +133,41 @@ impl ShapesSolver { impl ShapeSolver { #[inline] - pub(super) fn triangulate(validation: Validation, shape: &IntShape) -> RawIntTriangulation { + pub(super) fn triangulate( + validation: Validation, + shape: &IntShape, + ) -> RawIntTriangulation { let shapes = shape.simplify(validation.fill_rule, validation.options); ShapesSolver::uncheck_triangulate(&shapes) } #[inline] - pub(super) fn uncheck_triangulate(shape: &IntShape) -> RawIntTriangulation { + pub(super) fn uncheck_triangulate( + shape: &IntShape, + ) -> RawIntTriangulation { let mut raw = RawIntTriangulation::default(); MonotoneTriangulator::default().shape_into_net_triangulation(shape, None, &mut raw); raw } #[inline] - pub(super) fn triangulate_with_steiner_points( - validation: Validation, - shape: &IntShape, - points: &[IntPoint], - ) -> RawIntTriangulation { + pub(super) fn triangulate_with_steiner_points< + I: IntNumber + Expiration + LayoutNumber + SortKey, + >( + validation: Validation, + shape: &IntShape, + points: &[IntPoint], + ) -> RawIntTriangulation { shape .simplify(validation.fill_rule, validation.options) .uncheck_triangulate_with_steiner_points(points) } #[inline] - pub(super) fn uncheck_triangulate_with_steiner_points( - shape: &IntShape, - points: &[IntPoint], - ) -> RawIntTriangulation { + pub(super) fn uncheck_triangulate_with_steiner_points( + shape: &IntShape, + points: &[IntPoint], + ) -> RawIntTriangulation { if shape.len() <= 1 { return if let Some(first) = shape.first() { first.uncheck_triangulate_with_steiner_points(points) @@ -166,14 +183,19 @@ impl ShapeSolver { impl ContourSolver { #[inline] - pub(super) fn triangulate(validation: Validation, contour: &IntContour) -> RawIntTriangulation { + pub(super) fn triangulate( + validation: Validation, + contour: &IntContour, + ) -> RawIntTriangulation { contour .simplify(validation.fill_rule, validation.options) .uncheck_triangulate() } #[inline] - pub(super) fn uncheck_triangulate(contour: &IntContour) -> RawIntTriangulation { + pub(super) fn uncheck_triangulate( + contour: &IntContour, + ) -> RawIntTriangulation { if contour.len() < 3 { RawIntTriangulation::default() } else { @@ -184,21 +206,23 @@ impl ContourSolver { } #[inline] - pub(super) fn triangulate_with_steiner_points( - validation: Validation, - contour: &IntContour, - points: &[IntPoint], - ) -> RawIntTriangulation { + pub(super) fn triangulate_with_steiner_points< + I: IntNumber + Expiration + LayoutNumber + SortKey, + >( + validation: Validation, + contour: &IntContour, + points: &[IntPoint], + ) -> RawIntTriangulation { contour .simplify(validation.fill_rule, validation.options) .uncheck_triangulate_with_steiner_points(points) } #[inline] - pub(super) fn uncheck_triangulate_with_steiner_points( - contour: &IntContour, - points: &[IntPoint], - ) -> RawIntTriangulation { + pub(super) fn uncheck_triangulate_with_steiner_points( + contour: &IntContour, + points: &[IntPoint], + ) -> RawIntTriangulation { if contour.len() < 3 { Default::default() } else { diff --git a/iTriangle/src/int/triangulatable.rs b/iTriangle/src/int/triangulatable.rs index db9c858..e91e292 100644 --- a/iTriangle/src/int/triangulatable.rs +++ b/iTriangle/src/int/triangulatable.rs @@ -1,7 +1,10 @@ use crate::int::solver::{ContourSolver, ShapeSolver, ShapesSolver}; use crate::int::triangulation::RawIntTriangulation; +use i_key_sort::sort::key::SortKey; +use i_overlay::i_float::int::number::int::IntNumber; use i_overlay::i_float::int::point::IntPoint; use i_overlay::i_shape::int::shape::{IntContour, IntShape, IntShapes}; +use i_tree::{Expiration, LayoutNumber}; /// A trait for performing triangulation with default validation settings. /// /// Provides a simplified interface for converting shapes or contours into triangle meshes. @@ -20,50 +23,50 @@ use i_overlay::i_shape::int::shape::{IntContour, IntShape, IntShapes}; /// /// # Steiner Points /// Use [`triangulate_with_steiner_points`] to inject additional internal points during triangulation. -pub trait IntTriangulatable { +pub trait IntTriangulatable { /// Triangulates the shape(s) with automatic validation and cleanup. /// /// Uses the default [`DisposableTriangulator`] (non-zero fill rule, zero area threshold). - fn triangulate(&self) -> RawIntTriangulation; + fn triangulate(&self) -> RawIntTriangulation; /// Triangulates the shape(s) with inserted Steiner points. /// /// Points must lie within the shape's valid interior area (not on edges). - fn triangulate_with_steiner_points(&self, points: &[IntPoint]) -> RawIntTriangulation; + fn triangulate_with_steiner_points(&self, points: &[IntPoint]) -> RawIntTriangulation; } -impl IntTriangulatable for IntContour { +impl IntTriangulatable for IntContour { #[inline] - fn triangulate(&self) -> RawIntTriangulation { + fn triangulate(&self) -> RawIntTriangulation { ContourSolver::triangulate(Default::default(), self) } #[inline] - fn triangulate_with_steiner_points(&self, points: &[IntPoint]) -> RawIntTriangulation { + fn triangulate_with_steiner_points(&self, points: &[IntPoint]) -> RawIntTriangulation { ContourSolver::triangulate_with_steiner_points(Default::default(), self, points) } } -impl IntTriangulatable for IntShape { +impl IntTriangulatable for IntShape { #[inline] - fn triangulate(&self) -> RawIntTriangulation { + fn triangulate(&self) -> RawIntTriangulation { ShapeSolver::triangulate(Default::default(), self) } #[inline] - fn triangulate_with_steiner_points(&self, points: &[IntPoint]) -> RawIntTriangulation { + fn triangulate_with_steiner_points(&self, points: &[IntPoint]) -> RawIntTriangulation { ShapeSolver::triangulate_with_steiner_points(Default::default(), self, points) } } -impl IntTriangulatable for IntShapes { +impl IntTriangulatable for IntShapes { #[inline] - fn triangulate(&self) -> RawIntTriangulation { + fn triangulate(&self) -> RawIntTriangulation { ShapesSolver::triangulate(Default::default(), self) } #[inline] - fn triangulate_with_steiner_points(&self, points: &[IntPoint]) -> RawIntTriangulation { + fn triangulate_with_steiner_points(&self, points: &[IntPoint]) -> RawIntTriangulation { ShapesSolver::triangulate_with_steiner_points(Default::default(), self, points) } } diff --git a/iTriangle/src/int/triangulation.rs b/iTriangle/src/int/triangulation.rs index 68c7022..b68a441 100644 --- a/iTriangle/src/int/triangulation.rs +++ b/iTriangle/src/int/triangulation.rs @@ -2,6 +2,8 @@ use crate::advanced::delaunay::IntDelaunay; use crate::geom::triangle::IntTriangle; use alloc::vec::Vec; use core::iter::FusedIterator; +use i_overlay::i_float::int::number::int::IntNumber; +use i_overlay::i_float::int::number::wide_int::WideIntNumber; use i_overlay::i_float::int::point::IntPoint; use i_overlay::i_float::triangle::Triangle; use i_overlay::i_shape::util::reserve::Reserve; @@ -74,10 +76,20 @@ impl IndexType for usize { } } -#[derive(Debug, Clone, Default)] -pub struct IntTriangulation { - pub points: Vec, - pub indices: Vec, +#[derive(Debug, Clone)] +pub struct IntTriangulation { + pub points: Vec>, + pub indices: Vec, +} + +impl Default for IntTriangulation { + #[inline] + fn default() -> Self { + Self { + points: Vec::new(), + indices: Vec::new(), + } + } } /// Iterator over resolved triangles in a flat [`IntTriangulation`]. @@ -85,13 +97,13 @@ pub struct IntTriangulation { /// Each item contains the three triangle points addressed by one consecutive /// triple in the triangulation index buffer. #[derive(Clone)] -pub struct IntTriangleIterator<'a, I> { - points: &'a [IntPoint], - indices: core::slice::ChunksExact<'a, I>, +pub struct IntTriangleIterator<'a, I: IntNumber, N> { + points: &'a [IntPoint], + indices: core::slice::ChunksExact<'a, N>, } -impl Iterator for IntTriangleIterator<'_, I> { - type Item = [IntPoint; 3]; +impl Iterator for IntTriangleIterator<'_, I, N> { + type Item = [IntPoint; 3]; #[inline] fn next(&mut self) -> Option { @@ -108,14 +120,14 @@ impl Iterator for IntTriangleIterator<'_, I> { } } -impl ExactSizeIterator for IntTriangleIterator<'_, I> { +impl ExactSizeIterator for IntTriangleIterator<'_, I, N> { #[inline] fn len(&self) -> usize { self.indices.len() } } -impl FusedIterator for IntTriangleIterator<'_, I> {} +impl FusedIterator for IntTriangleIterator<'_, I, N> {} /// A int triangle mesh produced by the triangulation process. /// @@ -125,15 +137,25 @@ impl FusedIterator for IntTriangleIterator<'_, I> {} /// /// Use this when you need detailed control over topology, neighbor tracking, or /// advanced mesh manipulation. -#[derive(Debug, Default)] -pub struct RawIntTriangulation { - pub(crate) triangles: Vec, - pub(crate) points: Vec, +#[derive(Debug)] +pub struct RawIntTriangulation { + pub(crate) triangles: Vec>, + pub(crate) points: Vec>, +} + +impl Default for RawIntTriangulation { + #[inline] + fn default() -> Self { + Self { + triangles: Vec::new(), + points: Vec::new(), + } + } } -impl RawIntTriangulation { +impl RawIntTriangulation { #[inline] - pub(super) fn new(triangles: Vec, points: Vec) -> Self { + pub(super) fn new(triangles: Vec>, points: Vec>) -> Self { Self { triangles, points } } @@ -147,7 +169,7 @@ impl RawIntTriangulation { /// /// Each point corresponds to a coordinate used by one or more triangles. #[inline] - pub fn points(&self) -> &Vec { + pub fn points(&self) -> &Vec> { &self.points } @@ -155,7 +177,7 @@ impl RawIntTriangulation { /// /// Each triangle contributes 3 indices into the `points` buffer. #[inline] - pub fn triangle_indices(&self) -> Vec { + pub fn triangle_indices(&self) -> Vec { let mut indices = Vec::new(); self.triangles.feed_indices(self.points.len(), &mut indices); indices @@ -174,7 +196,7 @@ impl RawIntTriangulation { /// /// Returns a [`IntTriangulation`] with separate index buffer and point list. #[inline] - pub fn into_triangulation(self) -> IntTriangulation { + pub fn into_triangulation(self) -> IntTriangulation { IntTriangulation { indices: self.triangle_indices(), points: self.points, @@ -185,7 +207,7 @@ impl RawIntTriangulation { /// /// Returns a [`IntTriangulation`] with separate index buffer and point list. #[inline] - pub fn to_triangulation(&self) -> IntTriangulation { + pub fn to_triangulation(&self) -> IntTriangulation { IntTriangulation { indices: self.triangle_indices(), points: self.points.as_slice().to_vec(), @@ -204,7 +226,7 @@ impl RawIntTriangulation { } } } -impl IntTriangulation { +impl IntTriangulation { #[inline] pub fn empty() -> Self { Self { @@ -223,7 +245,7 @@ impl IntTriangulation { #[inline] pub fn join(&mut self, other: &Self) { - let points_offset = I::try_from(self.points.len()).unwrap_or(I::ZERO); + let points_offset = N::try_from(self.points.len()).unwrap_or(N::ZERO); for &i in other.indices.iter() { self.indices.push(i.add(points_offset)); } @@ -235,7 +257,7 @@ impl IntTriangulation { /// The iterator walks `indices` in exact triples and yields the matching /// `[IntPoint; 3]` for each triangle. #[inline] - pub fn triangles(&self) -> IntTriangleIterator<'_, I> { + pub fn triangles(&self) -> IntTriangleIterator<'_, I, N> { IntTriangleIterator { points: &self.points, indices: self.indices.chunks_exact(3), @@ -251,7 +273,7 @@ impl IntTriangulation { } #[inline] - pub fn fill_with_raw(&mut self, triangulation: &RawIntTriangulation) { + pub fn fill_with_raw(&mut self, triangulation: &RawIntTriangulation) { self.points.clear(); self.points.extend_from_slice(&triangulation.points); @@ -261,7 +283,7 @@ impl IntTriangulation { } #[inline] - pub fn fill_with_delaunay(&mut self, delaunay: &IntDelaunay) { + pub fn fill_with_delaunay(&mut self, delaunay: &IntDelaunay) { self.points.clear(); self.points.extend_from_slice(&delaunay.points); @@ -310,16 +332,16 @@ mod tests { } pub(crate) trait IndicesBuilder { - fn feed_indices(&self, max_count: usize, indices: &mut Vec); + fn feed_indices(&self, max_count: usize, indices: &mut Vec); } -impl IndicesBuilder for [IntTriangle] { +impl IndicesBuilder for [IntTriangle] { #[inline] - fn feed_indices(&self, max_count: usize, indices: &mut Vec) { - if max_count > I::MAX { + fn feed_indices(&self, max_count: usize, indices: &mut Vec) { + if max_count > N::MAX { panic!( "Index type `{}` cannot hold {} points", - core::any::type_name::(), + core::any::type_name::(), max_count ); } @@ -329,9 +351,9 @@ impl IndicesBuilder for [IntTriangle] { indices.clear(); for t in self.iter() { - let i0 = unsafe { I::try_from(t.vertices[0].index).unwrap_unchecked() }; - let i1 = unsafe { I::try_from(t.vertices[1].index).unwrap_unchecked() }; - let i2 = unsafe { I::try_from(t.vertices[2].index).unwrap_unchecked() }; + let i0 = unsafe { N::try_from(t.vertices[0].index).unwrap_unchecked() }; + let i1 = unsafe { N::try_from(t.vertices[1].index).unwrap_unchecked() }; + let i2 = unsafe { N::try_from(t.vertices[2].index).unwrap_unchecked() }; indices.push(i0); indices.push(i1); indices.push(i2); @@ -339,14 +361,14 @@ impl IndicesBuilder for [IntTriangle] { } } -impl RawIntTriangulation { +impl RawIntTriangulation { pub fn validate(&self) { for (i, t) in self.triangles.iter().enumerate() { let a = t.vertices[0].point; let b = t.vertices[1].point; let c = t.vertices[2].point; - let area = Triangle::area_two_point(a, b, c); - assert!(area <= 0); + let area = Triangle::area_two(a, b, c); + assert!(area >= I::Wide::ZERO); let n0 = t.neighbors[0]; let n1 = t.neighbors[1]; @@ -364,23 +386,23 @@ impl RawIntTriangulation { } } - pub fn area_two(&self) -> i64 { - let mut s = 0; + pub fn area_two(&self) -> I::Wide { + let mut s = I::Wide::ZERO; for t in self.triangles.iter() { let a = t.vertices[0].point; let b = t.vertices[1].point; let c = t.vertices[2].point; - s += Triangle::area_two_point(a, b, c); + s = s + Triangle::area_two(a, b, c); } s } } #[cfg(test)] -impl IntTriangulation { - pub fn validate(&self, shape_x2_area: i64) { - let mut s = 0; +impl IntTriangulation { + pub fn validate(&self, shape_x2_area: I::Wide) { + let mut s = I::Wide::ZERO; let mut i = 0; while i < self.indices.len() { let ai = self.indices[i]; @@ -394,9 +416,9 @@ impl IntTriangulation { let b = self.points[bi.into_usize()]; let c = self.points[ci.into_usize()]; - let abc = Triangle::area_two_point(a, b, c); + let abc = Triangle::area_two(a, b, c); - assert!(abc < 0); + assert!(abc > I::Wide::ZERO); s = s + abc; } diff --git a/iTriangle/src/int/triangulator.rs b/iTriangle/src/int/triangulator.rs index 3ef1b6d..3da5fcf 100644 --- a/iTriangle/src/int/triangulator.rs +++ b/iTriangle/src/int/triangulator.rs @@ -3,27 +3,34 @@ use crate::int::earcut::earcut_64::Earcut64; use crate::int::monotone::triangulator::MonotoneTriangulator; use crate::int::triangulation::{IndexType, IntTriangulation, RawIntTriangulation}; use crate::int::validation::Validation; +use i_key_sort::sort::key::SortKey; use i_overlay::core::fill_rule::FillRule; use i_overlay::core::overlay::Overlay; use i_overlay::core::solver::Solver; +use i_overlay::i_float::int::number::int::IntNumber; use i_overlay::i_float::int::point::IntPoint; use i_overlay::i_shape::flat::buffer::FlatContoursBuffer; use i_overlay::i_shape::int::shape::{IntContour, IntShape, IntShapes}; +use i_tree::{Expiration, LayoutNumber}; -pub struct IntTriangulator { - pub overlay: Overlay, +pub struct IntTriangulator { + pub overlay: Overlay, pub fill_rule: FillRule, pub earcut: bool, pub delaunay: bool, - triangulator: MonotoneTriangulator, - shapes_buffer: Option>, - raw_buffer: Option, + triangulator: MonotoneTriangulator, + shapes_buffer: Option>, + raw_buffer: Option>, delaunay_buffer: DelaunayBuffer, } -impl IntTriangulator { +impl IntTriangulator +where + I: IntNumber + Expiration + LayoutNumber + SortKey, + N: IndexType, +{ #[inline] - pub fn new(max_points_count: usize, validation: Validation, solver: Solver) -> Self { + pub fn new(max_points_count: usize, validation: Validation, solver: Solver) -> Self { Self { overlay: Overlay::new_custom(max_points_count, validation.options, solver), fill_rule: validation.fill_rule, @@ -37,16 +44,24 @@ impl IntTriangulator { } } -impl Default for IntTriangulator { +impl Default for IntTriangulator +where + I: IntNumber + Expiration + LayoutNumber + SortKey, + N: IndexType, +{ #[inline] fn default() -> Self { Self::new(64, Default::default(), Default::default()) } } -impl IntTriangulator { +impl IntTriangulator +where + I: IntNumber + Expiration + LayoutNumber + SortKey, + N: IndexType, +{ #[inline] - pub fn triangulate_contour(&mut self, contour: &IntContour) -> IntTriangulation { + pub fn triangulate_contour(&mut self, contour: &IntContour) -> IntTriangulation { match self.overlay.simplify_contour(contour, self.fill_rule) { None => self.uncheck_triangulate_contour(contour), Some(shapes) => self.uncheck_triangulate_shapes(&shapes), @@ -56,8 +71,8 @@ impl IntTriangulator { #[inline] pub fn triangulate_contour_into( &mut self, - contour: IntContour, - triangulation: &mut IntTriangulation, + contour: IntContour, + triangulation: &mut IntTriangulation, ) { match self.overlay.simplify_contour(&contour, self.fill_rule) { None => self.uncheck_triangulate_contour_into(&contour, triangulation), @@ -66,7 +81,7 @@ impl IntTriangulator { } #[inline] - pub fn triangulate_shape(&mut self, shape: &IntShape) -> IntTriangulation { + pub fn triangulate_shape(&mut self, shape: &IntShape) -> IntTriangulation { match self.overlay.simplify_shape(shape, self.fill_rule) { None => self.uncheck_triangulate_shape(shape), Some(shapes) => self.uncheck_triangulate_shapes(&shapes), @@ -76,8 +91,8 @@ impl IntTriangulator { #[inline] pub fn triangulate_shape_into( &mut self, - shape: &IntShape, - triangulation: &mut IntTriangulation, + shape: &IntShape, + triangulation: &mut IntTriangulation, ) { match self.overlay.simplify_shape(shape, self.fill_rule) { None => self.uncheck_triangulate_shape_into(shape, triangulation), @@ -86,7 +101,7 @@ impl IntTriangulator { } #[inline] - pub fn triangulate_shapes(&mut self, shapes: &IntShapes) -> IntTriangulation { + pub fn triangulate_shapes(&mut self, shapes: &IntShapes) -> IntTriangulation { let simple = self.overlay.simplify_shapes(shapes, self.fill_rule); self.uncheck_triangulate_shapes(&simple) } @@ -94,15 +109,15 @@ impl IntTriangulator { #[inline] pub fn triangulate_shapes_into( &mut self, - shapes: &IntShapes, - triangulation: &mut IntTriangulation, + shapes: &IntShapes, + triangulation: &mut IntTriangulation, ) { let simple = self.overlay.simplify_shapes(shapes, self.fill_rule); self.uncheck_triangulate_shapes_into(&simple, triangulation); } #[inline] - pub fn triangulate_flat(&mut self, flat: &mut FlatContoursBuffer) -> IntTriangulation { + pub fn triangulate_flat(&mut self, flat: &mut FlatContoursBuffer) -> IntTriangulation { self.overlay.simplify_flat_buffer(flat, self.fill_rule); self.uncheck_triangulate_flat(flat) } @@ -110,17 +125,24 @@ impl IntTriangulator { #[inline] pub fn triangulate_flat_into( &mut self, - flat: &mut FlatContoursBuffer, - triangulation: &mut IntTriangulation, + flat: &mut FlatContoursBuffer, + triangulation: &mut IntTriangulation, ) { self.overlay.simplify_flat_buffer(flat, self.fill_rule); self.uncheck_triangulate_flat_into(flat, triangulation); } } -impl IntTriangulator { +impl IntTriangulator +where + I: IntNumber + Expiration + LayoutNumber + SortKey, + N: IndexType, +{ #[inline] - pub fn uncheck_triangulate_contour(&mut self, contour: &IntContour) -> IntTriangulation { + pub fn uncheck_triangulate_contour( + &mut self, + contour: &IntContour, + ) -> IntTriangulation { let mut triangulation = Default::default(); self.uncheck_triangulate_contour_into(contour, &mut triangulation); triangulation @@ -129,8 +151,8 @@ impl IntTriangulator { #[inline] pub fn uncheck_triangulate_contour_into( &mut self, - contour: &IntContour, - triangulation: &mut IntTriangulation, + contour: &IntContour, + triangulation: &mut IntTriangulation, ) { if self.delaunay { let mut raw = self.raw_buffer.take().unwrap_or_default(); @@ -152,7 +174,7 @@ impl IntTriangulator { } #[inline] - pub fn uncheck_triangulate_shape(&mut self, shape: &IntShape) -> IntTriangulation { + pub fn uncheck_triangulate_shape(&mut self, shape: &IntShape) -> IntTriangulation { let mut triangulation = Default::default(); self.uncheck_triangulate_shape_into(shape, &mut triangulation); triangulation @@ -161,8 +183,8 @@ impl IntTriangulator { #[inline] pub fn uncheck_triangulate_shape_into( &mut self, - shape: &IntShape, - triangulation: &mut IntTriangulation, + shape: &IntShape, + triangulation: &mut IntTriangulation, ) { if shape.len() == 1 { self.uncheck_triangulate_contour_into(&shape[0], triangulation); @@ -183,7 +205,7 @@ impl IntTriangulator { } #[inline] - pub fn uncheck_triangulate_shapes(&mut self, shapes: &IntShapes) -> IntTriangulation { + pub fn uncheck_triangulate_shapes(&mut self, shapes: &IntShapes) -> IntTriangulation { let mut triangulation = Default::default(); self.uncheck_triangulate_shapes_into(shapes, &mut triangulation); triangulation @@ -192,8 +214,8 @@ impl IntTriangulator { #[inline] pub fn uncheck_triangulate_shapes_into( &mut self, - shapes: &IntShapes, - triangulation: &mut IntTriangulation, + shapes: &IntShapes, + triangulation: &mut IntTriangulation, ) { if shapes.len() == 1 { self.uncheck_triangulate_shape_into(&shapes[0], triangulation); @@ -214,8 +236,8 @@ impl IntTriangulator { #[inline] pub fn uncheck_triangulate_flat( &mut self, - flat_buffer: &FlatContoursBuffer, - ) -> IntTriangulation { + flat_buffer: &FlatContoursBuffer, + ) -> IntTriangulation { let mut triangulation = Default::default(); self.uncheck_triangulate_flat_into(flat_buffer, &mut triangulation); triangulation @@ -224,8 +246,8 @@ impl IntTriangulator { #[inline] pub fn uncheck_triangulate_flat_into( &mut self, - flat: &FlatContoursBuffer, - triangulation: &mut IntTriangulation, + flat: &FlatContoursBuffer, + triangulation: &mut IntTriangulation, ) { if flat.is_empty() { triangulation.reserve_and_clear(0); @@ -258,14 +280,14 @@ trait Earcut64Compatible { fn is_earcut_compatible(&self) -> bool; } -impl Earcut64Compatible for FlatContoursBuffer { +impl Earcut64Compatible for FlatContoursBuffer { #[inline(always)] fn is_earcut_compatible(&self) -> bool { self.is_single_contour() && self.points.len() <= 64 } } -impl Earcut64Compatible for [IntPoint] { +impl Earcut64Compatible for [IntPoint] { #[inline(always)] fn is_earcut_compatible(&self) -> bool { self.len() <= 64 diff --git a/iTriangle/src/int/unchecked.rs b/iTriangle/src/int/unchecked.rs index b447439..034949b 100644 --- a/iTriangle/src/int/unchecked.rs +++ b/iTriangle/src/int/unchecked.rs @@ -1,8 +1,11 @@ use crate::int::binder::SteinerInference; use crate::int::solver::{ContourSolver, ShapeSolver, ShapesSolver}; use crate::int::triangulation::RawIntTriangulation; +use i_key_sort::sort::key::SortKey; +use i_overlay::i_float::int::number::int::IntNumber; use i_overlay::i_float::int::point::IntPoint; use i_overlay::i_shape::int::shape::{IntContour, IntShape, IntShapes}; +use i_tree::Expiration; /// A trait for performing triangulation on already validated geometry. /// @@ -19,48 +22,60 @@ use i_overlay::i_shape::int::shape::{IntContour, IntShape, IntShapes}; /// - [`IntContour`] /// - [`IntShape`] /// - [`IntShapes`] -pub trait IntUncheckedTriangulatable { +pub trait IntUncheckedTriangulatable { /// Performs triangulation without applying any shape simplification or validation. - fn uncheck_triangulate(&self) -> RawIntTriangulation; + fn uncheck_triangulate(&self) -> RawIntTriangulation; /// Performs triangulation without validation, inserting the given Steiner points. /// /// Points are grouped and applied based on their target shape. - fn uncheck_triangulate_with_steiner_points(&self, points: &[IntPoint]) -> RawIntTriangulation; + fn uncheck_triangulate_with_steiner_points( + &self, + points: &[IntPoint], + ) -> RawIntTriangulation; } -impl IntUncheckedTriangulatable for IntContour { +impl IntUncheckedTriangulatable for IntContour { #[inline] - fn uncheck_triangulate(&self) -> RawIntTriangulation { + fn uncheck_triangulate(&self) -> RawIntTriangulation { ContourSolver::uncheck_triangulate(self) } #[inline] - fn uncheck_triangulate_with_steiner_points(&self, points: &[IntPoint]) -> RawIntTriangulation { + fn uncheck_triangulate_with_steiner_points( + &self, + points: &[IntPoint], + ) -> RawIntTriangulation { ContourSolver::uncheck_triangulate_with_steiner_points(self, points) } } -impl IntUncheckedTriangulatable for IntShape { +impl IntUncheckedTriangulatable for IntShape { #[inline] - fn uncheck_triangulate(&self) -> RawIntTriangulation { + fn uncheck_triangulate(&self) -> RawIntTriangulation { ShapeSolver::uncheck_triangulate(self) } #[inline] - fn uncheck_triangulate_with_steiner_points(&self, points: &[IntPoint]) -> RawIntTriangulation { + fn uncheck_triangulate_with_steiner_points( + &self, + points: &[IntPoint], + ) -> RawIntTriangulation { ShapeSolver::uncheck_triangulate_with_steiner_points(self, points) } } -impl IntUncheckedTriangulatable for IntShapes { +impl IntUncheckedTriangulatable for IntShapes { #[inline] - fn uncheck_triangulate(&self) -> RawIntTriangulation { + fn uncheck_triangulate(&self) -> RawIntTriangulation { ShapesSolver::uncheck_triangulate(self) } #[inline] - fn uncheck_triangulate_with_steiner_points(&self, points: &[IntPoint]) -> RawIntTriangulation { + fn uncheck_triangulate_with_steiner_points( + &self, + points: &[IntPoint], + ) -> RawIntTriangulation { let group = self.group_by_shapes(points); ShapesSolver::uncheck_triangulate_with_steiner_points(self, &group) } diff --git a/iTriangle/src/int/validation.rs b/iTriangle/src/int/validation.rs index 007b031..ab334d0 100644 --- a/iTriangle/src/int/validation.rs +++ b/iTriangle/src/int/validation.rs @@ -1,13 +1,14 @@ use i_overlay::core::fill_rule::FillRule; use i_overlay::core::overlay::IntOverlayOptions; +use i_overlay::i_float::int::number::int::IntNumber; #[derive(Debug, Clone, Copy)] -pub struct Validation { +pub struct Validation { pub fill_rule: FillRule, - pub options: IntOverlayOptions, + pub options: IntOverlayOptions, } -impl Validation { +impl Validation { pub fn with_fill_rule(fill_rule: FillRule) -> Self { Self { fill_rule, @@ -16,7 +17,7 @@ impl Validation { } } -impl Default for Validation { +impl Default for Validation { fn default() -> Self { Self { fill_rule: FillRule::NonZero, diff --git a/iTriangle/src/tessellation/circumcenter.rs b/iTriangle/src/tessellation/circumcenter.rs index a997039..8cce5bf 100644 --- a/iTriangle/src/tessellation/circumcenter.rs +++ b/iTriangle/src/tessellation/circumcenter.rs @@ -3,34 +3,38 @@ use crate::advanced::delaunay::{DelaunayRefine, IntDelaunay}; use crate::geom::point::IndexPoint; use crate::geom::triangle::{Abc, IntTriangle}; use alloc::vec::Vec; -use i_overlay::i_float::float::number::FloatNumber; +use i_overlay::i_float::int::number::int::IntNumber; +use i_overlay::i_float::int::number::wide_int::WideIntNumber; use i_overlay::i_float::int::point::IntPoint; use i_overlay::i_float::triangle::Triangle; -impl IntDelaunay { +impl IntDelaunay { #[inline] - pub fn refine_with_circumcenters(mut self, min_area: u64) -> Self { + pub fn refine_with_circumcenters(mut self, min_area: I::WideUInt) -> Self { self.refine_with_circumcenters_mut(min_area); self } #[inline] - pub fn refine_with_circumcenters_mut(&mut self, min_area: u64) { + pub fn refine_with_circumcenters_mut(&mut self, min_area: I::WideUInt) { self.refine_with_circumcenters_and_selector::(min_area); } #[inline] - pub fn refine_with_circumcenters_by_obtuse_angle(mut self, min_area: u64) -> Self { + pub fn refine_with_circumcenters_by_obtuse_angle(mut self, min_area: I::WideUInt) -> Self { self.refine_with_circumcenters_by_obtuse_angle_mut(min_area); self } #[inline] - pub fn refine_with_circumcenters_by_obtuse_angle_mut(&mut self, min_area: u64) { + pub fn refine_with_circumcenters_by_obtuse_angle_mut(&mut self, min_area: I::WideUInt) { self.refine_with_circumcenters_and_selector::(min_area) } - fn refine_with_circumcenters_and_selector(&mut self, min_area: u64) { + fn refine_with_circumcenters_and_selector>( + &mut self, + min_area: I::WideUInt, + ) { let two_area = min_area << 1; let mut bitset = IndexBitSet::with_size(self.triangles.len()); @@ -59,16 +63,16 @@ impl IntDelaunay { } #[inline] - fn select_edge_for_refinement( + fn select_edge_for_refinement>( &self, - min_area: u64, - abc: &IntTriangle, - ) -> Option { + min_area: I::WideUInt, + abc: &IntTriangle, + ) -> Option> { let a = abc.vertices[0].point; let b = abc.vertices[1].point; let c = abc.vertices[2].point; - let area = Triangle::area_two_point(a, b, c).unsigned_abs(); + let area = Triangle::area_two(a, b, c).unsigned_abs(); if area <= min_area { return None; } @@ -77,7 +81,7 @@ impl IntDelaunay { } #[inline] - fn split_triangle(&mut self, abc_index: usize, abc: Abc, buffer: &mut Vec) { + fn split_triangle(&mut self, abc_index: usize, abc: Abc, buffer: &mut Vec) { let pcb_index = abc.v0.neighbor; if pcb_index < self.triangles.len() { buffer.extend_from_slice(&self.split_triangle_with_neighbor(abc_index, abc, pcb_index)); @@ -89,7 +93,7 @@ impl IntDelaunay { fn split_triangle_with_neighbor( &mut self, abc_index: usize, - abc: Abc, + abc: Abc, pcb_index: usize, ) -> [usize; 4] { let p = abc.circumscribed_center(); @@ -154,7 +158,7 @@ impl IntDelaunay { [abm_index, pcm_index, amc_index, pmb_index] } - fn split_alone_triangle(&mut self, abc_index: usize, abc: Abc) -> [usize; 2] { + fn split_alone_triangle(&mut self, abc_index: usize, abc: Abc) -> [usize; 2] { let m = abc.edge_mid_point(); let m_index = self.points.len(); self.points.push(m); @@ -188,18 +192,18 @@ impl IntDelaunay { } } -impl Abc { +impl Abc { #[inline] - fn circumscribed_center(&self) -> IntPoint { + fn circumscribed_center(&self) -> IntPoint { let a = self.v0.vertex.point; let b = self.v1.vertex.point; let c = self.v2.vertex.point; - let ax = a.x as f64; - let ay = a.y as f64; - let bx = b.x as f64; - let by = b.y as f64; - let cx = c.x as f64; - let cy = c.y as f64; + let ax = a.x.to_f64(); + let ay = a.y.to_f64(); + let bx = b.x.to_f64(); + let by = b.y.to_f64(); + let cx = c.x.to_f64(); + let cy = c.y.to_f64(); let d = 2.0 * (ax * (by - cy) + bx * (cy - ay) + cx * (ay - by)); let aa = ax * ax + ay * ay; @@ -210,43 +214,43 @@ impl Abc { let fx = (aa * (by - cy) + bb * (cy - ay) + cc * (ay - by)) * id; let fy = (aa * (cx - bx) + bb * (ax - cx) + cc * (bx - ax)) * id; - let x = fx.to_i32(); - let y = fy.to_i32(); + let x = I::from_float(fx); + let y = I::from_float(fy); IntPoint::new(x, y) } #[inline] - fn is_contain(&self, p: IntPoint) -> bool { + fn is_contain(&self, p: IntPoint) -> bool { let a = self.v0.vertex.point; let b = self.v1.vertex.point; let c = self.v2.vertex.point; - Triangle::is_contain_point_exclude_borders(p, a, b, c) + Triangle::is_contain_exclude_borders(p, a, b, c) } #[inline] - fn edge_mid_point(&self) -> IntPoint { + fn edge_mid_point(&self) -> IntPoint { let b = self.v1.vertex.point; let c = self.v2.vertex.point; - let x = (b.x as i64 + c.x as i64) >> 1; - let y = (b.y as i64 + c.y as i64) >> 1; + let x = (b.x.wide() + c.x.wide()) >> 1; + let y = (b.y.wide() + c.y.wide()) >> 1; - IntPoint::new(x as i32, y as i32) + IntPoint::new(I::from_wide(x), I::from_wide(y)) } } -trait EdgeSelector { - fn select(abc: &IntTriangle) -> Option; +trait EdgeSelector { + fn select(abc: &IntTriangle) -> Option>; } struct SelectBiggerAngle {} struct SelectObtuseAngle {} -impl EdgeSelector for SelectObtuseAngle { +impl EdgeSelector for SelectObtuseAngle { #[inline] - fn select(abc: &IntTriangle) -> Option { + fn select(abc: &IntTriangle) -> Option> { let a = abc.vertices[0].point; let b = abc.vertices[1].point; let c = abc.vertices[2].point; @@ -267,9 +271,9 @@ impl EdgeSelector for SelectObtuseAngle { } } -impl EdgeSelector for SelectBiggerAngle { +impl EdgeSelector for SelectBiggerAngle { #[inline] - fn select(abc: &IntTriangle) -> Option { + fn select(abc: &IntTriangle) -> Option> { let a = abc.vertices[0].point; let b = abc.vertices[1].point; let c = abc.vertices[2].point; diff --git a/iTriangle/src/tessellation/split.rs b/iTriangle/src/tessellation/split.rs index b6f0c68..7abc9d6 100644 --- a/iTriangle/src/tessellation/split.rs +++ b/iTriangle/src/tessellation/split.rs @@ -1,26 +1,31 @@ use alloc::vec::Vec; +use i_overlay::i_float::int::number::int::IntNumber; +use i_overlay::i_float::int::number::uint::UIntNumber; +use i_overlay::i_float::int::number::wide_int::WideIntNumber; use i_overlay::i_float::int::point::IntPoint; use i_overlay::i_shape::int::shape::{IntContour, IntShape, IntShapes}; -pub trait SliceContour { - fn slice_contour(&self, max_edge_length: u32) -> Self; +pub trait SliceContour { + fn slice_contour(&self, max_edge_length: I::WideUInt) -> Self; } -const SCALE: u32 = 29; - -impl SliceContour for IntContour { +impl SliceContour for IntContour { #[inline] - fn slice_contour(&self, max_edge_length: u32) -> Self { + fn slice_contour(&self, max_edge_length: I::WideUInt) -> Self { let mut a = if let Some(last) = self.last() { *last } else { return Vec::new(); }; - let radius = max_edge_length as u64; - let sqr_radius = radius.pow(2); + let radius = max_edge_length; + if radius > I::WideUInt::HALF_MASK { + return self.clone(); + } + + let sqr_radius = radius * radius; - let mut contour = IntContour::with_capacity(2 * self.len()); + let mut contour = IntContour::::with_capacity(2 * self.len()); for &b in self.iter() { extract(a, b, radius, sqr_radius, &mut contour); @@ -31,9 +36,9 @@ impl SliceContour for IntContour { } } -impl SliceContour for IntShape { +impl SliceContour for IntShape { #[inline] - fn slice_contour(&self, max_edge_length: u32) -> Self { + fn slice_contour(&self, max_edge_length: I::WideUInt) -> Self { let mut shape = Vec::with_capacity(self.len()); for contour in self.iter() { @@ -44,9 +49,9 @@ impl SliceContour for IntShape { } } -impl SliceContour for IntShapes { +impl SliceContour for IntShapes { #[inline] - fn slice_contour(&self, max_edge_length: u32) -> Self { + fn slice_contour(&self, max_edge_length: I::WideUInt) -> Self { let mut shapes = Vec::with_capacity(self.len()); for shape in self.iter() { @@ -58,15 +63,21 @@ impl SliceContour for IntShapes { } #[inline] -fn extract(a: IntPoint, b: IntPoint, radius: u64, sqr_radius: u64, contour: &mut IntContour) { - let ab = b.subtract(a); - let sqr_len = ab.sqr_length() as u64; +fn extract( + a: IntPoint, + b: IntPoint, + radius: I::WideUInt, + sqr_radius: I::WideUInt, + contour: &mut IntContour, +) { + let ab = b - a; + let sqr_len = ab.sqr_length().to_uint(); if sqr_len <= sqr_radius { contour.push(b); return; } - let len = sqr_len.isqrt(); - let n = ((len + (radius >> 1)) / radius) as i64; + let len = i_overlay::i_float::float::number::FloatNumber::sqrt(sqr_len.to_f64()); + let n = ((len + 0.5 * radius.to_f64()) / radius.to_f64()) as usize; if n <= 1 { contour.push(b); @@ -74,26 +85,19 @@ fn extract(a: IntPoint, b: IntPoint, radius: u64, sqr_radius: u64, contour: &mut } if n == 2 { - let x = ((a.x as i64 + b.x as i64) / 2) as i32; - let y = ((a.y as i64 + b.y as i64) / 2) as i32; + let x = I::from_wide((a.x.wide() + b.x.wide()) / I::Wide::TWO); + let y = I::from_wide((a.y.wide() + b.y.wide()) / I::Wide::TWO); contour.push(IntPoint::new(x, y)); contour.push(b); return; } - let sx = (ab.x << SCALE) / n; - let sy = (ab.y << SCALE) / n; - - let mut dx = 0i64; - let mut dy = 0i64; - - for _ in 1..n { - dx += sx; - dy += sy; - - let x = a.x + (dx >> SCALE) as i32; - let y = a.y + (dy >> SCALE) as i32; + let n_w = I::Wide::from_usize(n); + for i in 1..n { + let i_w = I::Wide::from_usize(i); + let x = I::from_wide(a.x.wide() + ab.x * i_w / n_w); + let y = I::from_wide(a.y.wide() + ab.y * i_w / n_w); contour.push(IntPoint::new(x, y)); } @@ -115,19 +119,19 @@ mod tests { IntPoint::new(0, 10), ]; - let s0 = contour.slice_contour(8); + let s0 = contour.slice_contour(8u64); assert_eq!(s0.len(), 4); - let s1 = contour.slice_contour(7); + let s1 = contour.slice_contour(7u64); assert_eq!(s1.len(), 4); - let s2 = contour.slice_contour(6); + let s2 = contour.slice_contour(6u64); assert_eq!(s2.len(), 8); - let s3 = contour.slice_contour(5); + let s3 = contour.slice_contour(5u64); assert_eq!(s3.len(), 8); - let s4 = contour.slice_contour(3); + let s4 = contour.slice_contour(3u64); assert_eq!(s4.len(), 12); } } diff --git a/iTriangle/tests/float_tests.rs b/iTriangle/tests/float_tests.rs index b36e1d3..9d372e6 100644 --- a/iTriangle/tests/float_tests.rs +++ b/iTriangle/tests/float_tests.rs @@ -1,16 +1,29 @@ #[cfg(test)] mod tests { + use i_key_sort::sort::key::SortKey; use i_overlay::core::fill_rule::FillRule; use i_overlay::float::simplify::SimplifyShape; + use i_overlay::i_float::int::number::int::IntNumber; use i_overlay::i_shape::base::data::Contour; use i_overlay::i_shape::float::area::Area; + use i_tree::{Expiration, LayoutNumber}; use i_triangle::float::triangulatable::Triangulatable; use i_triangle::float::triangulation::Triangulation; use i_triangle::float::triangulator::Triangulator; use rand::RngExt; + trait TestInt: IntNumber + Expiration + LayoutNumber + SortKey {} + + impl TestInt for I where I: IntNumber + Expiration + LayoutNumber + SortKey {} + #[test] fn test_0() { + test_0_as::(); + test_0_as::(); + test_0_as::(); + } + + fn test_0_as() { let shape = [[ [1.0, 1.0], [1.0, 4.0], @@ -22,7 +35,10 @@ mod tests { .to_vec()] .to_vec(); - let triangulation = shape.triangulate().to_triangulation::(); + let triangulation = shape + .as_slice() + .triangulate_as::() + .to_triangulation::(); assert_eq!(triangulation.points.len(), 6); assert_eq!(triangulation.indices.len(), 12); @@ -30,9 +46,15 @@ mod tests { #[test] fn test_1() { + test_1_as::(); + test_1_as::(); + test_1_as::(); + } + + fn test_1_as() { let contour = [[0.0, 2.0], [0.0, 0.0], [4.0, 2.0], [4.0, 0.0]]; - let mut triangulator = Triangulator::::default(); + let mut triangulator = Triangulator::::default(); triangulator.delaunay(false); let t0 = triangulator.triangulate(&contour); @@ -48,6 +70,12 @@ mod tests { #[test] fn test_2() { + test_2_as::(); + test_2_as::(); + test_2_as::(); + } + + fn test_2_as() { let contour = [ [0.0, 3.0], [-4.0, -3.0], @@ -59,7 +87,7 @@ mod tests { let simple = contour.simplify_shape(FillRule::NonZero); let area = simple.area(); - let mut triangulator = Triangulator::::default(); + let mut triangulator = Triangulator::::default(); triangulator.delaunay(false); let t0 = triangulator.triangulate(&contour); @@ -73,9 +101,15 @@ mod tests { #[test] fn test_3() { + test_3_as::(); + test_3_as::(); + test_3_as::(); + } + + fn test_3_as() { let contour = [[2.0, 3.0], [2.0, -2.0], [0.0, 3.0], [-1.0, 4.0], [0.0, 1.0]]; - let mut triangulator = Triangulator::::default(); + let mut triangulator = Triangulator::::default(); triangulator.delaunay(false); let t0 = triangulator.triangulate(&contour); @@ -91,7 +125,13 @@ mod tests { #[test] fn test_random_0() { - let mut triangulator = Triangulator::::default(); + test_random_0_as::(); + test_random_0_as::(); + test_random_0_as::(); + } + + fn test_random_0_as() { + let mut triangulator = Triangulator::::default(); let mut t = Triangulation::with_capacity(8); for _ in 0..20_000 { @@ -110,7 +150,13 @@ mod tests { #[test] fn test_random_1() { - let mut triangulator = Triangulator::::default(); + test_random_1_as::(); + test_random_1_as::(); + test_random_1_as::(); + } + + fn test_random_1_as() { + let mut triangulator = Triangulator::::default(); let mut t = Triangulation::with_capacity(8); for _ in 0..20_000 { @@ -129,7 +175,13 @@ mod tests { #[test] fn test_random_2() { - let mut triangulator = Triangulator::::default(); + test_random_2_as::(); + test_random_2_as::(); + test_random_2_as::(); + } + + fn test_random_2_as() { + let mut triangulator = Triangulator::::default(); let mut t = Triangulation::with_capacity(8); for _ in 0..20_000 { @@ -148,7 +200,13 @@ mod tests { #[test] fn test_random_3() { - let mut triangulator = Triangulator::::default(); + test_random_3_as::(); + test_random_3_as::(); + test_random_3_as::(); + } + + fn test_random_3_as() { + let mut triangulator = Triangulator::::default(); let mut t = Triangulation::with_capacity(8); for _ in 0..10_000 { @@ -167,7 +225,13 @@ mod tests { #[test] fn test_random_4() { - let mut triangulator = Triangulator::::default(); + test_random_4_as::(); + test_random_4_as::(); + test_random_4_as::(); + } + + fn test_random_4_as() { + let mut triangulator = Triangulator::::default(); let mut t = Triangulation::with_capacity(8); for _ in 0..1_000 { @@ -186,7 +250,13 @@ mod tests { #[test] fn test_random_5() { - let mut triangulator = Triangulator::::default(); + test_random_5_as::(); + test_random_5_as::(); + test_random_5_as::(); + } + + fn test_random_5_as() { + let mut triangulator = Triangulator::::default(); let mut t = Triangulation::with_capacity(8); for _ in 0..500 { diff --git a/readme/architecture.png b/readme/architecture.png deleted file mode 100644 index 6820197..0000000 Binary files a/readme/architecture.png and /dev/null differ diff --git a/readme/architecture.svg b/readme/architecture.svg new file mode 100644 index 0000000..3aa236c --- /dev/null +++ b/readme/architecture.svg @@ -0,0 +1,435 @@ + + + + iTriangle architecture overview + Input contours are normalized, sweep-line triangulated, optionally refined into Delaunay, tessellation, convex decomposition, centroid net, and triangle index outputs. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Input + contours + + + + Normalize + fix intersections + + + + Sweep-line + triangulation + + + + Raw + triangulation + + + + Delaunay + triangulation + + + + Tessellation + refinement + + + + Convex + decomposition + + + + Centroid + net + + + + Triangles + and indices + + + + + iTriangle architecture overview + + + +