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