1use std::collections::HashMap;
33use std::fmt;
34
35use axiolid_core::Point3;
36use axiolid_guarantees::Sign;
37
38use crate::hilbert;
39use crate::sos::{beyond_face, collinear, in_sphere, orientation};
40
41const INFINITE: u32 = u32::MAX;
43
44pub const MIN_COORDINATE: f64 = 7.888_609_052_210_118e-31;
51
52pub const MAX_COORDINATE: f64 = 1.267_650_600_228_229_4e30;
54
55#[derive(Debug, Clone, Copy, PartialEq, Eq)]
57#[non_exhaustive]
58pub enum Delaunay3Error {
59 NonFinite {
61 index: usize,
63 },
64 OutOfRange {
68 index: usize,
70 },
71 NotFullDimensional {
75 dimension: Option<usize>,
77 },
78}
79
80impl fmt::Display for Delaunay3Error {
81 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
82 match self {
83 Self::NonFinite { index } => write!(f, "point {index} has a non-finite coordinate"),
84 Self::OutOfRange { index } => write!(
85 f,
86 "point {index} has a coordinate outside the exactly decidable range 2^-100..=2^100"
87 ),
88 Self::NotFullDimensional { dimension: None } => write!(f, "no points"),
89 Self::NotFullDimensional {
90 dimension: Some(dimension),
91 } => write!(
92 f,
93 "the points span {dimension} dimension(s); a tetrahedralization needs 3"
94 ),
95 }
96 }
97}
98
99impl std::error::Error for Delaunay3Error {}
100
101#[derive(Debug, Clone, Copy, PartialEq, Eq)]
103#[non_exhaustive]
104pub enum Insertion {
105 Vertex(usize),
107 Duplicate(usize),
110}
111
112#[derive(Debug, Clone, PartialEq, Eq, Default)]
114pub struct Tetrahedra {
115 pub tetrahedra: Vec<[usize; 4]>,
119 pub neighbors: Vec<[Option<usize>; 4]>,
122}
123
124#[derive(Debug, Clone, Copy)]
125struct Cell {
126 vertices: [u32; 4],
127 neighbors: [u32; 4],
128}
129
130impl Cell {
131 fn infinite_index(&self) -> Option<usize> {
132 self.vertices.iter().position(|&v| v == INFINITE)
133 }
134}
135
136#[derive(Debug, Clone)]
146pub struct Delaunay3 {
147 points: Vec<Point3>,
148 vertex: Vec<u32>,
150 cells: Vec<Cell>,
151 alive: Vec<bool>,
152 free: Vec<u32>,
153 marks: Vec<u64>,
154 epoch: u64,
155 hint: u32,
156 rng: u64,
157 frame: Vec<u32>,
159 pending: Vec<u32>,
161 seen: HashMap<[u64; 3], u32>,
162 scratch: Scratch,
163}
164
165#[derive(Debug, Clone, Default)]
167struct Scratch {
168 stack: Vec<u32>,
169 region: Vec<u32>,
170 created: Vec<(Cell, usize, u32, usize)>,
173 ids: Vec<u32>,
174 edges: Vec<(u64, u64)>,
176}
177
178impl Scratch {
179 fn clear(&mut self) {
180 self.stack.clear();
181 self.region.clear();
182 self.created.clear();
183 self.ids.clear();
184 self.edges.clear();
185 }
186}
187
188impl Default for Delaunay3 {
189 fn default() -> Self {
190 Self::new()
191 }
192}
193
194fn check_point(p: Point3, index: usize) -> Result<Point3, Delaunay3Error> {
197 for value in [p.x, p.y, p.z] {
198 if !value.is_finite() {
199 return Err(Delaunay3Error::NonFinite { index });
200 }
201 if value != 0.0 && !(MIN_COORDINATE..=MAX_COORDINATE).contains(&value.abs()) {
202 return Err(Delaunay3Error::OutOfRange { index });
203 }
204 }
205 Ok(Point3::new(p.x + 0.0, p.y + 0.0, p.z + 0.0))
206}
207
208fn key(p: Point3) -> [u64; 3] {
209 [p.x.to_bits(), p.y.to_bits(), p.z.to_bits()]
210}
211
212impl Delaunay3 {
213 #[must_use]
215 pub fn new() -> Self {
216 Self {
217 points: Vec::new(),
218 vertex: Vec::new(),
219 cells: Vec::new(),
220 alive: Vec::new(),
221 free: Vec::new(),
222 marks: Vec::new(),
223 epoch: 0,
224 hint: 0,
225 rng: 0x9E37_79B9_7F4A_7C15,
226 frame: Vec::new(),
227 pending: Vec::new(),
228 seen: HashMap::new(),
229 scratch: Scratch::default(),
230 }
231 }
232
233 pub fn from_points(points: &[Point3]) -> Result<Self, Delaunay3Error> {
245 let mut triangulation = Self::new();
246 triangulation.points.reserve(points.len());
247 for (index, &p) in points.iter().enumerate() {
248 triangulation.points.push(check_point(p, index)?);
249 }
250 let count = u32::try_from(points.len()).map_err(|_| Delaunay3Error::OutOfRange {
251 index: u32::MAX as usize,
252 })?;
253 triangulation.vertex = (0..count).collect();
254 let all: Vec<u32> = (0..count).collect();
255 for index in hilbert::order(&triangulation.points, &all) {
256 triangulation.insert_index(index);
257 }
258 if triangulation.frame.len() < 4 {
259 return Err(Delaunay3Error::NotFullDimensional {
260 dimension: triangulation.dimension(),
261 });
262 }
263 Ok(triangulation)
264 }
265
266 pub fn insert(&mut self, point: Point3) -> Result<Insertion, Delaunay3Error> {
277 let index = self.points.len();
278 let point = check_point(point, index)?;
279 let id = u32::try_from(index)
280 .ok()
281 .filter(|&id| id != INFINITE)
282 .ok_or(Delaunay3Error::OutOfRange { index })?;
283 self.points.push(point);
284 self.vertex.push(id);
285 Ok(self.insert_index(id))
286 }
287
288 #[must_use]
290 pub fn points(&self) -> &[Point3] {
291 &self.points
292 }
293
294 #[must_use]
301 pub fn vertex_of(&self, index: usize) -> usize {
302 self.vertex[index] as usize
303 }
304
305 #[must_use]
307 pub fn dimension(&self) -> Option<usize> {
308 self.frame.len().checked_sub(1)
309 }
310
311 #[must_use]
313 pub fn tetrahedron_count(&self) -> usize {
314 self.live_cells()
315 .filter(|&c| self.cells[c].infinite_index().is_none())
316 .count()
317 }
318
319 #[must_use]
321 pub fn tetrahedra(&self) -> Tetrahedra {
322 let mut id = vec![usize::MAX; self.cells.len()];
323 let mut tetrahedra = Vec::new();
324 for c in self.live_cells() {
325 let cell = &self.cells[c];
326 if cell.infinite_index().is_none() {
327 id[c] = tetrahedra.len();
328 tetrahedra.push(cell.vertices.map(|v| v as usize));
329 }
330 }
331 let neighbors = self
332 .live_cells()
333 .filter(|&c| id[c] != usize::MAX)
334 .map(|c| {
335 self.cells[c].neighbors.map(|n| {
336 let n = id[n as usize];
337 (n != usize::MAX).then_some(n)
338 })
339 })
340 .collect();
341 Tetrahedra {
342 tetrahedra,
343 neighbors,
344 }
345 }
346
347 #[must_use]
353 pub fn hull_triangles(&self) -> Vec<[usize; 3]> {
354 self.live_cells()
355 .filter_map(|c| {
356 let cell = &self.cells[c];
357 let k = cell.infinite_index()?;
358 let mut order = cell.vertices;
359 order.swap(k, 3);
363 if k != 3 {
364 order.swap(0, 1);
365 }
366 Some([order[0], order[1], order[2]].map(|v| v as usize))
367 })
368 .collect()
369 }
370
371 fn live_cells(&self) -> impl Iterator<Item = usize> + '_ {
372 (0..self.cells.len()).filter(|&c| self.alive[c])
373 }
374
375 fn point(&self, v: u32) -> Point3 {
376 self.points[v as usize]
377 }
378
379 fn next_random(&mut self) -> u64 {
380 self.rng ^= self.rng << 13;
381 self.rng ^= self.rng >> 7;
382 self.rng ^= self.rng << 17;
383 self.rng
384 }
385
386 fn insert_index(&mut self, id: u32) -> Insertion {
388 if self.frame.len() == 4 {
389 return self.insert_3d(id);
390 }
391 let p = self.point(id);
392 if let Some(&existing) = self.seen.get(&key(p)) {
393 self.vertex[id as usize] = existing;
394 return Insertion::Duplicate(existing as usize);
395 }
396 self.seen.insert(key(p), id);
397 self.pending.push(id);
398 let raises = match self.frame.len() {
399 0 | 1 => true,
400 2 => !collinear(self.point(self.frame[0]), self.point(self.frame[1]), p),
401 _ => {
402 let [a, b, c] =
403 [self.frame[0], self.frame[1], self.frame[2]].map(|v| self.point(v));
404 orientation(a, b, c, p) != Sign::Zero
405 }
406 };
407 if raises {
408 self.frame.push(id);
409 }
410 if self.frame.len() == 4 {
411 self.build_first_tetrahedron();
412 let pending = std::mem::take(&mut self.pending);
413 self.seen = HashMap::new();
414 let rest: Vec<u32> = pending
415 .into_iter()
416 .filter(|v| !self.frame.contains(v))
417 .collect();
418 for v in hilbert::order(&self.points, &rest) {
419 let inserted = self.insert_3d(v);
420 debug_assert_eq!(inserted, Insertion::Vertex(v as usize));
421 }
422 }
423 Insertion::Vertex(id as usize)
424 }
425
426 fn build_first_tetrahedron(&mut self) {
428 let [a, b, mut c, mut d] = [self.frame[0], self.frame[1], self.frame[2], self.frame[3]];
429 if orientation(self.point(a), self.point(b), self.point(c), self.point(d)) == Sign::Negative
430 {
431 std::mem::swap(&mut c, &mut d);
432 }
433 let finite = [a, b, c, d];
434 let mut cells = vec![finite];
435 for i in 0..4 {
436 let mut ghost = finite;
437 ghost[i] = INFINITE;
438 let others: Vec<usize> = (0..4).filter(|&j| j != i).collect();
441 ghost.swap(others[0], others[1]);
442 cells.push(ghost);
443 }
444 for vertices in &cells {
445 self.allocate(Cell {
446 vertices: *vertices,
447 neighbors: [INFINITE; 4],
448 });
449 }
450 for x in 0..5 {
452 for i in 0..4 {
453 let face = face_key(cells[x], i);
454 for (y, other) in cells.iter().enumerate() {
455 if y == x {
456 continue;
457 }
458 if let Some(j) = (0..4).find(|&j| face_key(*other, j) == face) {
459 self.cells[x].neighbors[i] = y as u32;
460 debug_assert!(j < 4);
461 }
462 }
463 }
464 }
465 self.hint = 0;
466 }
467
468 fn allocate(&mut self, cell: Cell) -> u32 {
469 if let Some(c) = self.free.pop() {
470 self.cells[c as usize] = cell;
471 self.alive[c as usize] = true;
472 c
473 } else {
474 self.cells.push(cell);
475 self.alive.push(true);
476 self.marks.push(0);
477 (self.cells.len() - 1) as u32
478 }
479 }
480
481 fn orientation_with(&self, c: u32, slot: usize, p: u32) -> Sign {
484 let mut vertices = self.cells[c as usize].vertices;
485 vertices[slot] = p;
486 if vertices.contains(&INFINITE) {
487 return Sign::Zero;
488 }
489 let [a, b, x, y] = vertices.map(|v| self.point(v));
490 orientation(a, b, x, y)
491 }
492
493 fn locate(&mut self, p: u32) -> u32 {
496 let mut c = if self.alive[self.hint as usize] {
497 self.hint
498 } else {
499 self.live_cells().next().map_or(0, |c| c as u32)
500 };
501 let mut previous = INFINITE;
502 let budget = 4 * self.cells.len() + 64;
503 for _ in 0..budget {
504 let cell = self.cells[c as usize];
505 if let Some(k) = cell.infinite_index() {
506 if self.orientation_with(c, k, p) == Sign::Positive {
507 return c;
508 }
509 previous = c;
510 c = cell.neighbors[k];
511 continue;
512 }
513 let start = (self.next_random() % 4) as usize;
514 let mut moved = false;
515 for t in 0..4 {
516 let i = (start + t) % 4;
517 let next = cell.neighbors[i];
518 if next == previous {
519 continue;
520 }
521 if self.orientation_with(c, i, p) == Sign::Negative {
522 previous = c;
523 c = next;
524 moved = true;
525 break;
526 }
527 }
528 if !moved {
529 return c;
530 }
531 }
532 self.locate_exhaustively(p)
533 }
534
535 fn locate_exhaustively(&self, p: u32) -> u32 {
537 let mut beyond = None;
538 for c in self.live_cells() {
539 let cell = &self.cells[c];
540 match cell.infinite_index() {
541 Some(k) => {
542 if beyond.is_none() && self.orientation_with(c as u32, k, p) == Sign::Positive {
543 beyond = Some(c as u32);
544 }
545 }
546 None => {
547 if (0..4).all(|i| self.orientation_with(c as u32, i, p) != Sign::Negative) {
548 return c as u32;
549 }
550 }
551 }
552 }
553 beyond.unwrap_or(self.hint)
554 }
555
556 fn in_conflict(&self, c: u32, p: u32) -> bool {
557 let cell = &self.cells[c as usize];
558 match cell.infinite_index() {
559 None => in_sphere(&self.points, cell.vertices, p),
560 Some(k) => {
561 let mut order = cell.vertices;
564 order.swap(k, 3);
565 if k != 3 {
566 order.swap(0, 1);
567 }
568 beyond_face(&self.points, [order[0], order[1], order[2]], p)
569 }
570 }
571 }
572
573 fn insert_3d(&mut self, p: u32) -> Insertion {
574 let start = self.locate(p);
575 let located = self.cells[start as usize];
576 if located.infinite_index().is_none() {
577 let point = self.point(p);
578 if let Some(&v) = located
579 .vertices
580 .iter()
581 .find(|&&v| key(self.point(v)) == key(point))
582 {
583 self.vertex[p as usize] = v;
584 return Insertion::Duplicate(v as usize);
585 }
586 }
587
588 let mut scratch = std::mem::take(&mut self.scratch);
592 scratch.clear();
593 self.epoch += 1;
594 let conflict = 2 * self.epoch + 1;
595 let clear = 2 * self.epoch;
596 scratch.stack.push(start);
597 scratch.region.push(start);
598 self.marks[start as usize] = conflict;
599 while let Some(c) = scratch.stack.pop() {
600 for i in 0..4 {
601 let n = self.cells[c as usize].neighbors[i];
602 let mark = self.marks[n as usize];
603 if mark == conflict {
604 continue;
605 }
606 if mark != clear && self.in_conflict(n, p) {
607 self.marks[n as usize] = conflict;
608 scratch.stack.push(n);
609 scratch.region.push(n);
610 } else {
611 self.marks[n as usize] = clear;
612 let j = self.cells[n as usize]
614 .neighbors
615 .iter()
616 .position(|&m| m == c)
617 .expect("adjacency is symmetric");
618 let mut vertices = self.cells[c as usize].vertices;
619 vertices[i] = p;
620 let mut neighbors = [INFINITE; 4];
621 neighbors[i] = n;
622 scratch.created.push((
623 Cell {
624 vertices,
625 neighbors,
626 },
627 i,
628 n,
629 j,
630 ));
631 }
632 }
633 }
634
635 for &c in &scratch.region {
638 self.alive[c as usize] = false;
639 self.free.push(c);
640 }
641 for &(cell, _, outside, j) in &scratch.created {
642 let id = self.allocate(cell);
643 self.cells[outside as usize].neighbors[j] = id;
644 scratch.ids.push(id);
645 }
646
647 let capacity = (6 * scratch.created.len()).next_power_of_two();
651 scratch.edges.clear();
652 scratch.edges.resize(capacity, (u64::MAX, 0));
653 for (k, &(cell, i, _, _)) in scratch.created.iter().enumerate() {
654 for j in (0..4).filter(|&j| j != i) {
655 let mut ends = (0..4)
656 .filter(|&slot| slot != i && slot != j)
657 .map(|slot| cell.vertices[slot]);
658 let (x, y) = (
659 ends.next().unwrap_or(INFINITE),
660 ends.next().unwrap_or(INFINITE),
661 );
662 let edge = (u64::from(x.min(y)) << 32) | u64::from(x.max(y));
663 let here = (scratch.ids[k], j as u32);
664 let mut probe = (edge.wrapping_mul(0x9E37_79B9_7F4A_7C15) >> 32) as usize;
666 loop {
667 probe &= capacity - 1;
668 let (stored, other) = scratch.edges[probe];
669 if stored == u64::MAX {
670 scratch.edges[probe] = (edge, (u64::from(here.0) << 2) | u64::from(here.1));
671 break;
672 }
673 if stored == edge {
674 let (b, l) = ((other >> 2) as u32, (other & 3) as usize);
675 self.cells[here.0 as usize].neighbors[j] = b;
676 self.cells[b as usize].neighbors[l] = here.0;
677 scratch.edges[probe].0 = u64::MAX - 1;
680 break;
681 }
682 probe += 1;
683 }
684 }
685 }
686 self.hint = scratch.ids[0];
687 self.scratch = scratch;
688 Insertion::Vertex(p as usize)
689 }
690}
691
692fn face_key(vertices: [u32; 4], i: usize) -> [u32; 3] {
694 let mut face = [0; 3];
695 let mut k = 0;
696 for (slot, &v) in vertices.iter().enumerate() {
697 if slot != i {
698 face[k] = v;
699 k += 1;
700 }
701 }
702 face.sort_unstable();
703 face
704}