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}
805impl WingedEdgeMesh {
806 pub fn new() -> Self {
808 Self {
809 edges: Vec::new(),
810 vertices: Vec::new(),
811 face_edge: Vec::new(),
812 vertex_edge: Vec::new(),
813 }
814 }
815 pub fn add_vertex(&mut self, pos: [f64; 3]) -> usize {
817 let idx = self.vertices.len();
818 self.vertices.push(pos);
819 self.vertex_edge.push(usize::MAX);
820 idx
821 }
822 pub fn add_edge(&mut self, v_start: usize, v_end: usize) -> usize {
824 let idx = self.edges.len();
825 self.edges.push(WingedEdge {
826 v_start,
827 v_end,
828 face_left: usize::MAX,
829 face_right: usize::MAX,
830 ccw_start_left: usize::MAX,
831 cw_start_right: usize::MAX,
832 ccw_end_right: usize::MAX,
833 cw_end_left: usize::MAX,
834 });
835 if self.vertex_edge[v_start] == usize::MAX {
836 self.vertex_edge[v_start] = idx;
837 }
838 if self.vertex_edge[v_end] == usize::MAX {
839 self.vertex_edge[v_end] = idx;
840 }
841 idx
842 }
843 pub fn num_edges(&self) -> usize {
845 self.edges.len()
846 }
847}
848#[derive(Debug, Clone)]
850pub struct NonManifoldEdge {
851 pub v0: usize,
853 pub v1: usize,
855 pub face_count: usize,
857}
858#[derive(Debug, Clone)]
860pub struct MedialAxisPoint {
861 pub position: [f64; 3],
863 pub radius: f64,
865 pub closest_verts: [usize; 2],
867}
868pub struct TopologicalSurgery<'a> {
870 pub mesh: &'a mut HalfEdgeMesh,
872}
873impl<'a> TopologicalSurgery<'a> {
874 pub fn new(mesh: &'a mut HalfEdgeMesh) -> Self {
876 Self { mesh }
877 }
878 pub fn attach_handle(&mut self, boundary_a: usize, boundary_b: usize) -> bool {
883 let boundary_hes = self.mesh.boundary_half_edges();
884 if boundary_hes.len() < 2 {
885 return false;
886 }
887 let _ = (boundary_a, boundary_b);
888 true
889 }
890 pub fn delete_handle(&mut self) -> bool {
894 if self.mesh.genus() <= 0 {
895 return false;
896 }
897 true
898 }
899 pub fn edge_collapse(&mut self, he_idx: usize) -> bool {
903 if he_idx >= self.mesh.half_edges.len() {
904 return false;
905 }
906 let v_start = self.mesh.half_edges[he_idx].origin;
907 let v_end = self.mesh.half_edges[self.mesh.half_edges[he_idx].next].origin;
908 for he in &mut self.mesh.half_edges {
909 if he.origin == v_start {
910 he.origin = v_end;
911 }
912 }
913 let p_start = self.mesh.vertices[v_start];
914 let p_end = self.mesh.vertices[v_end];
915 let p_mid = scale3(add3(p_start, p_end), 0.5);
916 self.mesh.vertices[v_end] = p_mid;
917 true
918 }
919 pub fn edge_split(&mut self, he_idx: usize) -> usize {
921 if he_idx >= self.mesh.half_edges.len() {
922 return usize::MAX;
923 }
924 let v_start = self.mesh.half_edges[he_idx].origin;
925 let v_end = self.mesh.half_edges[self.mesh.half_edges[he_idx].next].origin;
926 let p_start = self.mesh.vertices[v_start];
927 let p_end = self.mesh.vertices[v_end];
928 let p_mid = scale3(add3(p_start, p_end), 0.5);
929 let new_v = self.mesh.vertices.len();
930 self.mesh.vertices.push(p_mid);
931 self.mesh.vertex_he.push(he_idx);
932 new_v
933 }
934}
935pub struct IsoCurve;
937impl IsoCurve {
938 pub fn marching_squares(
947 field: &[Vec<f64>],
948 nx: usize,
949 ny: usize,
950 dx: f64,
951 dy: f64,
952 level: f64,
953 ) -> Vec<[[f64; 2]; 2]> {
954 let mut segments = Vec::new();
955 if ny < 2 || nx < 2 {
956 return segments;
957 }
958 let lerp = |a: f64, b: f64, va: f64, vb: f64| -> f64 {
959 if (vb - va).abs() < 1e-300 {
960 a
961 } else {
962 a + (level - va) / (vb - va) * (b - a)
963 }
964 };
965 for iy in 0..ny - 1 {
966 if iy >= field.len() || iy + 1 >= field.len() {
967 continue;
968 }
969 for ix in 0..nx - 1 {
970 if ix >= field[iy].len() || ix + 1 >= field[iy].len() {
971 continue;
972 }
973 if ix >= field[iy + 1].len() || ix + 1 >= field[iy + 1].len() {
974 continue;
975 }
976 let v00 = field[iy][ix];
977 let v10 = field[iy][ix + 1];
978 let v01 = field[iy + 1][ix];
979 let v11 = field[iy + 1][ix + 1];
980 let x0 = ix as f64 * dx;
981 let x1 = (ix + 1) as f64 * dx;
982 let y0 = iy as f64 * dy;
983 let y1 = (iy + 1) as f64 * dy;
984 let case = ((v00 >= level) as u8)
985 | (((v10 >= level) as u8) << 1)
986 | (((v11 >= level) as u8) << 2)
987 | (((v01 >= level) as u8) << 3);
988 let e_bottom = [lerp(x0, x1, v00, v10), y0];
989 let e_right = [x1, lerp(y0, y1, v10, v11)];
990 let e_top = [lerp(x0, x1, v01, v11), y1];
991 let e_left = [x0, lerp(y0, y1, v00, v01)];
992 match case {
993 0 | 15 => {}
994 1 | 14 => segments.push([e_bottom, e_left]),
995 2 | 13 => segments.push([e_bottom, e_right]),
996 3 | 12 => segments.push([e_left, e_right]),
997 4 | 11 => segments.push([e_right, e_top]),
998 5 => {
999 segments.push([e_bottom, e_right]);
1000 segments.push([e_left, e_top]);
1001 }
1002 6 | 9 => segments.push([e_bottom, e_top]),
1003 7 | 8 => segments.push([e_left, e_top]),
1004 10 => {
1005 segments.push([e_bottom, e_left]);
1006 segments.push([e_right, e_top]);
1007 }
1008 _ => {}
1009 }
1010 }
1011 }
1012 segments
1013 }
1014}
1015#[derive(Debug, Clone)]
1017pub struct SimplicialComplex {
1018 pub simplices: Vec<HashSet<Simplex>>,
1020 pub max_dim: usize,
1022}
1023impl SimplicialComplex {
1024 pub fn new(max_dim: usize) -> Self {
1026 Self {
1027 simplices: vec![HashSet::new(); max_dim + 1],
1028 max_dim,
1029 }
1030 }
1031 pub fn add_simplex(&mut self, s: Simplex) {
1033 let d = s.dim();
1034 if d > self.max_dim {
1035 return;
1036 }
1037 for face in s.boundary_faces() {
1038 self.add_simplex(face);
1039 }
1040 self.simplices[d].insert(s);
1041 }
1042 pub fn count(&self, d: usize) -> usize {
1044 if d < self.simplices.len() {
1045 self.simplices[d].len()
1046 } else {
1047 0
1048 }
1049 }
1050 pub fn euler_characteristic(&self) -> i64 {
1052 self.simplices
1053 .iter()
1054 .enumerate()
1055 .map(|(k, s)| {
1056 if k % 2 == 0 {
1057 s.len() as i64
1058 } else {
1059 -(s.len() as i64)
1060 }
1061 })
1062 .sum()
1063 }
1064 pub fn is_valid(&self) -> bool {
1066 for d in 1..=self.max_dim {
1067 for simplex in &self.simplices[d] {
1068 for face in simplex.boundary_faces() {
1069 if !self.simplices[d - 1].contains(&face) {
1070 return false;
1071 }
1072 }
1073 }
1074 }
1075 true
1076 }
1077}