From 132c02c1f62eeb34d12b1fab2815acfca77c5ec7 Mon Sep 17 00:00:00 2001 From: Nail Sharipov Date: Sat, 2 May 2026 15:13:16 +0300 Subject: [PATCH 1/2] migrate to new FloatPointCompatible api --- iTriangle/Cargo.toml | 4 +- iTriangle/README.md | 82 ++++++++++++++++++++++++++- iTriangle/src/float/centroid_net.rs | 5 +- iTriangle/src/float/circumcenter.rs | 11 ++-- iTriangle/src/float/convex.rs | 3 +- iTriangle/src/float/custom.rs | 49 ++++++++-------- iTriangle/src/float/delaunay.rs | 11 ++-- iTriangle/src/float/triangulatable.rs | 49 ++++++++-------- iTriangle/src/float/triangulation.rs | 36 ++++++------ iTriangle/src/float/triangulator.rs | 34 +++++------ iTriangle/src/float/unchecked.rs | 49 ++++++++-------- 11 files changed, 197 insertions(+), 136 deletions(-) diff --git a/iTriangle/Cargo.toml b/iTriangle/Cargo.toml index 8b77379..3facf03 100644 --- a/iTriangle/Cargo.toml +++ b/iTriangle/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "i_triangle" -version = "0.42.0" +version = "0.43.0" edition = "2021" authors = ["Nail Sharipov "] description = "Polygon Triangulation Library: Efficient Delaunay Triangulation for Complex Shapes." @@ -24,7 +24,7 @@ serde = { version = "^1.0", default-features = false, features = ["derive"], opt #i_tree = { path = "../../iTree" } #i_key_sort = { path = "../../iKeySort/iKeySort" } -i_overlay = "~5.0.0" +i_overlay = "^6.0.0" i_tree = "~0.18.0" i_key_sort = "~0.10.1" diff --git a/iTriangle/README.md b/iTriangle/README.md index a3f5db0..f57af25 100644 --- a/iTriangle/README.md +++ b/iTriangle/README.md @@ -21,6 +21,7 @@ iTriangle is a high-performance 2D polygon triangulation library for Rust. It so - [Quick Start](#quick-start) - [Documentation](#documentation) - [Examples](#examples) +- [Integer API](#integer-api) - [Performance](#performance) - [Gallery](#gallery) - [Contributing](#contributing) @@ -73,7 +74,7 @@ Add to your `Cargo.toml`: ```toml [dependencies] -i_triangle = "0.36" +i_triangle = "0.43" ``` Minimal example: @@ -183,7 +184,13 @@ println!("centroids: {:?}", centroids); If you need to triangulate many shapes, it is more efficient to use `Triangulator`. ```rust -let contours = random_contours(100); +use i_triangle::float::triangulation::Triangulation; +use i_triangle::float::triangulator::Triangulator; + +let contours = vec![ + vec![[0.0, 0.0], [4.0, 0.0], [4.0, 4.0], [0.0, 4.0]], + vec![[5.0, 0.0], [9.0, 0.0], [9.0, 4.0], [5.0, 4.0]], +]; let mut triangulator = Triangulator::::default(); @@ -204,6 +211,77 @@ for contour in contours.iter() { } ``` +## Integer API + +The integer API is useful when your coordinates are already quantized or when you want direct control over the robust integer core. It avoids float-to-int adapter setup and returns integer points unchanged. + +Use `IntPoint` with `IntContour`, `IntShape`, or `IntShapes`-compatible containers: + +```rust +use i_triangle::int::triangulatable::IntTriangulatable; +use i_triangle::i_overlay::i_float::int::point::IntPoint; + +let contour = vec![ + IntPoint::new(0, 0), + IntPoint::new(10, 0), + IntPoint::new(10, 10), + IntPoint::new(0, 10), +]; + +let triangulation = contour.triangulate().into_triangulation::(); + +assert_eq!(triangulation.points.len(), 4); +assert_eq!(triangulation.indices.len(), 6); +``` + +For repeated triangulation, use `IntTriangulator` and reuse its internal buffers: + +```rust +use i_triangle::int::triangulation::IntTriangulation; +use i_triangle::int::triangulator::IntTriangulator; +use i_triangle::i_overlay::i_float::int::point::IntPoint; + +let contours = vec![ + vec![ + IntPoint::new(0, 0), + IntPoint::new(10, 0), + IntPoint::new(10, 10), + IntPoint::new(0, 10), + ], + vec![ + IntPoint::new(20, 0), + IntPoint::new(30, 0), + IntPoint::new(30, 10), + IntPoint::new(20, 10), + ], +]; + +let mut triangulator = IntTriangulator::::default(); +let mut output = IntTriangulation::::default(); + +for contour in &contours { + triangulator.triangulate_contour_into(contour.clone(), &mut output); + assert!(!output.indices.is_empty()); +} +``` + +If your integer contours are already valid and correctly oriented, the unchecked API skips validation: + +```rust +use i_triangle::int::unchecked::IntUncheckedTriangulatable; +use i_triangle::i_overlay::i_float::int::point::IntPoint; + +let contour = vec![ + IntPoint::new(0, 0), + IntPoint::new(10, 0), + IntPoint::new(10, 10), + IntPoint::new(0, 10), +]; + +let triangulation = contour.uncheck_triangulate().into_triangulation::(); +assert_eq!(triangulation.indices.len(), 6); +``` + ## Performance Benchmarks and interactive demos are available here: diff --git a/iTriangle/src/float/centroid_net.rs b/iTriangle/src/float/centroid_net.rs index 20c7198..938348b 100644 --- a/iTriangle/src/float/centroid_net.rs +++ b/iTriangle/src/float/centroid_net.rs @@ -1,13 +1,12 @@ use crate::float::delaunay::Delaunay; use alloc::vec::Vec; use i_overlay::i_float::float::compatible::FloatPointCompatible; -use i_overlay::i_float::float::number::FloatNumber; use i_overlay::i_shape::base::data::Contour; use i_overlay::i_shape::float::adapter::ShapeToFloat; -impl, T: FloatNumber> Delaunay { +impl Delaunay

{ #[inline] - pub fn to_centroid_net(&self, min_area: T) -> Vec> { + 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) } diff --git a/iTriangle/src/float/circumcenter.rs b/iTriangle/src/float/circumcenter.rs index 08e828e..af98cce 100644 --- a/iTriangle/src/float/circumcenter.rs +++ b/iTriangle/src/float/circumcenter.rs @@ -1,28 +1,27 @@ use crate::float::delaunay::Delaunay; use i_overlay::i_float::float::compatible::FloatPointCompatible; -use i_overlay::i_float::float::number::FloatNumber; -impl, T: FloatNumber> Delaunay { +impl Delaunay

{ #[inline] - pub fn refine_with_circumcenters(mut self, min_area: T) -> Self { + pub fn refine_with_circumcenters(mut self, min_area: P::Scalar) -> Self { self.refine_with_circumcenters_mut(min_area); self } #[inline] - pub fn refine_with_circumcenters_by_obtuse_angle(mut self, min_area: T) -> Self { + pub fn refine_with_circumcenters_by_obtuse_angle(mut self, min_area: P::Scalar) -> Self { self.refine_with_circumcenters_by_obtuse_angle_mut(min_area); self } #[inline] - pub fn refine_with_circumcenters_mut(&mut self, min_area: T) { + 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); } #[inline] - pub fn refine_with_circumcenters_by_obtuse_angle_mut(&mut self, min_area: T) { + 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); self.delaunay .refine_with_circumcenters_by_obtuse_angle_mut(int_area); diff --git a/iTriangle/src/float/convex.rs b/iTriangle/src/float/convex.rs index f2deeb6..e1cb7f2 100644 --- a/iTriangle/src/float/convex.rs +++ b/iTriangle/src/float/convex.rs @@ -1,11 +1,10 @@ use crate::float::delaunay::Delaunay; use alloc::vec::Vec; use i_overlay::i_float::float::compatible::FloatPointCompatible; -use i_overlay::i_float::float::number::FloatNumber; use i_overlay::i_shape::base::data::Contour; use i_overlay::i_shape::float::adapter::ShapeToFloat; -impl, T: FloatNumber> 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 ff2fa52..2e3b322 100644 --- a/iTriangle/src/float/custom.rs +++ b/iTriangle/src/float/custom.rs @@ -4,7 +4,6 @@ use crate::int::triangulation::RawIntTriangulation; use crate::int::validation::Validation; 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::float::rect::FloatRect; use i_overlay::i_shape::base::data::{Contour, Shape}; use i_overlay::i_shape::float::adapter::{PathToInt, ShapeToInt, ShapesToInt}; @@ -13,28 +12,28 @@ use i_overlay::i_shape::float::rect::RectInit; /// 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, T: FloatNumber> { +pub trait CustomTriangulatable { /// Performs triangulation using the specified [`Validation`] settings. - fn custom_triangulate(&self, validation: Validation) -> RawTriangulation; + fn custom_triangulate(&self, validation: Validation) -> RawTriangulation

; /// Performs triangulation with Steiner points and a custom [`Validation`] config. fn custom_triangulate_with_steiner_points( &self, points: &[P], validation: Validation, - ) -> RawTriangulation; + ) -> RawTriangulation

; } -impl, T: FloatNumber> CustomTriangulatable for Contour

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

for Contour

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

{ 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()), } } } @@ -43,9 +42,9 @@ impl, T: FloatNumber> CustomTriangulatable for &self, points: &[P], validation: Validation, - ) -> RawTriangulation { + ) -> RawTriangulation

