1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
use crate::float::triangulation::Triangulation;
use crate::int::triangulation::{IndexType, IntTriangulation};
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;
/// A reusable triangulator that converts float-based shapes into triangle meshes.
pub struct Triangulator<I> {
flat_buffer: Option<FlatContoursBuffer>,
int_buffer: Option<IntTriangulation<I>>,
int_triangulator: IntTriangulator<I>,
}
impl<I: IndexType> Triangulator<I> {
/// Enables or disables Delaunay refinement for triangulation.
///
/// When enabled, the triangulator will attempt to generate a mesh that satisfies the
/// Delaunay condition (no point lies inside the circumcircle of any triangle).
///
/// This can improve triangle quality at the cost of slightly increased computation.
pub fn delaunay(&mut self, enable: bool) {
self.int_triangulator.delaunay = enable;
}
/// Returns whether Delaunay refinement is currently enabled.
pub fn is_delaunay(&self) -> bool {
self.int_triangulator.delaunay
}
/// Enables or disables Earcut64 optimization for small contours.
///
/// When enabled, the triangulator will automatically use the highly optimized Earcut64
/// algorithm for any contour with fewer or equal than 64 points. This reduces overhead
/// for small polygons while maintaining correctness.
pub fn earcut(&mut self, enable: bool) {
self.int_triangulator.earcut = enable;
}
/// Returns whether Earcut64 optimization is currently enabled.
pub fn is_earcut(&self) -> bool {
self.int_triangulator.earcut
}
/// Performs triangulation on the given shape resource and returns a new `Triangulation`.
///
/// - `resource`: A shape container implementing `ShapeResource` (e.g., contour, contours, or shapes).
/// - `delaunay`: Enables Delaunay-compatible triangulation when set to true.
/// - Returns: A new `Triangulation` containing triangle indices and corresponding points.
///
/// Uses internal buffers to minimize allocations and speed up repeated calls.
#[inline]
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)),
int_triangulator: IntTriangulator::new(max_points_count, validation, solver),
}
}
}
impl<I: IndexType> Default for Triangulator<I> {
#[inline]
fn default() -> Self {
Self::new(64, Default::default(), Default::default())
}
}
impl<I: IndexType> Triangulator<I> {
/// Performs triangulation on the provided shape resource and returns a new `Triangulation`.
///
/// - `resource`: A `ShapeResource` that define contours.
/// `ShapeResource` can be one of the following:
/// - `Contour`: A contour representing a closed path. This path is interpreted as closed, so it doesn’t require the start and endpoint to be the same for processing.
/// - `Contours`: A collection of contours, each representing a closed path.
/// - `Shapes`: A collection of shapes, where each shape may consist of multiple contours.
///
/// Uses internal buffers to reduce allocations and preserve performance.
#[inline]
pub fn triangulate<R, P, T>(&mut self, resource: &R) -> Triangulation<P, I>
where
R: ShapeResource<P, T> + ?Sized,
P: FloatPointCompatible<T>,
T: FloatNumber,
{
let mut flat_buffer = self.flat_buffer.take().unwrap_or_default();
let mut int_buffer = self.int_buffer.take().unwrap_or_default();
let adapter = flat_buffer.set_with_resource(resource);
self.int_triangulator
.triangulate_flat_into(&mut flat_buffer, &mut int_buffer);
let triangulation = int_buffer.to_float(&adapter);
self.flat_buffer = Some(flat_buffer);
self.int_buffer = Some(int_buffer);
triangulation
}
/// Triangulates the given shape resource and stores the result into an existing `Triangulation` instance.
///
/// Avoids allocating a new `Triangulation` by reusing the provided output buffer.
///
/// - `resource`: A `ShapeResource` that define contours.
/// `ShapeResource` can be one of the following:
/// - `Contour`: A contour representing a closed path. This path is interpreted as closed, so it doesn’t require the start and endpoint to be the same for processing.
/// - `Contours`: A collection of contours, each representing a closed path.
/// - `Shapes`: A collection of shapes, where each shape may consist of multiple contours.
/// - `triangulation`: Output buffer to store the resulting triangle mesh.
///
/// Uses internal buffers to reduce allocations and preserve performance.
#[inline]
pub fn triangulate_into<R, P, T>(
&mut self,
resource: &R,
triangulation: &mut Triangulation<P, I>,
) where
R: ShapeResource<P, T> + ?Sized,
P: FloatPointCompatible<T>,
T: FloatNumber,
{
let mut flat_buffer = self.flat_buffer.take().unwrap_or_default();
let mut int_buffer = self.int_buffer.take().unwrap_or_default();
let adapter = flat_buffer.set_with_resource(resource);
self.int_triangulator
.triangulate_flat_into(&mut flat_buffer, &mut int_buffer);
triangulation.set_with_int(&int_buffer, &adapter);
self.flat_buffer = Some(flat_buffer);
self.int_buffer = Some(int_buffer);
}
/// Performs triangulation on the provided shape resource and returns a new `Triangulation`.
///
/// Skips input validation (e.g., area checks or self-intersections), offering faster performance
/// at the cost of issues.
///
/// - `resource`: A `ShapeResource` that define contours.
/// `ShapeResource` can be one of the following:
/// - `Contour`: A contour representing a closed path. This path is interpreted as closed, so it doesn’t require the start and endpoint to be the same for processing.
/// - `Contours`: A collection of contours, each representing a closed path.
/// - `Shapes`: A collection of shapes, where each shape may consist of multiple contours.
/// - `delaunay`: if true, applies Delaunay refinement.
///
/// Uses internal buffers to reduce allocations and preserve performance.
#[inline]
pub fn uncheck_triangulate<R, P, T>(&mut self, resource: &R) -> Triangulation<P, I>
where
R: ShapeResource<P, T> + ?Sized,
P: FloatPointCompatible<T>,
T: FloatNumber,
{
let mut flat_buffer = self.flat_buffer.take().unwrap_or_default();
let mut int_buffer = self.int_buffer.take().unwrap_or_default();
let adapter = flat_buffer.set_with_resource(resource);
self.int_triangulator
.uncheck_triangulate_flat_into(&flat_buffer, &mut int_buffer);
let triangulation = int_buffer.to_float(&adapter);
self.flat_buffer = Some(flat_buffer);
self.int_buffer = Some(int_buffer);
triangulation
}
/// Triangulates the given shape resource and stores the result into an existing `Triangulation` instance.
///
/// Skips input validation (e.g., area checks or self-intersections), offering faster performance
/// at the cost of issues.
///
/// Avoids allocating a new `Triangulation` by reusing the provided output buffer.
///
/// - `resource`: A `ShapeResource` that define contours.
/// `ShapeResource` can be one of the following:
/// - `Contour`: A contour representing a closed path. This path is interpreted as closed, so it doesn’t require the start and endpoint to be the same for processing.
/// - `Contours`: A collection of contours, each representing a closed path.
/// - `Shapes`: A collection of shapes, where each shape may consist of multiple contours.
/// - `triangulation`: Output buffer to store the resulting triangle mesh.
///
/// Uses internal buffers to reduce allocations and preserve performance.
#[inline]
pub fn uncheck_triangulate_into<R, P, T>(
&mut self,
resource: &R,
triangulation: &mut Triangulation<P, I>,
) where
R: ShapeResource<P, T> + ?Sized,
P: FloatPointCompatible<T>,
T: FloatNumber,
{
let mut flat_buffer = self.flat_buffer.take().unwrap_or_default();
let mut int_buffer = self.int_buffer.take().unwrap_or_default();
let adapter = flat_buffer.set_with_resource(resource);
self.int_triangulator
.uncheck_triangulate_flat_into(&flat_buffer, &mut int_buffer);
triangulation.set_with_int(&int_buffer, &adapter);
self.flat_buffer = Some(flat_buffer);
self.int_buffer = Some(int_buffer);
}
}