1mod api;
11mod connect;
12mod dirty_regions;
13mod geometry;
14mod output;
15mod priority_queue;
16mod region;
17mod sweep;
18#[cfg(test)]
19mod tests;
20
21pub use api::TessellatorApi;
22
23use geometry::{check_orientation, compute_normal, dot, is_valid_coord, long_axis};
24
25use crate::dict::Dict;
26use crate::geom::{vert_eq, Real};
27use crate::mesh::{Mesh, VertIdx, E_HEAD, INVALID, V_HEAD};
28use crate::sweep::ActiveRegion;
29
30#[derive(Copy, Clone, Debug, PartialEq)]
33pub enum WindingRule {
34 Odd,
35 NonZero,
36 Positive,
37 Negative,
38 AbsGeqTwo,
39}
40
41#[derive(Copy, Clone, Debug, PartialEq)]
42pub enum ElementType {
43 Polygons,
44 ConnectedPolygons,
45 BoundaryContours,
46}
47
48#[derive(Copy, Clone, Debug, PartialEq)]
49pub enum TessOption {
50 ConstrainedDelaunayTriangulation,
51 ReverseContours,
52}
53
54#[derive(Copy, Clone, Debug, PartialEq)]
55pub enum TessStatus {
56 Ok,
57 OutOfMemory,
58 InvalidInput,
59}
60
61pub const TESS_UNDEF: u32 = u32::MAX;
62const MAX_VALID_COORD: Real = (1u64 << 50) as Real;
66const MIN_VALID_COORD: Real = -MAX_VALID_COORD;
67
68type RegionIdx = u32;
69
70pub struct Tessellator {
73 mesh: Option<Mesh>,
74 pub status: TessStatus,
75 normal: [Real; 3],
76 s_unit: [Real; 3],
77 t_unit: [Real; 3],
78 bmin: [Real; 2],
79 bmax: [Real; 2],
80 process_cdt: bool,
81 reverse_contours: bool,
82 winding_rule: WindingRule,
83
84 dict: Dict,
86 intersection_verts: Vec<VertIdx>,
89 next_isect_handle: i32,
90 event: VertIdx,
91 event_s: Real,
92 event_t: Real,
93
94 regions: Vec<Option<ActiveRegion>>,
96 region_free: Vec<RegionIdx>,
97
98 pub out_vertices: Vec<Real>,
100 pub out_vertex_indices: Vec<u32>,
101 pub out_elements: Vec<u32>,
102 pub out_edge_flags: Vec<u8>,
118 pub out_vertex_count: usize,
119 pub out_element_count: usize,
120 vertex_index_counter: u32,
121
122 sorted_events: Vec<VertIdx>,
124 sorted_event_pos: usize,
125 sweep_event_num: u32,
126 trace_enabled: bool,
127}
128
129impl Tessellator {
130 pub fn new() -> Self {
131 Tessellator {
132 mesh: None,
133 status: TessStatus::Ok,
134 normal: [0.0; 3],
135 s_unit: [0.0; 3],
136 t_unit: [0.0; 3],
137 bmin: [0.0; 2],
138 bmax: [0.0; 2],
139 process_cdt: false,
140 reverse_contours: false,
141 winding_rule: WindingRule::Odd,
142 dict: Dict::new(),
143 intersection_verts: Vec::new(),
144 next_isect_handle: 0,
145 event: INVALID,
146 event_s: 0.0,
147 event_t: 0.0,
148 regions: Vec::new(),
149 region_free: Vec::new(),
150 out_vertices: Vec::new(),
151 out_vertex_indices: Vec::new(),
152 out_elements: Vec::new(),
153 out_edge_flags: Vec::new(),
154 out_vertex_count: 0,
155 out_element_count: 0,
156 vertex_index_counter: 0,
157 sorted_events: Vec::new(),
158 sorted_event_pos: 0,
159 sweep_event_num: 0,
160 trace_enabled: std::env::var("TESS_TRACE").is_ok(),
161 }
162 }
163
164 pub fn set_option(&mut self, option: TessOption, value: bool) {
165 match option {
166 TessOption::ConstrainedDelaunayTriangulation => self.process_cdt = value,
167 TessOption::ReverseContours => self.reverse_contours = value,
168 }
169 }
170
171 pub fn add_contour(&mut self, size: usize, vertices: &[Real]) {
177 if self.status != TessStatus::Ok {
178 return;
179 }
180 let size = size.min(3).max(2);
181 let count = vertices.len() / size;
182 if self.mesh.is_none() {
183 self.mesh = Some(Mesh::new());
184 }
185
186 let mut e = INVALID;
187 for i in 0..count {
188 let cx = vertices[i * size];
189 let cy = vertices[i * size + 1];
190 let cz = if size > 2 {
191 vertices[i * size + 2]
192 } else {
193 0.0
194 };
195
196 if !is_valid_coord(cx) || !is_valid_coord(cy) || (size > 2 && !is_valid_coord(cz)) {
197 self.status = TessStatus::InvalidInput;
198 return;
199 }
200
201 let mesh = self.mesh.as_mut().unwrap();
202 if e == INVALID {
203 let new_e = match mesh.make_edge() {
204 Some(v) => v,
205 None => {
206 self.status = TessStatus::OutOfMemory;
207 return;
208 }
209 };
210 e = new_e;
211 if !mesh.splice(e, e ^ 1) {
212 self.status = TessStatus::OutOfMemory;
213 return;
214 }
215 } else {
216 if mesh.split_edge(e).is_none() {
217 self.status = TessStatus::OutOfMemory;
218 return;
219 }
220 e = mesh.edges[e as usize].lnext;
221 }
222
223 let org = mesh.edges[e as usize].org;
224 mesh.verts[org as usize].coords[0] = cx;
225 mesh.verts[org as usize].coords[1] = cy;
226 mesh.verts[org as usize].coords[2] = cz;
227 mesh.verts[org as usize].idx = self.vertex_index_counter;
228 self.vertex_index_counter += 1;
229
230 let w = if self.reverse_contours { -1 } else { 1 };
231 mesh.edges[e as usize].winding = w;
232 mesh.edges[(e ^ 1) as usize].winding = -w;
233 }
234 }
235
236 pub fn tessellate(
237 &mut self,
238 winding_rule: WindingRule,
239 element_type: ElementType,
240 poly_size: usize,
241 vertex_size: usize,
242 normal: Option<[Real; 3]>,
243 ) -> bool {
244 if self.status != TessStatus::Ok {
245 return false;
246 }
247 self.winding_rule = winding_rule;
248 self.out_vertices.clear();
249 self.out_vertex_indices.clear();
250 self.out_elements.clear();
251 self.out_edge_flags.clear();
252 self.out_vertex_count = 0;
253 self.out_element_count = 0;
254 self.normal = normal.unwrap_or([0.0, 0.0, 0.0]);
255
256 if self.mesh.is_none() {
257 self.mesh = Some(Mesh::new());
258 }
259
260 if !self.project_polygon() {
261 self.status = TessStatus::OutOfMemory;
262 return false;
263 }
264
265 if !self.compute_interior() {
266 if self.status == TessStatus::Ok {
267 self.status = TessStatus::OutOfMemory;
268 }
269 return false;
270 }
271
272 let vertex_size = vertex_size.min(3).max(2);
273 if element_type == ElementType::BoundaryContours {
274 self.output_contours(vertex_size);
275 } else {
276 self.output_polymesh(element_type, poly_size, vertex_size);
277 }
278
279 self.mesh = None;
280 self.status == TessStatus::Ok
281 }
282
283 pub fn vertex_count(&self) -> usize {
286 self.out_vertex_count
287 }
288 pub fn element_count(&self) -> usize {
289 self.out_element_count
290 }
291 pub fn vertices(&self) -> &[Real] {
292 &self.out_vertices
293 }
294 pub fn vertex_indices(&self) -> &[u32] {
295 &self.out_vertex_indices
296 }
297 pub fn elements(&self) -> &[u32] {
298 &self.out_elements
299 }
300 pub fn edge_flags(&self) -> &[u8] {
304 &self.out_edge_flags
305 }
306 pub fn get_status(&self) -> TessStatus {
307 self.status
308 }
309
310 fn project_polygon(&mut self) -> bool {
313 let mut norm = self.normal;
314 let mut computed_normal = false;
315 if norm[0] == 0.0 && norm[1] == 0.0 && norm[2] == 0.0 {
316 if let Some(ref m) = self.mesh {
317 compute_normal(m, &mut norm);
318 }
319 computed_normal = true;
320 }
321
322 let i = long_axis(&norm);
323 self.s_unit = [0.0; 3];
324 self.t_unit = [0.0; 3];
325 self.s_unit[(i + 1) % 3] = 1.0;
326 self.t_unit[(i + 2) % 3] = if norm[i] > 0.0 { 1.0 } else { -1.0 };
327 let su = self.s_unit;
328 let tu = self.t_unit;
329
330 if let Some(ref mut mesh) = self.mesh {
331 let mut v = mesh.verts[V_HEAD as usize].next;
332 while v != V_HEAD {
333 let c = mesh.verts[v as usize].coords;
334 mesh.verts[v as usize].s = dot(&c, &su);
335 mesh.verts[v as usize].t = dot(&c, &tu);
336 v = mesh.verts[v as usize].next;
337 }
338 if computed_normal {
339 check_orientation(mesh);
340 }
341
342 let mut first = true;
343 let mut v = mesh.verts[V_HEAD as usize].next;
344 while v != V_HEAD {
345 let vs = mesh.verts[v as usize].s;
346 let vt = mesh.verts[v as usize].t;
347 if first {
348 self.bmin = [vs, vt];
349 self.bmax = [vs, vt];
350 first = false;
351 } else {
352 if vs < self.bmin[0] {
353 self.bmin[0] = vs;
354 }
355 if vs > self.bmax[0] {
356 self.bmax[0] = vs;
357 }
358 if vt < self.bmin[1] {
359 self.bmin[1] = vt;
360 }
361 if vt > self.bmax[1] {
362 self.bmax[1] = vt;
363 }
364 }
365 v = mesh.verts[v as usize].next;
366 }
367 }
368 true
369 }
370
371 fn compute_interior(&mut self) -> bool {
374 self.sweep_event_num = 0;
375
376 if !self.remove_degenerate_edges() {
377 return false;
378 }
379 if !self.init_priority_queue() {
380 return false;
381 }
382 if !self.init_edge_dict() {
383 return false;
384 }
385
386 loop {
387 if self.pq_is_empty() {
388 break;
389 }
390
391 let v = self.pq_extract_min();
392 if v == INVALID {
393 break;
394 }
395
396 loop {
398 if self.pq_is_empty() {
399 break;
400 }
401 let next_v = self.pq_minimum();
402 if next_v == INVALID {
403 break;
404 }
405 let (v_s, v_t) = {
406 let mesh = self.mesh.as_ref().unwrap();
407 (mesh.verts[v as usize].s, mesh.verts[v as usize].t)
408 };
409 let (nv_s, nv_t) = {
410 let mesh = self.mesh.as_ref().unwrap();
411 (mesh.verts[next_v as usize].s, mesh.verts[next_v as usize].t)
412 };
413 if !vert_eq(v_s, v_t, nv_s, nv_t) {
414 break;
415 }
416 let next_v = self.pq_extract_min();
417 let an1 = self.mesh.as_ref().unwrap().verts[v as usize].an_edge;
419 let an2 = self.mesh.as_ref().unwrap().verts[next_v as usize].an_edge;
420 if an1 != INVALID && an2 != INVALID {
421 if !self.mesh.as_mut().unwrap().splice(an1, an2) {
422 return false;
423 }
424 }
425 }
426
427 self.event = v;
428 let (v_s, v_t) = {
429 let m = self.mesh.as_ref().unwrap();
430 (m.verts[v as usize].s, m.verts[v as usize].t)
431 };
432 self.event_s = v_s;
433 self.event_t = v_t;
434
435 if !self.sweep_event(v) {
436 return false;
437 }
438 }
439
440 self.done_edge_dict();
441
442 let trace = self.trace_enabled;
443 if let Some(ref mut mesh) = self.mesh {
444 if trace {
445 let mut inside = 0u32;
446 let mut outside = 0u32;
447 let mut f = mesh.faces[crate::mesh::F_HEAD as usize].next;
448 while f != crate::mesh::F_HEAD {
449 let an = mesh.faces[f as usize].an_edge;
450 let mut edge_count = 0u32;
451 if an != INVALID {
452 let mut e = an;
453 loop {
454 edge_count += 1;
455 e = mesh.edges[e as usize].lnext;
456 if e == an { break; }
457 if edge_count > 10000 { break; }
458 }
459 }
460 if mesh.faces[f as usize].inside {
461 inside += 1;
462 eprintln!("R FACE inside edges={}", edge_count);
463 } else {
464 outside += 1;
465 }
466 f = mesh.faces[f as usize].next;
467 }
468 eprintln!("R FACES inside={} outside={}", inside, outside);
469 }
470 if !mesh.tessellate_interior() {
471 return false;
472 }
473 if self.process_cdt {
474 mesh.refine_delaunay();
475 }
476 }
477 true
478 }
479
480 fn remove_degenerate_edges(&mut self) -> bool {
481 let mesh = match self.mesh.as_mut() {
483 Some(m) => m,
484 None => return true,
485 };
486 let mut e = mesh.edges[E_HEAD as usize].next;
487 while e != E_HEAD {
488 let mut e_next = mesh.edges[e as usize].next;
489 let mut e_lnext = mesh.edges[e as usize].lnext;
490
491 let org = mesh.edges[e as usize].org;
492 let dst = mesh.dst(e);
493 let valid = org != INVALID
494 && dst != INVALID
495 && (org as usize) < mesh.verts.len()
496 && (dst as usize) < mesh.verts.len();
497
498 if valid {
499 let (os, ot) = (mesh.verts[org as usize].s, mesh.verts[org as usize].t);
500 let (ds, dt) = (mesh.verts[dst as usize].s, mesh.verts[dst as usize].t);
501
502 if vert_eq(os, ot, ds, dt) && mesh.edges[e_lnext as usize].lnext != e {
503 mesh.splice(e_lnext, e);
505 if !mesh.delete_edge(e) {
506 return false;
507 }
508 e = e_lnext;
509 e_lnext = mesh.edges[e as usize].lnext;
510 }
511 }
512
513 let e_lnext_lnext = mesh.edges[e_lnext as usize].lnext;
515 if e_lnext_lnext == e {
516 if e_lnext != e {
517 if e_lnext == e_next || e_lnext == (e_next ^ 1) {
519 e_next = mesh.edges[e_next as usize].next;
520 }
521 let w1 = mesh.edges[e_lnext as usize].winding;
522 let w2 = mesh.edges[(e_lnext ^ 1) as usize].winding;
523 mesh.edges[e as usize].winding += w1;
524 mesh.edges[(e ^ 1) as usize].winding += w2;
525 if !mesh.delete_edge(e_lnext) {
526 return false;
527 }
528 }
529 if e == e_next || e == (e_next ^ 1) {
531 e_next = mesh.edges[e_next as usize].next;
532 }
533 if !mesh.delete_edge(e) {
534 return false;
535 }
536 }
537
538 e = e_next;
539 }
540 true
541 }
542}