{ 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,22 +53,22 @@ impl, T: FloatNumber> CustomTriangulatable for } else { RawTriangulation { raw: RawIntTriangulation::default(), - adapter: FloatPointAdapter::::new(FloatRect::zero()), + adapter: FloatPointAdapter::

::new(FloatRect::zero()), } } } } -impl, T: FloatNumber> CustomTriangulatable for [Contour

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

for [Contour

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

{ 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()), } } } @@ -78,9 +77,9 @@ impl, T: FloatNumber> CustomTriangulatable for &self, points: &[P], validation: Validation, - ) -> RawTriangulation { + ) -> RawTriangulation

{ 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) @@ -89,22 +88,22 @@ impl, T: FloatNumber> CustomTriangulatable for } else { RawTriangulation { raw: RawIntTriangulation::default(), - adapter: FloatPointAdapter::::new(FloatRect::zero()), + adapter: FloatPointAdapter::

::new(FloatRect::zero()), } } } } -impl, T: FloatNumber> CustomTriangulatable for [Shape

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

for [Shape

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

{ 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()), } } } @@ -113,9 +112,9 @@ impl, T: FloatNumber> CustomTriangulatable for &self, points: &[P], validation: Validation, - ) -> RawTriangulation { + ) -> RawTriangulation

{ 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) @@ -124,7 +123,7 @@ impl, T: FloatNumber> CustomTriangulatable for } 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 cb43d1e..b79d345 100644 --- a/iTriangle/src/float/delaunay.rs +++ b/iTriangle/src/float/delaunay.rs @@ -4,21 +4,20 @@ 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::float::number::FloatNumber; 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, T: FloatNumber> { +pub struct Delaunay { pub(super) delaunay: IntDelaunay, - pub(super) adapter: FloatPointAdapter, + pub(super) adapter: FloatPointAdapter

, } -impl, T: FloatNumber> RawTriangulation { +impl RawTriangulation

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

{ Delaunay { delaunay: self.raw.into_delaunay(), adapter: self.adapter, @@ -26,7 +25,7 @@ impl, T: FloatNumber> RawTriangulation { } } -impl, T: FloatNumber> Delaunay { +impl Delaunay

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

{ diff --git a/iTriangle/src/float/triangulatable.rs b/iTriangle/src/float/triangulatable.rs index 2acadf7..a57ff7a 100644 --- a/iTriangle/src/float/triangulatable.rs +++ b/iTriangle/src/float/triangulatable.rs @@ -3,7 +3,6 @@ use crate::int::triangulatable::IntTriangulatable; use crate::int::triangulation::RawIntTriangulation; 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::float::rect::FloatRect; use i_overlay::i_shape::base::data::{Contour, Shape}; use i_overlay::i_shape::float::adapter::{PathToInt, ShapeToInt, ShapesToInt}; @@ -18,35 +17,35 @@ use i_overlay::i_shape::float::rect::RectInit; /// - `Contour

` /// - `[Contour

]` /// - `[Shape

]` -pub trait Triangulatable, T: FloatNumber> { +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

; /// 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

; } -impl, T: FloatNumber> Triangulatable for [P] { - fn triangulate(&self) -> RawTriangulation { +impl Triangulatable

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

{ 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(&self, points: &[P]) -> RawTriangulation

{ 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) @@ -55,29 +54,29 @@ impl, T: FloatNumber> Triangulatable for [P] { } else { RawTriangulation { raw: RawIntTriangulation::default(), - adapter: FloatPointAdapter::::new(FloatRect::zero()), + adapter: FloatPointAdapter::

::new(FloatRect::zero()), } } } } -impl, T: FloatNumber> Triangulatable for [Contour

] { - fn triangulate(&self) -> RawTriangulation { +impl Triangulatable

for [Contour

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

{ 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(&self, points: &[P]) -> RawTriangulation

{ 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) @@ -86,29 +85,29 @@ impl, T: FloatNumber> Triangulatable for [Conto } else { RawTriangulation { raw: RawIntTriangulation::default(), - adapter: FloatPointAdapter::::new(FloatRect::zero()), + adapter: FloatPointAdapter::

::new(FloatRect::zero()), } } } } -impl, T: FloatNumber> Triangulatable for [Shape

] { - fn triangulate(&self) -> RawTriangulation { +impl Triangulatable

for [Shape

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

{ 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(&self, points: &[P]) -> RawTriangulation

{ 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) @@ -117,7 +116,7 @@ impl, T: FloatNumber> 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 e3259cc..dad88e3 100644 --- a/iTriangle/src/float/triangulation.rs +++ b/iTriangle/src/float/triangulation.rs @@ -13,10 +13,9 @@ use i_overlay::i_shape::util::reserve::Reserve; /// /// # Parameters /// - `P`: Float point type (e.g., `Vec2`, `[f32; 2]`, etc.) -/// - `T`: Float scalar type (e.g., `f32`, `f64`) -pub struct RawTriangulation, T: FloatNumber> { +pub struct RawTriangulation { pub raw: RawIntTriangulation, - pub adapter: FloatPointAdapter, + pub adapter: FloatPointAdapter

, } /// A flat triangulation result consisting of float points and triangle indices. @@ -29,7 +28,7 @@ pub struct Triangulation { pub indices: Vec, } -impl, T: FloatNumber> 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. @@ -64,13 +63,12 @@ impl Triangulation { } #[inline] - pub fn set_with_int( + pub fn set_with_int( &mut self, triangulation: &IntTriangulation, - adapter: &FloatPointAdapter, + adapter: &FloatPointAdapter

, ) where - P: FloatPointCompatible, - T: FloatNumber, + P: FloatPointCompatible, { self.points.clear(); self.points @@ -85,9 +83,9 @@ impl Triangulation { impl IntTriangulation { #[inline] - pub fn into_float, T: FloatNumber>( + pub fn into_float( self, - adapter: &FloatPointAdapter, + adapter: &FloatPointAdapter

, ) -> Triangulation { let points = self .points @@ -101,9 +99,9 @@ impl IntTriangulation { } #[inline] - pub fn to_float, T: FloatNumber>( + pub fn to_float( &self, - adapter: &FloatPointAdapter, + adapter: &FloatPointAdapter

, ) -> Triangulation { let points = self .points @@ -118,11 +116,11 @@ impl IntTriangulation { } impl Triangulation { - pub fn validate(&self, shape_area: T, epsilon: T) + pub fn validate(&self, shape_area: P::Scalar, epsilon: P::Scalar) where - P: FloatPointCompatible, + P: FloatPointCompatible, { - let mut s = T::from_float(0.0); + let mut s = P::Scalar::from_float(0.0); let mut i = 0; let neg_eps = -epsilon; while i < self.indices.len() { @@ -146,17 +144,17 @@ impl Triangulation { s = s + abc; } - s = T::from_float(0.5) * s; + s = P::Scalar::from_float(0.5) * s; - let eps = epsilon * T::from_usize(self.indices.len() / 3); + let eps = epsilon * P::Scalar::from_usize(self.indices.len() / 3); let delta = (shape_area - s).abs(); assert!(delta <= eps); } - fn triangle_area_x2(a: &P, b: &P, c: &P) -> T + fn triangle_area_x2(a: &P, b: &P, c: &P) -> P::Scalar where - P: FloatPointCompatible, + P: FloatPointCompatible, { let ax = a.x(); let ay = a.y(); diff --git a/iTriangle/src/float/triangulator.rs b/iTriangle/src/float/triangulator.rs index 0be632d..26112e5 100644 --- a/iTriangle/src/float/triangulator.rs +++ b/iTriangle/src/float/triangulator.rs @@ -4,7 +4,6 @@ use crate::int::triangulator::IntTriangulator; use crate::int::validation::Validation; use i_overlay::core::solver::Solver; use i_overlay::i_float::float::compatible::FloatPointCompatible; -use i_overlay::i_float::float::number::FloatNumber; use i_overlay::i_shape::flat::buffer::FlatContoursBuffer; use i_overlay::i_shape::source::resource::ShapeResource; @@ -80,11 +79,10 @@ 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, - T: FloatNumber, + R: ShapeResource

+ ?Sized, + P: FloatPointCompatible, { let mut flat_buffer = self.flat_buffer.take().unwrap_or_default(); let mut int_buffer = self.int_buffer.take().unwrap_or_default(); @@ -115,14 +113,10 @@ impl Triangulator { /// /// Uses internal buffers to reduce allocations and preserve performance. #[inline] - pub fn triangulate_into( - &mut self, - resource: &R, - triangulation: &mut Triangulation, - ) where - R: ShapeResource + ?Sized, - P: FloatPointCompatible, - T: FloatNumber, + pub fn triangulate_into(&mut self, resource: &R, triangulation: &mut Triangulation) + where + R: ShapeResource

+ ?Sized, + P: FloatPointCompatible, { let mut flat_buffer = self.flat_buffer.take().unwrap_or_default(); let mut int_buffer = self.int_buffer.take().unwrap_or_default(); @@ -151,11 +145,10 @@ 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, - T: FloatNumber, + R: ShapeResource

+ ?Sized, + P: FloatPointCompatible, { let mut flat_buffer = self.flat_buffer.take().unwrap_or_default(); let mut int_buffer = self.int_buffer.take().unwrap_or_default(); @@ -188,14 +181,13 @@ impl Triangulator { /// /// Uses internal buffers to reduce allocations and preserve performance. #[inline] - pub fn uncheck_triangulate_into( + pub fn uncheck_triangulate_into( &mut self, resource: &R, triangulation: &mut Triangulation, ) where - R: ShapeResource + ?Sized, - P: FloatPointCompatible, - T: FloatNumber, + R: ShapeResource

+ ?Sized, + P: FloatPointCompatible, { let mut flat_buffer = self.flat_buffer.take().unwrap_or_default(); let mut int_buffer = self.int_buffer.take().unwrap_or_default(); diff --git a/iTriangle/src/float/unchecked.rs b/iTriangle/src/float/unchecked.rs index 3dcff9b..bf2074e 100644 --- a/iTriangle/src/float/unchecked.rs +++ b/iTriangle/src/float/unchecked.rs @@ -3,7 +3,6 @@ use crate::int::triangulation::RawIntTriangulation; use crate::int::unchecked::IntUncheckedTriangulatable; 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::float::rect::FloatRect; use i_overlay::i_shape::base::data::{Contour, Shape}; use i_overlay::i_shape::float::adapter::{PathToInt, ShapeToInt, ShapesToInt}; @@ -17,30 +16,30 @@ use i_overlay::i_shape::float::rect::RectInit; /// - Outer contours must be counter-clockwise /// - Holes must be clockwise /// - Steiner points must lie strictly within the shape -pub trait UncheckedTriangulatable, T: FloatNumber> { +pub trait UncheckedTriangulatable { /// Triangulates float geometry without validation or simplification. - fn unchecked_triangulate(&self) -> RawTriangulation; + fn unchecked_triangulate(&self) -> RawTriangulation

; /// 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

; } -impl, T: FloatNumber> UncheckedTriangulatable for [P] { - fn unchecked_triangulate(&self) -> RawTriangulation { +impl UncheckedTriangulatable

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

{ 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(&self, points: &[P]) -> RawTriangulation

{ 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) @@ -49,29 +48,29 @@ impl, T: FloatNumber> UncheckedTriangulatable f } else { RawTriangulation { raw: RawIntTriangulation::default(), - adapter: FloatPointAdapter::::new(FloatRect::zero()), + adapter: FloatPointAdapter::

::new(FloatRect::zero()), } } } } -impl, T: FloatNumber> UncheckedTriangulatable for [Contour

] { - fn unchecked_triangulate(&self) -> RawTriangulation { +impl UncheckedTriangulatable

for [Contour

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

{ 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(&self, points: &[P]) -> RawTriangulation

{ 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) @@ -80,29 +79,29 @@ impl, T: FloatNumber> UncheckedTriangulatable f } else { RawTriangulation { raw: RawIntTriangulation::default(), - adapter: FloatPointAdapter::::new(FloatRect::zero()), + adapter: FloatPointAdapter::

::new(FloatRect::zero()), } } } } -impl, T: FloatNumber> UncheckedTriangulatable for [Shape

] { - fn unchecked_triangulate(&self) -> RawTriangulation { +impl UncheckedTriangulatable

for [Shape

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

{ 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(&self, points: &[P]) -> RawTriangulation

{ 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) @@ -111,7 +110,7 @@ impl, T: FloatNumber> UncheckedTriangulatable f } else { RawTriangulation { raw: RawIntTriangulation::default(), - adapter: FloatPointAdapter::::new(FloatRect::zero()), + adapter: FloatPointAdapter::

::new(FloatRect::zero()), } } } From f07e0acd9b49bbd4d594151a4964f3dbd2231fe7 Mon Sep 17 00:00:00 2001 From: Nail Sharipov Date: Sat, 2 May 2026 15:15:08 +0300 Subject: [PATCH 2/2] up min i_key_sort --- iTriangle/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iTriangle/Cargo.toml b/iTriangle/Cargo.toml index 3facf03..ea8a47a 100644 --- a/iTriangle/Cargo.toml +++ b/iTriangle/Cargo.toml @@ -26,7 +26,7 @@ serde = { version = "^1.0", default-features = false, features = ["derive"], opt i_overlay = "^6.0.0" i_tree = "~0.18.0" -i_key_sort = "~0.10.1" +i_key_sort = "~0.10.3"