1#![allow(clippy::ptr_arg)]
6use super::functions::*;
7use std::collections::{HashMap, HashSet};
8
9#[derive(Debug, Clone, Copy)]
11pub struct MorseVertex {
12 pub idx: usize,
14 pub value: f64,
16 pub critical_type: MorseCriticalType,
18}
19pub struct PolygonOffset;
21impl PolygonOffset {
22 pub fn offset_polygon_2d(verts: &[[f64; 2]], dist: f64) -> Vec<[f64; 2]> {
27 let n = verts.len();
28 if n < 3 {
29 return verts.to_vec();
30 }
31 let edge_normal = |a: [f64; 2], b: [f64; 2]| -> [f64; 2] {
32 let dx = b[0] - a[0];
33 let dy = b[1] - a[1];
34 let len = (dx * dx + dy * dy).sqrt();
35 if len < 1e-300 {
36 [0.0, 1.0]
37 } else {
38 [dy / len, -dx / len]
39 }
40 };
41 let mut result = Vec::with_capacity(n);
42 for i in 0..n {
43 let prev = if i == 0 { n - 1 } else { i - 1 };
44 let next = (i + 1) % n;
45 let n_prev = edge_normal(verts[prev], verts[i]);
46 let n_next = edge_normal(verts[i], verts[next]);
47 let bx = n_prev[0] + n_next[0];
48 let by = n_prev[1] + n_next[1];
49 let blen = (bx * bx + by * by).sqrt();
50 let (ox, oy) = if blen < 1e-12 {
51 (n_next[0] * dist, n_next[1] * dist)
52 } else {
53 let dot = n_prev[0] * n_next[0] + n_prev[1] * n_next[1];
54 let miter_scale = dist / (1.0 + dot).max(0.1).sqrt();
55 (bx / blen * miter_scale, by / blen * miter_scale)
56 };
57 result.push([verts[i][0] + ox, verts[i][1] + oy]);
58 }
59 result
60 }
61 pub fn signed_area(verts: &[[f64; 2]]) -> f64 {
63 let n = verts.len();
64 if n < 3 {
65 return 0.0;
66 }
67 let mut area = 0.0;
68 for i in 0..n {
69 let j = (i + 1) % n;
70 area += verts[i][0] * verts[j][1];
71 area -= verts[j][0] * verts[i][1];
72 }
73 area * 0.5
74 }
75 pub fn is_ccw(verts: &[[f64; 2]]) -> bool {
77 Self::signed_area(verts) > 0.0
78 }
79}
80#[derive(Debug, Clone, Copy, PartialEq, Eq)]
82pub struct HalfEdge {
83 pub origin: usize,
85 pub next: usize,
87 pub prev: usize,
89 pub twin: usize,
91 pub face: usize,
93}
94impl HalfEdge {
95 pub fn new(origin: usize) -> Self {
97 Self {
98 origin,
99 next: usize::MAX,
100 prev: usize::MAX,
101 twin: usize::MAX,
102 face: usize::MAX,
103 }
104 }
105 pub fn is_boundary(&self) -> bool {
107 self.twin == usize::MAX
108 }
109}
110#[derive(Debug, Clone)]
112pub struct HalfEdgeMesh {
113 pub half_edges: Vec<HalfEdge>,
115 pub vertices: Vec<[f64; 3]>,
117 pub vertex_he: Vec<usize>,
119 pub faces: Vec<Face>,
121}
122impl HalfEdgeMesh {
123 pub fn new() -> Self {
125 Self {
126 half_edges: Vec::new(),
127 vertices: Vec::new(),
128 vertex_he: Vec::new(),
129 faces: Vec::new(),
130 }
131 }
132 pub fn from_triangles(verts: Vec<[f64; 3]>, faces: &[[usize; 3]]) -> Self {
134 let nv = verts.len();
135 let nf = faces.len();
136 let nhe = nf * 3;
137 let mut he = vec![
138 HalfEdge {
139 origin: 0,
140 next: usize::MAX,
141 prev: usize::MAX,
142 twin: usize::MAX,
143 face: usize::MAX,
144 };
145 nhe
146 ];
147 let mut face_list = Vec::with_capacity(nf);
148 let mut vertex_he = vec![usize::MAX; nv];
149 for (fi, tri) in faces.iter().enumerate() {
150 let base = fi * 3;
151 for k in 0..3 {
152 let he_idx = base + k;
153 he[he_idx].origin = tri[k];
154 he[he_idx].next = base + (k + 1) % 3;
155 he[he_idx].prev = base + (k + 2) % 3;
156 he[he_idx].face = fi;
157 if vertex_he[tri[k]] == usize::MAX {
158 vertex_he[tri[k]] = he_idx;
159 }
160 }
161 face_list.push(Face {
162 start_he: base,
163 is_outer: false,
164 });
165 }
166 let mut edge_map: HashMap<(usize, usize), usize> = HashMap::new();
167 for (i, h) in he.iter().enumerate() {
168 let dst = he[h.next].origin;
169 edge_map.insert((h.origin, dst), i);
170 }
171 for i in 0..nhe {
172 if he[i].twin != usize::MAX {
173 continue;
174 }
175 let src = he[i].origin;
176 let dst = he[he[i].next].origin;
177 if let Some(&twin_idx) = edge_map.get(&(dst, src)) {
178 he[i].twin = twin_idx;
179 he[twin_idx].twin = i;
180 }
181 }
182 Self {
183 half_edges: he,
184 vertices: verts,
185 vertex_he,
186 faces: face_list,
187 }
188 }
189 pub fn num_vertices(&self) -> usize {
191 self.vertices.len()
192 }
193 pub fn num_faces(&self) -> usize {
195 self.faces.len()
196 }
197 pub fn num_edges(&self) -> usize {
199 let interior: usize = self
200 .half_edges
201 .iter()
202 .filter(|he| he.twin != usize::MAX && he.twin > self.half_edges.len() / 2)
203 .count();
204 let boundary: usize = self
205 .half_edges
206 .iter()
207 .filter(|he| he.twin == usize::MAX)
208 .count();
209 interior + boundary
210 }
211 pub fn face_half_edges(&self, fi: usize) -> Vec<usize> {
213 let start = self.faces[fi].start_he;
214 let mut cur = start;
215 let mut result = Vec::new();
216 loop {
217 result.push(cur);
218 cur = self.half_edges[cur].next;
219 if cur == start {
220 break;
221 }
222 if result.len() > 100 {
223 break;
224 }
225 }
226 result
227 }
228 pub fn face_vertices(&self, fi: usize) -> Vec<[f64; 3]> {
230 self.face_half_edges(fi)
231 .iter()
232 .map(|&he_idx| self.vertices[self.half_edges[he_idx].origin])
233 .collect()
234 }
235 pub fn face_normal(&self, fi: usize) -> [f64; 3] {
237 let verts = self.face_vertices(fi);
238 if verts.len() < 3 {
239 return [0.0, 1.0, 0.0];
240 }
241 let e1 = sub3(verts[1], verts[0]);
242 let e2 = sub3(verts[2], verts[0]);
243 norm3(cross3(e1, e2))
244 }
245 pub fn euler_characteristic(&self) -> i64 {
247 let v = self.num_vertices() as i64;
248 let e = self.count_unique_edges() as i64;
249 let f = self.num_faces() as i64;
250 v - e + f
251 }
252 pub fn count_unique_edges(&self) -> usize {
254 let mut seen: HashSet<(usize, usize)> = HashSet::new();
255 for he in &self.half_edges {
256 if he.face == usize::MAX {
257 continue;
258 }
259 let a = he.origin;
260 let b = self.half_edges[he.next].origin;
261 let key = if a < b { (a, b) } else { (b, a) };
262 seen.insert(key);
263 }
264 seen.len()
265 }
266 pub fn genus(&self) -> i64 {
270 (2 - self.euler_characteristic()) / 2
271 }
272 pub fn boundary_half_edges(&self) -> Vec<usize> {
274 self.half_edges
275 .iter()
276 .enumerate()
277 .filter(|(_, he)| he.twin == usize::MAX)
278 .map(|(i, _)| i)
279 .collect()
280 }
281 pub fn is_closed(&self) -> bool {
283 self.boundary_half_edges().is_empty()
284 }
285 pub fn is_manifold(&self) -> bool {
290 let mut edge_count: HashMap<(usize, usize), usize> = HashMap::new();
291 for he in &self.half_edges {
292 if he.face == usize::MAX {
293 continue;
294 }
295 let a = he.origin;
296 let b = self.half_edges[he.next].origin;
297 let key = if a < b { (a, b) } else { (b, a) };
298 *edge_count.entry(key).or_insert(0) += 1;
299 }
300 edge_count.values().all(|&c| c <= 2)
301 }
302 pub fn vertex_normals(&self) -> Vec<[f64; 3]> {
304 let nv = self.num_vertices();
305 let mut normals = vec![[0.0f64; 3]; nv];
306 let mut counts = vec![0usize; nv];
307 for fi in 0..self.num_faces() {
308 let n = self.face_normal(fi);
309 for he_idx in self.face_half_edges(fi) {
310 let v = self.half_edges[he_idx].origin;
311 normals[v] = add3(normals[v], n);
312 counts[v] += 1;
313 }
314 }
315 for (i, n) in normals.iter_mut().enumerate() {
316 if counts[i] > 0 {
317 *n = norm3(*n);
318 }
319 }
320 normals
321 }
322 pub fn face_area(&self, fi: usize) -> f64 {
324 let verts = self.face_vertices(fi);
325 if verts.len() < 3 {
326 return 0.0;
327 }
328 let e1 = sub3(verts[1], verts[0]);
329 let e2 = sub3(verts[2], verts[0]);
330 len3(cross3(e1, e2)) * 0.5
331 }
332 pub fn total_area(&self) -> f64 {
334 (0..self.num_faces()).map(|fi| self.face_area(fi)).sum()
335 }
336 pub fn vertex_neighbors(&self, v: usize) -> Vec<usize> {
338 let mut neighbors = Vec::new();
339 let start = self.vertex_he[v];
340 if start == usize::MAX {
341 return neighbors;
342 }
343 let mut cur = start;
344 loop {
345 let next_he = self.half_edges[cur].next;
346 let neighbor = self.half_edges[next_he].origin;
347 neighbors.push(neighbor);
348 if self.half_edges[cur].twin == usize::MAX {
349 break;
350 }
351 cur = self.half_edges[self.half_edges[cur].twin].next;
352 if cur == start {
353 break;
354 }
355 if neighbors.len() > 1000 {
356 break;
357 }
358 }
359 neighbors
360 }
361}
362#[derive(Debug, Clone)]
364pub struct WingedEdge {
365 pub v_start: usize,
367 pub v_end: usize,
369 pub face_left: usize,
371 pub face_right: usize,
373 pub ccw_start_left: usize,
375 pub cw_start_right: usize,
377 pub ccw_end_right: usize,
379 pub cw_end_left: usize,
381}
382#[derive(Debug, Clone, Copy, PartialEq, Eq)]
384pub enum MorseCriticalType {
385 Minimum,
387 Saddle,
389 Maximum,
391 Regular,
393}
394#[derive(Debug, Clone, Copy, PartialEq, Eq)]
396pub struct MeshTopology {
397 pub n_vertices: usize,
399 pub n_edges: usize,
401 pub n_faces: usize,
403}
404impl MeshTopology {
405 pub fn new(n_vertices: usize, n_edges: usize, n_faces: usize) -> Self {
407 Self {
408 n_vertices,
409 n_edges,
410 n_faces,
411 }
412 }
413 pub fn euler_characteristic(&self) -> i32 {
415 self.n_vertices as i32 - self.n_edges as i32 + self.n_faces as i32
416 }
417 pub fn genus(&self) -> i32 {
419 (2 - self.euler_characteristic()) / 2
420 }
421 pub fn betti_0_estimate(&self) -> usize {
424 1
425 }
426 pub fn cycle_rank(&self) -> i32 {
428 self.n_edges as i32 - self.n_vertices as i32 + 1
429 }
430}
431pub struct MeshSimplification;
433impl MeshSimplification {
434 pub fn quadric_error_matrix(_vertex: [f64; 3], faces: &[[[f64; 3]; 3]]) -> [[f64; 4]; 4] {
439 let mut q = [[0.0f64; 4]; 4];
440 for tri in faces {
441 let e1 = sub3(tri[1], tri[0]);
442 let e2 = sub3(tri[2], tri[0]);
443 let n = norm3(cross3(e1, e2));
444 let d = -dot3(n, tri[0]);
445 let p = [n[0], n[1], n[2], d];
446 for i in 0..4 {
447 for j in 0..4 {
448 q[i][j] += p[i] * p[j];
449 }
450 }
451 }
452 q
453 }
454 pub fn edge_collapse_cost(
458 v1: [f64; 3],
459 v2: [f64; 3],
460 q1: [[f64; 4]; 4],
461 q2: [[f64; 4]; 4],
462 ) -> f64 {
463 let mut q = [[0.0f64; 4]; 4];
464 for i in 0..4 {
465 for j in 0..4 {
466 q[i][j] = q1[i][j] + q2[i][j];
467 }
468 }
469 let v = [
470 (v1[0] + v2[0]) * 0.5,
471 (v1[1] + v2[1]) * 0.5,
472 (v1[2] + v2[2]) * 0.5,
473 1.0,
474 ];
475 let mut cost = 0.0;
476 for i in 0..4 {
477 let mut row_sum = 0.0;
478 for j in 0..4 {
479 row_sum += q[i][j] * v[j];
480 }
481 cost += v[i] * row_sum;
482 }
483 cost.abs()
484 }
485 pub fn simplify_qem(
489 positions: &mut Vec<[f64; 3]>,
490 triangles: &mut Vec<[usize; 3]>,
491 target_count: usize,
492 ) {
493 while triangles.len() > target_count {
494 if triangles.is_empty() || positions.len() < 2 {
495 break;
496 }
497 let mut best_cost = f64::INFINITY;
498 let mut best_v1 = 0usize;
499 let mut best_v2 = 1usize;
500 let nv = positions.len();
501 let mut vertex_faces: Vec<Vec<usize>> = vec![Vec::new(); nv];
502 for (fi, tri) in triangles.iter().enumerate() {
503 for &v in tri.iter() {
504 if v < nv {
505 vertex_faces[v].push(fi);
506 }
507 }
508 }
509 let mut quadrics: Vec<[[f64; 4]; 4]> = vec![[[0.0; 4]; 4]; nv];
510 for v in 0..nv {
511 let face_tris: Vec<[[f64; 3]; 3]> = vertex_faces[v]
512 .iter()
513 .filter_map(|&fi| {
514 let t = triangles[fi];
515 if t[0] < nv && t[1] < nv && t[2] < nv {
516 Some([positions[t[0]], positions[t[1]], positions[t[2]]])
517 } else {
518 None
519 }
520 })
521 .collect();
522 quadrics[v] = Self::quadric_error_matrix(positions[v], &face_tris);
523 }
524 let mut seen_edges: HashSet<(usize, usize)> = HashSet::new();
525 for tri in triangles.iter() {
526 for k in 0..3 {
527 let a = tri[k];
528 let b = tri[(k + 1) % 3];
529 if a >= nv || b >= nv {
530 continue;
531 }
532 let key = if a < b { (a, b) } else { (b, a) };
533 if seen_edges.insert(key) {
534 let cost = Self::edge_collapse_cost(
535 positions[a],
536 positions[b],
537 quadrics[a],
538 quadrics[b],
539 );
540 if cost < best_cost {
541 best_cost = cost;
542 best_v1 = a;
543 best_v2 = b;
544 }
545 }
546 }
547 }
548 if best_cost.is_infinite() {
549 break;
550 }
551 let mid = [
552 (positions[best_v1][0] + positions[best_v2][0]) * 0.5,
553 (positions[best_v1][1] + positions[best_v2][1]) * 0.5,
554 (positions[best_v1][2] + positions[best_v2][2]) * 0.5,
555 ];
556 positions[best_v1] = mid;
557 for tri in triangles.iter_mut() {
558 for v in tri.iter_mut() {
559 if *v == best_v2 {
560 *v = best_v1;
561 }
562 }
563 }
564 triangles.retain(|t| t[0] != t[1] && t[1] != t[2] && t[0] != t[2]);
565 }
566 }
567}
568#[derive(Debug, Clone)]
570pub struct CurveSkeleton {
571 pub nodes: Vec<[f64; 3]>,
573 pub edges: Vec<(usize, usize)>,
575}
576impl Default for CurveSkeleton {
577 fn default() -> Self {
578 Self::new()
579 }
580}
581impl CurveSkeleton {
582 pub fn new() -> Self {
584 Self {
585 nodes: Vec::new(),
586 edges: Vec::new(),
587 }
588 }
589 pub fn add_node(&mut self, pos: [f64; 3]) -> usize {
591 let idx = self.nodes.len();
592 self.nodes.push(pos);
593 idx
594 }
595 pub fn add_edge(&mut self, a: usize, b: usize) {
597 self.edges.push((a, b));
598 }
599 pub fn total_length(&self) -> f64 {
601 self.edges
602 .iter()
603 .map(|&(a, b)| len3(sub3(self.nodes[b], self.nodes[a])))
604 .sum()
605 }
606 pub fn num_nodes(&self) -> usize {
608 self.nodes.len()
609 }
610 pub fn num_edges(&self) -> usize {
612 self.edges.len()
613 }
614}
615#[derive(Debug, Clone)]
617pub struct Face {
618 pub start_he: usize,
620 pub is_outer: bool,
622}
623#[derive(Debug, Clone, Default)]
625pub struct PersistenceDiagram {
626 pub pairs: Vec<BirthDeathPair>,
628}
629impl PersistenceDiagram {
630 pub fn new() -> Self {
632 Self { pairs: Vec::new() }
633 }
634 pub fn add_pair(&mut self, dim: usize, birth: f64, death: f64) {
636 self.pairs.push(BirthDeathPair { dim, birth, death });
637 }
638 pub fn pairs_for_dim(&self, dim: usize) -> Vec<&BirthDeathPair> {
640 self.pairs.iter().filter(|p| p.dim == dim).collect()
641 }
642 pub fn betti_at(&self, dim: usize, t: f64) -> usize {
644 self.pairs
645 .iter()
646 .filter(|p| p.dim == dim && p.birth <= t && t < p.death)
647 .count()
648 }
649 pub fn max_persistence(&self) -> f64 {
651 self.pairs
652 .iter()
653 .filter(|p| !p.is_essential())
654 .map(|p| p.persistence())
655 .fold(0.0_f64, f64::max)
656 }
657 pub fn bottleneck_distance(&self, other: &PersistenceDiagram) -> f64 {
659 let mut dist = 0.0_f64;
660 for p in &self.pairs {
661 let closest = other
662 .pairs
663 .iter()
664 .filter(|q| q.dim == p.dim)
665 .map(|q| (p.birth - q.birth).abs().max((p.death - q.death).abs()))
666 .fold(f64::MAX, f64::min);
667 if closest < f64::MAX {
668 dist = dist.max(closest);
669 }
670 }
671 dist
672 }
673}
674#[derive(Debug, Clone)]
676pub struct NonManifoldVertex {
677 pub v: usize,
679 pub fan_count: usize,
681}
682#[derive(Debug, Clone)]
684pub struct QuadEdgeMesh {
685 pub edges: Vec<QuadEdge>,
687 pub vertices: Vec<[f64; 3]>,
689}
690impl QuadEdgeMesh {
691 pub fn new() -> Self {
693 Self {
694 edges: Vec::new(),
695 vertices: Vec::new(),
696 }
697 }
698 pub fn make_edge(&mut self, org: usize, dst: usize) -> usize {
700 let base = self.edges.len() * 4;
701 let qe = QuadEdge {
702 next: [base, base + 3, base + 2, base + 1],
703 data: [org, 0, dst, 0],
704 };
705 self.edges.push(qe);
706 base
707 }
708 pub fn add_vertex(&mut self, pos: [f64; 3]) -> usize {
710 let idx = self.vertices.len();
711 self.vertices.push(pos);
712 idx
713 }
714 pub fn num_edges(&self) -> usize {
716 self.edges.len()
717 }
718}
719#[derive(Debug, Clone, PartialEq, Eq, Hash)]
721pub struct Simplex {
722 pub vertices: Vec<usize>,
724}
725impl Simplex {
726 pub fn new(mut verts: Vec<usize>) -> Self {
728 verts.sort_unstable();
729 verts.dedup();
730 Self { vertices: verts }
731 }
732 pub fn dim(&self) -> usize {
734 self.vertices.len().saturating_sub(1)
735 }
736 pub fn boundary_faces(&self) -> Vec<Simplex> {
738 if self.vertices.len() <= 1 {
739 return Vec::new();
740 }
741 (0..self.vertices.len())
742 .map(|i| {
743 let verts: Vec<usize> = self
744 .vertices
745 .iter()
746 .enumerate()
747 .filter(|(j, _)| *j != i)
748 .map(|(_, &v)| v)
749 .collect();
750 Simplex::new(verts)
751 })
752 .collect()
753 }
754 pub fn is_face_of(&self, other: &Simplex) -> bool {
756 self.vertices.iter().all(|v| other.vertices.contains(v))
757 }
758}
759#[derive(Debug, Clone)]
763pub struct QuadEdge {
764 pub next: [usize; 4],
766 pub data: [usize; 4],
768}
769#[derive(Debug, Clone, Copy, PartialEq)]
771pub struct BirthDeathPair {
772 pub dim: usize,
774 pub birth: f64,
776 pub death: f64,
778}
779impl BirthDeathPair {
780 pub fn persistence(&self) -> f64 {
782 if self.death == f64::MAX {
783 f64::MAX
784 } else {
785 self.death - self.birth
786 }
787 }
788 pub fn is_essential(&self) -> bool {
790 self.death == f64::MAX
791 }
792}
793#[derive(Debug, Clone)]
795pub struct WingedEdgeMesh {
796 pub edges: Vec<WingedEdge>,
798 pub vertices: Vec<[f64; 3]>,
800 pub face_edge: Vec<usize>,
802 pub vertex_edge: Vec<usize>,
804 pub face_edges: Vec<Vec<(usize, bool)>>,
806}
807impl WingedEdgeMesh {
808 pub fn new() -> Self {
810 Self {
811 edges: Vec::new(),
812 vertices: Vec::new(),
813 face_edge: Vec::new(),
814 vertex_edge: Vec::new(),
815 face_edges: Vec::new(),
816 }
817 }
818 pub fn add_vertex(&mut self, pos: [f64; 3]) -> usize {
820 let idx = self.vertices.len();
821 self.vertices.push(pos);
822 self.vertex_edge.push(usize::MAX);
823 idx
824 }
825 pub fn add_edge(&mut self, v_start: usize, v_end: usize) -> usize {
827 let idx = self.edges.len();
828 self.edges.push(WingedEdge {
829 v_start,
830 v_end,
831 face_left: usize::MAX,
832 face_right: usize::MAX,
833 ccw_start_left: usize::MAX,
834 cw_start_right: usize::MAX,
835 ccw_end_right: usize::MAX,
836 cw_end_left: usize::MAX,
837 });
838 if self.vertex_edge[v_start] == usize::MAX {
839 self.vertex_edge[v_start] = idx;
840 }
841 if self.vertex_edge[v_end] == usize::MAX {
842 self.vertex_edge[v_end] = idx;
843 }
844 idx
845 }
846 pub fn add_face_oriented(&mut self, oriented: &[(usize, bool)]) -> usize {
850 let fi = self.face_edge.len();
851 self.face_edge
852 .push(oriented.first().map(|&(ei, _)| ei).unwrap_or(usize::MAX));
853 self.face_edges.push(oriented.to_vec());
854 fi
855 }
856 pub fn add_face(&mut self, edges: &[usize]) -> usize {
858 let fi = self.face_edge.len();
859 if edges.is_empty() {
860 self.face_edge.push(usize::MAX);
861 self.face_edges.push(vec![]);
862 return fi;
863 }
864 self.face_edge.push(edges[0]);
865 let mut oriented = Vec::with_capacity(edges.len());
866 oriented.push((edges[0], true));
867 let mut prev_end = self.edges[edges[0]].v_end;
868 for &ei in &edges[1..] {
869 let e = &self.edges[ei];
870 if e.v_start == prev_end {
871 oriented.push((ei, true));
872 prev_end = e.v_end;
873 } else {
874 oriented.push((ei, false));
875 prev_end = e.v_start;
876 }
877 }
878 self.face_edges.push(oriented);
879 fi
880 }
881 pub fn build_adjacency(&mut self) {
893 for fi in 0..self.face_edges.len() {
895 let oriented = self.face_edges[fi].clone();
896 for &(ei, fwd) in &oriented {
897 if fwd {
898 self.edges[ei].face_left = fi;
899 } else {
900 self.edges[ei].face_right = fi;
901 }
902 }
903 }
904 for fi in 0..self.face_edges.len() {
906 let oriented = self.face_edges[fi].clone();
907 let n = oriented.len();
908 if n == 0 {
909 continue;
910 }
911 for k in 0..n {
912 let (ei, fwd) = oriented[k];
913 let prev = oriented[(k + n - 1) % n].0;
914 let next = oriented[(k + 1) % n].0;
915 if fwd {
916 self.edges[ei].ccw_start_left = prev;
917 self.edges[ei].cw_end_left = next;
918 } else {
919 self.edges[ei].cw_start_right = next;
920 self.edges[ei].ccw_end_right = prev;
921 }
922 }
923 }
924 }
925 pub fn num_edges(&self) -> usize {
927 self.edges.len()
928 }
929 pub fn num_faces(&self) -> usize {
931 self.face_edge.len()
932 }
933}
934
935#[cfg(test)]
936mod winged_edge_tests {
937 use super::WingedEdgeMesh;
938
939 fn make_cube() -> WingedEdgeMesh {
940 let mut m = WingedEdgeMesh::new();
941 for p in &[
942 [0.0f64, 0.0, 0.0],
943 [1.0, 0.0, 0.0],
944 [1.0, 1.0, 0.0],
945 [0.0, 1.0, 0.0],
946 [0.0, 0.0, 1.0],
947 [1.0, 0.0, 1.0],
948 [1.0, 1.0, 1.0],
949 [0.0, 1.0, 1.0],
950 ] {
951 m.add_vertex(*p);
952 }
953 let e0 = m.add_edge(0, 1);
954 let e1 = m.add_edge(1, 2);
955 let e2 = m.add_edge(2, 3);
956 let e3 = m.add_edge(3, 0);
957 let e4 = m.add_edge(4, 5);
958 let e5 = m.add_edge(5, 6);
959 let e6 = m.add_edge(6, 7);
960 let e7 = m.add_edge(7, 4);
961 let e8 = m.add_edge(0, 4);
962 let e9 = m.add_edge(1, 5);
963 let e10 = m.add_edge(2, 6);
964 let e11 = m.add_edge(3, 7);
965 m.add_face_oriented(&[(e3, false), (e2, false), (e1, false), (e0, false)]); m.add_face_oriented(&[(e4, true), (e5, true), (e6, true), (e7, true)]); m.add_face_oriented(&[(e0, true), (e9, true), (e4, false), (e8, false)]); m.add_face_oriented(&[(e2, true), (e11, true), (e6, false), (e10, false)]); m.add_face_oriented(&[(e1, true), (e10, true), (e5, false), (e9, false)]); m.add_face_oriented(&[(e8, true), (e7, false), (e11, false), (e3, true)]); m.build_adjacency();
973 m
974 }
975
976 #[test]
977 fn test_cube_counts() {
978 let m = make_cube();
979 assert_eq!(m.num_edges(), 12);
980 assert_eq!(m.num_faces(), 6);
981 assert_eq!(m.vertices.len(), 8);
982 }
983
984 #[test]
985 fn test_face_references_assigned() {
986 let m = make_cube();
987 for (i, e) in m.edges.iter().enumerate() {
988 assert_ne!(e.face_left, usize::MAX, "edge {} face_left unset", i);
989 assert_ne!(e.face_right, usize::MAX, "edge {} face_right unset", i);
990 }
991 }
992
993 #[test]
994 fn test_wing_pointers_set() {
995 let m = make_cube();
996 for (i, e) in m.edges.iter().enumerate() {
997 assert_ne!(
998 e.ccw_start_left,
999 usize::MAX,
1000 "edge {} ccw_start_left unset",
1001 i
1002 );
1003 assert_ne!(
1004 e.cw_start_right,
1005 usize::MAX,
1006 "edge {} cw_start_right unset",
1007 i
1008 );
1009 assert_ne!(
1010 e.ccw_end_right,
1011 usize::MAX,
1012 "edge {} ccw_end_right unset",
1013 i
1014 );
1015 assert_ne!(e.cw_end_left, usize::MAX, "edge {} cw_end_left unset", i);
1016 }
1017 }
1018
1019 #[test]
1020 fn test_ccw_cycle_closes() {
1021 let m = make_cube();
1022 for start in 0..m.num_edges() {
1024 let mut cur = m.edges[start].ccw_start_left;
1025 let mut steps = 1usize;
1026 while cur != start {
1027 cur = m.edges[cur].ccw_start_left;
1028 steps += 1;
1029 assert!(
1030 steps <= 12,
1031 "ccw_start_left loop for edge {} did not close",
1032 start
1033 );
1034 }
1035 }
1036 }
1037}
1038#[derive(Debug, Clone)]
1040pub struct NonManifoldEdge {
1041 pub v0: usize,
1043 pub v1: usize,
1045 pub face_count: usize,
1047}
1048#[derive(Debug, Clone)]
1050pub struct MedialAxisPoint {
1051 pub position: [f64; 3],
1053 pub radius: f64,
1055 pub closest_verts: [usize; 2],
1057}
1058pub struct TopologicalSurgery<'a> {
1060 pub mesh: &'a mut HalfEdgeMesh,
1062}
1063impl<'a> TopologicalSurgery<'a> {
1064 pub fn new(mesh: &'a mut HalfEdgeMesh) -> Self {
1066 Self { mesh }
1067 }
1068 pub fn attach_handle(&mut self, boundary_a: usize, boundary_b: usize) -> bool {
1073 let boundary_hes = self.mesh.boundary_half_edges();
1074 if boundary_hes.len() < 2 {
1075 return false;
1076 }
1077 let _ = (boundary_a, boundary_b);
1078 true
1079 }
1080 pub fn delete_handle(&mut self) -> bool {
1084 if self.mesh.genus() <= 0 {
1085 return false;
1086 }
1087 true
1088 }
1089 pub fn edge_collapse(&mut self, he_idx: usize) -> bool {
1093 if he_idx >= self.mesh.half_edges.len() {
1094 return false;
1095 }
1096 let v_start = self.mesh.half_edges[he_idx].origin;
1097 let v_end = self.mesh.half_edges[self.mesh.half_edges[he_idx].next].origin;
1098 for he in &mut self.mesh.half_edges {
1099 if he.origin == v_start {
1100 he.origin = v_end;
1101 }
1102 }
1103 let p_start = self.mesh.vertices[v_start];
1104 let p_end = self.mesh.vertices[v_end];
1105 let p_mid = scale3(add3(p_start, p_end), 0.5);
1106 self.mesh.vertices[v_end] = p_mid;
1107 true
1108 }
1109 pub fn edge_split(&mut self, he_idx: usize) -> usize {
1111 if he_idx >= self.mesh.half_edges.len() {
1112 return usize::MAX;
1113 }
1114 let v_start = self.mesh.half_edges[he_idx].origin;
1115 let v_end = self.mesh.half_edges[self.mesh.half_edges[he_idx].next].origin;
1116 let p_start = self.mesh.vertices[v_start];
1117 let p_end = self.mesh.vertices[v_end];
1118 let p_mid = scale3(add3(p_start, p_end), 0.5);
1119 let new_v = self.mesh.vertices.len();
1120 self.mesh.vertices.push(p_mid);
1121 self.mesh.vertex_he.push(he_idx);
1122 new_v
1123 }
1124}
1125pub struct IsoCurve;
1127impl IsoCurve {
1128 pub fn marching_squares(
1137 field: &[Vec<f64>],
1138 nx: usize,
1139 ny: usize,
1140 dx: f64,
1141 dy: f64,
1142 level: f64,
1143 ) -> Vec<[[f64; 2]; 2]> {
1144 let mut segments = Vec::new();
1145 if ny < 2 || nx < 2 {
1146 return segments;
1147 }
1148 let lerp = |a: f64, b: f64, va: f64, vb: f64| -> f64 {
1149 if (vb - va).abs() < 1e-300 {
1150 a
1151 } else {
1152 a + (level - va) / (vb - va) * (b - a)
1153 }
1154 };
1155 for iy in 0..ny - 1 {
1156 if iy >= field.len() || iy + 1 >= field.len() {
1157 continue;
1158 }
1159 for ix in 0..nx - 1 {
1160 if ix >= field[iy].len() || ix + 1 >= field[iy].len() {
1161 continue;
1162 }
1163 if ix >= field[iy + 1].len() || ix + 1 >= field[iy + 1].len() {
1164 continue;
1165 }
1166 let v00 = field[iy][ix];
1167 let v10 = field[iy][ix + 1];
1168 let v01 = field[iy + 1][ix];
1169 let v11 = field[iy + 1][ix + 1];
1170 let x0 = ix as f64 * dx;
1171 let x1 = (ix + 1) as f64 * dx;
1172 let y0 = iy as f64 * dy;
1173 let y1 = (iy + 1) as f64 * dy;
1174 let case = ((v00 >= level) as u8)
1175 | (((v10 >= level) as u8) << 1)
1176 | (((v11 >= level) as u8) << 2)
1177 | (((v01 >= level) as u8) << 3);
1178 let e_bottom = [lerp(x0, x1, v00, v10), y0];
1179 let e_right = [x1, lerp(y0, y1, v10, v11)];
1180 let e_top = [lerp(x0, x1, v01, v11), y1];
1181 let e_left = [x0, lerp(y0, y1, v00, v01)];
1182 match case {
1183 0 | 15 => {}
1184 1 | 14 => segments.push([e_bottom, e_left]),
1185 2 | 13 => segments.push([e_bottom, e_right]),
1186 3 | 12 => segments.push([e_left, e_right]),
1187 4 | 11 => segments.push([e_right, e_top]),
1188 5 => {
1189 segments.push([e_bottom, e_right]);
1190 segments.push([e_left, e_top]);
1191 }
1192 6 | 9 => segments.push([e_bottom, e_top]),
1193 7 | 8 => segments.push([e_left, e_top]),
1194 10 => {
1195 segments.push([e_bottom, e_left]);
1196 segments.push([e_right, e_top]);
1197 }
1198 _ => {}
1199 }
1200 }
1201 }
1202 segments
1203 }
1204}
1205#[derive(Debug, Clone)]
1207pub struct SimplicialComplex {
1208 pub simplices: Vec<HashSet<Simplex>>,
1210 pub max_dim: usize,
1212}
1213impl SimplicialComplex {
1214 pub fn new(max_dim: usize) -> Self {
1216 Self {
1217 simplices: vec![HashSet::new(); max_dim + 1],
1218 max_dim,
1219 }
1220 }
1221 pub fn add_simplex(&mut self, s: Simplex) {
1223 let d = s.dim();
1224 if d > self.max_dim {
1225 return;
1226 }
1227 for face in s.boundary_faces() {
1228 self.add_simplex(face);
1229 }
1230 self.simplices[d].insert(s);
1231 }
1232 pub fn count(&self, d: usize) -> usize {
1234 if d < self.simplices.len() {
1235 self.simplices[d].len()
1236 } else {
1237 0
1238 }
1239 }
1240 pub fn euler_characteristic(&self) -> i64 {
1242 self.simplices
1243 .iter()
1244 .enumerate()
1245 .map(|(k, s)| {
1246 if k % 2 == 0 {
1247 s.len() as i64
1248 } else {
1249 -(s.len() as i64)
1250 }
1251 })
1252 .sum()
1253 }
1254 pub fn is_valid(&self) -> bool {
1256 for d in 1..=self.max_dim {
1257 for simplex in &self.simplices[d] {
1258 for face in simplex.boundary_faces() {
1259 if !self.simplices[d - 1].contains(&face) {
1260 return false;
1261 }
1262 }
1263 }
1264 }
1265 true
1266 }
1267}