1use super::functions::*;
6use super::functions::{MC_EDGE_CORNERS, MC_EDGE_TABLE, MC_TRI_TABLE};
7
8pub struct SignedDistanceTransform {
13 pub source_points: Vec<[f64; 3]>,
15}
16impl SignedDistanceTransform {
17 pub fn new(points: Vec<[f64; 3]>) -> Self {
22 Self {
23 source_points: points,
24 }
25 }
26 pub fn unsigned_distance(&self, p: [f64; 3]) -> f64 {
31 self.source_points
32 .iter()
33 .map(|&q| {
34 ((p[0] - q[0]).powi(2) + (p[1] - q[1]).powi(2) + (p[2] - q[2]).powi(2)).sqrt()
35 })
36 .fold(f64::MAX, f64::min)
37 }
38 pub fn compute_grid_unsigned(
47 &self,
48 nx: usize,
49 ny: usize,
50 nz: usize,
51 dx: f64,
52 origin: [f64; 3],
53 ) -> LevelSetField {
54 let mut field = LevelSetField::new(nx, ny, nz, dx, origin);
55 for iz in 0..nz {
56 for iy in 0..ny {
57 for ix in 0..nx {
58 let p = field.node_pos(ix, iy, iz);
59 let d = self.unsigned_distance(p);
60 field.set(ix, iy, iz, d);
61 }
62 }
63 }
64 field
65 }
66 pub fn compute_grid_signed(
72 &self,
73 nx: usize,
74 ny: usize,
75 nz: usize,
76 dx: f64,
77 origin: [f64; 3],
78 ) -> LevelSetField {
79 let mut field = self.compute_grid_unsigned(nx, ny, nz, dx, origin);
80 if self.source_points.is_empty() {
81 return field;
82 }
83 let centroid: [f64; 3] = {
84 let n = self.source_points.len() as f64;
85 let s = self.source_points.iter().fold([0.0_f64; 3], |acc, p| {
86 [acc[0] + p[0], acc[1] + p[1], acc[2] + p[2]]
87 });
88 [s[0] / n, s[1] / n, s[2] / n]
89 };
90 let radius = self.unsigned_distance(centroid);
91 for iz in 0..nz {
92 for iy in 0..ny {
93 for ix in 0..nx {
94 let p = field.node_pos(ix, iy, iz);
95 let dc = ((p[0] - centroid[0]).powi(2)
96 + (p[1] - centroid[1]).powi(2)
97 + (p[2] - centroid[2]).powi(2))
98 .sqrt();
99 let val = field.get(ix, iy, iz);
100 if dc < radius {
101 field.set(ix, iy, iz, -val);
102 }
103 }
104 }
105 }
106 field
107 }
108 pub fn point_to_segment(p: [f64; 3], a: [f64; 3], b: [f64; 3]) -> f64 {
110 let ab = [b[0] - a[0], b[1] - a[1], b[2] - a[2]];
111 let ap = [p[0] - a[0], p[1] - a[1], p[2] - a[2]];
112 let len2 = ab[0] * ab[0] + ab[1] * ab[1] + ab[2] * ab[2];
113 if len2 < 1e-30 {
114 return (ap[0] * ap[0] + ap[1] * ap[1] + ap[2] * ap[2]).sqrt();
115 }
116 let t = ((ap[0] * ab[0] + ap[1] * ab[1] + ap[2] * ab[2]) / len2).clamp(0.0, 1.0);
117 let closest = [a[0] + t * ab[0], a[1] + t * ab[1], a[2] + t * ab[2]];
118 ((p[0] - closest[0]).powi(2) + (p[1] - closest[1]).powi(2) + (p[2] - closest[2]).powi(2))
119 .sqrt()
120 }
121}
122pub struct LevelSetEvolution {
127 pub dt: f64,
129 pub n_steps: usize,
131}
132impl LevelSetEvolution {
133 pub fn new(dt: f64, n_steps: usize) -> Self {
139 Self { dt, n_steps }
140 }
141 pub fn advect(&self, field: &mut LevelSetField, velocity: [f64; 3]) {
149 let dx = field.dx;
150 let nx = field.nx;
151 let ny = field.ny;
152 let nz = field.nz;
153 for _ in 0..self.n_steps {
154 let old = field.data.clone();
155 for iz in 0..nz {
156 for iy in 0..ny {
157 for ix in 0..nx {
158 let phi_c = old[field.idx(ix, iy, iz)];
159 let dphi_x = if velocity[0] > 0.0 {
160 if ix > 0 {
161 (phi_c - old[field.idx(ix - 1, iy, iz)]) / dx
162 } else {
163 0.0
164 }
165 } else {
166 if ix + 1 < nx {
167 (old[field.idx(ix + 1, iy, iz)] - phi_c) / dx
168 } else {
169 0.0
170 }
171 };
172 let dphi_y = if velocity[1] > 0.0 {
173 if iy > 0 {
174 (phi_c - old[field.idx(ix, iy - 1, iz)]) / dx
175 } else {
176 0.0
177 }
178 } else {
179 if iy + 1 < ny {
180 (old[field.idx(ix, iy + 1, iz)] - phi_c) / dx
181 } else {
182 0.0
183 }
184 };
185 let dphi_z = if velocity[2] > 0.0 {
186 if iz > 0 {
187 (phi_c - old[field.idx(ix, iy, iz - 1)]) / dx
188 } else {
189 0.0
190 }
191 } else {
192 if iz + 1 < nz {
193 (old[field.idx(ix, iy, iz + 1)] - phi_c) / dx
194 } else {
195 0.0
196 }
197 };
198 let rhs =
199 velocity[0] * dphi_x + velocity[1] * dphi_y + velocity[2] * dphi_z;
200 let idx = field.idx(ix, iy, iz);
201 field.data[idx] = phi_c - self.dt * rhs;
202 }
203 }
204 }
205 }
206 }
207 pub fn mean_curvature_flow(&self, field: &mut LevelSetField) {
215 let dx = field.dx;
216 let nx = field.nx;
217 let ny = field.ny;
218 let nz = field.nz;
219 for _ in 0..self.n_steps {
220 let old = field.data.clone();
221 let old_field = LevelSetField {
222 nx,
223 ny,
224 nz,
225 dx,
226 origin: field.origin,
227 data: old,
228 };
229 for iz in 0..nz {
230 for iy in 0..ny {
231 for ix in 0..nx {
232 let kappa = old_field.mean_curvature(ix, iy, iz);
233 let grad = old_field.gradient(ix, iy, iz);
234 let grad_mag =
235 (grad[0] * grad[0] + grad[1] * grad[1] + grad[2] * grad[2]).sqrt();
236 let idx = field.idx(ix, iy, iz);
237 field.data[idx] = old_field.data[idx] + self.dt * kappa * grad_mag;
238 }
239 }
240 }
241 }
242 }
243 pub fn normal_velocity_extension(&self, field: &mut LevelSetField, normal_velocity: f64) {
252 let nx = field.nx;
253 let ny = field.ny;
254 let nz = field.nz;
255 for _ in 0..self.n_steps {
256 let old = field.data.clone();
257 let old_field = LevelSetField {
258 nx,
259 ny,
260 nz,
261 dx: field.dx,
262 origin: field.origin,
263 data: old,
264 };
265 for iz in 0..nz {
266 for iy in 0..ny {
267 for ix in 0..nx {
268 let grad = old_field.gradient(ix, iy, iz);
269 let grad_mag =
270 (grad[0] * grad[0] + grad[1] * grad[1] + grad[2] * grad[2]).sqrt();
271 let idx = field.idx(ix, iy, iz);
272 field.data[idx] =
273 old_field.data[idx] - self.dt * normal_velocity * grad_mag;
274 }
275 }
276 }
277 }
278 }
279}
280pub struct LevelSetBoolean;
285impl LevelSetBoolean {
286 pub fn union(field_a: &LevelSetField, field_b: &LevelSetField) -> LevelSetField {
294 let mut result = LevelSetField::new(
295 field_a.nx,
296 field_a.ny,
297 field_a.nz,
298 field_a.dx,
299 field_a.origin,
300 );
301 for i in 0..result.data.len() {
302 let va = field_a.data.get(i).copied().unwrap_or(f64::MAX);
303 let vb = field_b.data.get(i).copied().unwrap_or(f64::MAX);
304 result.data[i] = va.min(vb);
305 }
306 result
307 }
308 pub fn intersection(field_a: &LevelSetField, field_b: &LevelSetField) -> LevelSetField {
316 let mut result = LevelSetField::new(
317 field_a.nx,
318 field_a.ny,
319 field_a.nz,
320 field_a.dx,
321 field_a.origin,
322 );
323 for i in 0..result.data.len() {
324 let va = field_a.data.get(i).copied().unwrap_or(f64::MAX);
325 let vb = field_b.data.get(i).copied().unwrap_or(f64::MAX);
326 result.data[i] = va.max(vb);
327 }
328 result
329 }
330 pub fn difference(field_a: &LevelSetField, field_b: &LevelSetField) -> LevelSetField {
338 let mut result = LevelSetField::new(
339 field_a.nx,
340 field_a.ny,
341 field_a.nz,
342 field_a.dx,
343 field_a.origin,
344 );
345 for i in 0..result.data.len() {
346 let va = field_a.data.get(i).copied().unwrap_or(f64::MAX);
347 let vb = field_b.data.get(i).copied().unwrap_or(f64::MAX);
348 result.data[i] = va.max(-vb);
349 }
350 result
351 }
352 pub fn complement(field_a: &LevelSetField) -> LevelSetField {
359 let mut result = LevelSetField::new(
360 field_a.nx,
361 field_a.ny,
362 field_a.nz,
363 field_a.dx,
364 field_a.origin,
365 );
366 for i in 0..result.data.len() {
367 result.data[i] = -field_a.data[i];
368 }
369 result
370 }
371 pub fn smooth_union(field_a: &LevelSetField, field_b: &LevelSetField, k: f64) -> LevelSetField {
380 let mut result = LevelSetField::new(
381 field_a.nx,
382 field_a.ny,
383 field_a.nz,
384 field_a.dx,
385 field_a.origin,
386 );
387 for i in 0..result.data.len() {
388 let va = field_a.data.get(i).copied().unwrap_or(f64::MAX);
389 let vb = field_b.data.get(i).copied().unwrap_or(f64::MAX);
390 let h = (0.5 + 0.5 * (vb - va) / k.max(1e-30)).clamp(0.0, 1.0);
391 result.data[i] = va * h + vb * (1.0 - h) - k * h * (1.0 - h);
392 }
393 result
394 }
395}
396pub struct LevelSetField {
402 pub nx: usize,
404 pub ny: usize,
406 pub nz: usize,
408 pub dx: f64,
410 pub origin: [f64; 3],
412 pub data: Vec<f64>,
414}
415impl LevelSetField {
416 pub fn new(nx: usize, ny: usize, nz: usize, dx: f64, origin: [f64; 3]) -> Self {
423 let data = vec![f64::MAX; nx * ny * nz];
424 Self {
425 nx,
426 ny,
427 nz,
428 dx,
429 origin,
430 data,
431 }
432 }
433 #[inline]
435 pub fn idx(&self, ix: usize, iy: usize, iz: usize) -> usize {
436 iz * self.ny * self.nx + iy * self.nx + ix
437 }
438 #[inline]
440 pub fn node_pos(&self, ix: usize, iy: usize, iz: usize) -> [f64; 3] {
441 [
442 self.origin[0] + ix as f64 * self.dx,
443 self.origin[1] + iy as f64 * self.dx,
444 self.origin[2] + iz as f64 * self.dx,
445 ]
446 }
447 pub fn get(&self, ix: usize, iy: usize, iz: usize) -> f64 {
451 if ix >= self.nx || iy >= self.ny || iz >= self.nz {
452 return f64::MAX;
453 }
454 self.data[self.idx(ix, iy, iz)]
455 }
456 pub fn set(&mut self, ix: usize, iy: usize, iz: usize, value: f64) {
460 if ix >= self.nx || iy >= self.ny || iz >= self.nz {
461 return;
462 }
463 let i = self.idx(ix, iy, iz);
464 self.data[i] = value;
465 }
466 pub fn interpolate(&self, p: [f64; 3]) -> f64 {
470 let fx = (p[0] - self.origin[0]) / self.dx;
471 let fy = (p[1] - self.origin[1]) / self.dx;
472 let fz = (p[2] - self.origin[2]) / self.dx;
473 if fx < 0.0 || fy < 0.0 || fz < 0.0 {
474 return f64::MAX;
475 }
476 let ix = fx as usize;
477 let iy = fy as usize;
478 let iz = fz as usize;
479 if ix + 1 >= self.nx || iy + 1 >= self.ny || iz + 1 >= self.nz {
480 return f64::MAX;
481 }
482 let tx = fx - ix as f64;
483 let ty = fy - iy as f64;
484 let tz = fz - iz as f64;
485 let c000 = self.get(ix, iy, iz);
486 let c100 = self.get(ix + 1, iy, iz);
487 let c010 = self.get(ix, iy + 1, iz);
488 let c110 = self.get(ix + 1, iy + 1, iz);
489 let c001 = self.get(ix, iy, iz + 1);
490 let c101 = self.get(ix + 1, iy, iz + 1);
491 let c011 = self.get(ix, iy + 1, iz + 1);
492 let c111 = self.get(ix + 1, iy + 1, iz + 1);
493 let c00 = c000 * (1.0 - tx) + c100 * tx;
494 let c10 = c010 * (1.0 - tx) + c110 * tx;
495 let c01 = c001 * (1.0 - tx) + c101 * tx;
496 let c11 = c011 * (1.0 - tx) + c111 * tx;
497 let c0 = c00 * (1.0 - ty) + c10 * ty;
498 let c1 = c01 * (1.0 - ty) + c11 * ty;
499 c0 * (1.0 - tz) + c1 * tz
500 }
501 pub fn gradient(&self, ix: usize, iy: usize, iz: usize) -> [f64; 3] {
505 let gx = if ix == 0 {
506 (self.get(1, iy, iz) - self.get(0, iy, iz)) / self.dx
507 } else if ix + 1 == self.nx {
508 (self.get(ix, iy, iz) - self.get(ix - 1, iy, iz)) / self.dx
509 } else {
510 (self.get(ix + 1, iy, iz) - self.get(ix - 1, iy, iz)) / (2.0 * self.dx)
511 };
512 let gy = if iy == 0 {
513 (self.get(ix, 1, iz) - self.get(ix, 0, iz)) / self.dx
514 } else if iy + 1 == self.ny {
515 (self.get(ix, iy, iz) - self.get(ix, iy - 1, iz)) / self.dx
516 } else {
517 (self.get(ix, iy + 1, iz) - self.get(ix, iy - 1, iz)) / (2.0 * self.dx)
518 };
519 let gz = if iz == 0 {
520 (self.get(ix, iy, 1) - self.get(ix, iy, 0)) / self.dx
521 } else if iz + 1 == self.nz {
522 (self.get(ix, iy, iz) - self.get(ix, iy, iz - 1)) / self.dx
523 } else {
524 (self.get(ix, iy, iz + 1) - self.get(ix, iy, iz - 1)) / (2.0 * self.dx)
525 };
526 [gx, gy, gz]
527 }
528 pub fn mean_curvature(&self, ix: usize, iy: usize, iz: usize) -> f64 {
532 let phi = self.get(ix, iy, iz);
533 let dx2 = self.dx * self.dx;
534 let get = |x: usize, y: usize, z: usize| -> f64 {
535 let xc = x.min(self.nx - 1);
536 let yc = y.min(self.ny - 1);
537 let zc = z.min(self.nz - 1);
538 self.get(xc, yc, zc)
539 };
540 let pxp = if ix + 1 < self.nx {
541 get(ix + 1, iy, iz)
542 } else {
543 phi
544 };
545 let pxm = if ix > 0 { get(ix - 1, iy, iz) } else { phi };
546 let pyp = if iy + 1 < self.ny {
547 get(ix, iy + 1, iz)
548 } else {
549 phi
550 };
551 let pym = if iy > 0 { get(ix, iy - 1, iz) } else { phi };
552 let pzp = if iz + 1 < self.nz {
553 get(ix, iy, iz + 1)
554 } else {
555 phi
556 };
557 let pzm = if iz > 0 { get(ix, iy, iz - 1) } else { phi };
558 let phix = (pxp - pxm) / (2.0 * self.dx);
559 let phiy = (pyp - pym) / (2.0 * self.dx);
560 let phiz = (pzp - pzm) / (2.0 * self.dx);
561 let phixx = (pxp - 2.0 * phi + pxm) / dx2;
562 let phiyy = (pyp - 2.0 * phi + pym) / dx2;
563 let phizz = (pzp - 2.0 * phi + pzm) / dx2;
564 let grad2 = phix * phix + phiy * phiy + phiz * phiz;
565 let grad_mag = grad2.sqrt().max(1e-30);
566
567 (phixx + phiyy + phizz) / grad_mag
568 - (phix * phix * phixx
569 + phiy * phiy * phiyy
570 + phiz * phiz * phizz
571 + 2.0
572 * (phix * phiy * ((pxp + pyp - pxm - pym) / (4.0 * self.dx * self.dx) - 0.0)
573 + phix * phiz * 0.0
574 + phiy * phiz * 0.0))
575 / (grad_mag * grad2).max(1e-30)
576 }
577 pub fn init_sphere(&mut self, center: [f64; 3], radius: f64) {
581 for iz in 0..self.nz {
582 for iy in 0..self.ny {
583 for ix in 0..self.nx {
584 let p = self.node_pos(ix, iy, iz);
585 let d = ((p[0] - center[0]).powi(2)
586 + (p[1] - center[1]).powi(2)
587 + (p[2] - center[2]).powi(2))
588 .sqrt();
589 self.set(ix, iy, iz, d - radius);
590 }
591 }
592 }
593 }
594 pub fn init_box(&mut self, lo: [f64; 3], hi: [f64; 3]) {
598 for iz in 0..self.nz {
599 for iy in 0..self.ny {
600 for ix in 0..self.nx {
601 let p = self.node_pos(ix, iy, iz);
602 let dx = (lo[0] - p[0]).max(p[0] - hi[0]).max(0.0);
603 let dy = (lo[1] - p[1]).max(p[1] - hi[1]).max(0.0);
604 let dz = (lo[2] - p[2]).max(p[2] - hi[2]).max(0.0);
605 let outside = (dx * dx + dy * dy + dz * dz).sqrt();
606 let inside = (p[0] - lo[0])
607 .min(hi[0] - p[0])
608 .min(p[1] - lo[1])
609 .min(hi[1] - p[1])
610 .min(p[2] - lo[2])
611 .min(hi[2] - p[2]);
612 let sdf = if inside < 0.0 { outside } else { -inside };
613 self.set(ix, iy, iz, sdf);
614 }
615 }
616 }
617 }
618 pub fn count_inside(&self) -> usize {
620 self.data.iter().filter(|&&v| v <= 0.0).count()
621 }
622 pub fn min_value(&self) -> f64 {
624 self.data.iter().cloned().fold(f64::MAX, f64::min)
625 }
626 pub fn max_value(&self) -> f64 {
628 self.data.iter().cloned().fold(f64::MIN, f64::max)
629 }
630}
631pub struct LevelSetReinit {
636 pub tol: f64,
638 pub max_iter: usize,
640}
641impl LevelSetReinit {
642 pub fn new(tol: f64, max_iter: usize) -> Self {
648 Self { tol, max_iter }
649 }
650 pub fn reinitialize(&self, field: &mut LevelSetField) {
658 let dx = field.dx;
659 let dt = 0.5 * dx;
660 let nx = field.nx;
661 let ny = field.ny;
662 let nz = field.nz;
663 let phi0: Vec<f64> = field.data.clone();
664 let sign0: Vec<f64> = phi0
665 .iter()
666 .map(|&v| {
667 if v > 0.0 {
668 1.0
669 } else if v < 0.0 {
670 -1.0
671 } else {
672 0.0
673 }
674 })
675 .collect();
676 for _iter in 0..self.max_iter {
677 let mut new_data = field.data.clone();
678 let mut max_change = 0.0_f64;
679 for iz in 0..nz {
680 for iy in 0..ny {
681 for ix in 0..nx {
682 let idx = field.idx(ix, iy, iz);
683 let s = sign0[idx];
684 if s == 0.0 {
685 continue;
686 }
687 let phi_c = field.data[idx];
688 let grad_mag = godunov_grad_mag(field, ix, iy, iz, s);
689 let update = s * (1.0 - grad_mag);
690 new_data[idx] = phi_c + dt * update;
691 max_change = max_change.max((dt * update).abs());
692 }
693 }
694 }
695 field.data = new_data;
696 if max_change < self.tol {
697 break;
698 }
699 }
700 }
701 pub fn fast_sweep(&self, field: &mut LevelSetField, n_sweeps: usize) {
710 let dx = field.dx;
711 let nx = field.nx;
712 let ny = field.ny;
713 let nz = field.nz;
714 for sweep in 0..n_sweeps {
715 let ix_range: Vec<usize> = if sweep % 2 == 0 {
716 (0..nx).collect()
717 } else {
718 (0..nx).rev().collect()
719 };
720 let iy_range: Vec<usize> = if (sweep / 2) % 2 == 0 {
721 (0..ny).collect()
722 } else {
723 (0..ny).rev().collect()
724 };
725 let iz_range: Vec<usize> = if (sweep / 4) % 2 == 0 {
726 (0..nz).collect()
727 } else {
728 (0..nz).rev().collect()
729 };
730 for &iz in &iz_range {
731 for &iy in &iy_range {
732 for &ix in &ix_range {
733 let phi_c = field.get(ix, iy, iz);
734 let axm = if ix > 0 {
735 field.get(ix - 1, iy, iz)
736 } else {
737 phi_c
738 };
739 let axp = if ix + 1 < nx {
740 field.get(ix + 1, iy, iz)
741 } else {
742 phi_c
743 };
744 let aym = if iy > 0 {
745 field.get(ix, iy - 1, iz)
746 } else {
747 phi_c
748 };
749 let ayp = if iy + 1 < ny {
750 field.get(ix, iy + 1, iz)
751 } else {
752 phi_c
753 };
754 let azm = if iz > 0 {
755 field.get(ix, iy, iz - 1)
756 } else {
757 phi_c
758 };
759 let azp = if iz + 1 < nz {
760 field.get(ix, iy, iz + 1)
761 } else {
762 phi_c
763 };
764 let ax = if phi_c >= 0.0 {
765 axm.min(axp)
766 } else {
767 axm.max(axp)
768 };
769 let ay = if phi_c >= 0.0 {
770 aym.min(ayp)
771 } else {
772 aym.max(ayp)
773 };
774 let az = if phi_c >= 0.0 {
775 azm.min(azp)
776 } else {
777 azm.max(azp)
778 };
779 let new_val = if phi_c >= 0.0 {
780 (ax.abs().min(ay.abs()).min(az.abs()) + dx).min(phi_c.abs())
781 } else {
782 let d = (ax.abs().min(ay.abs()).min(az.abs()) + dx).min(phi_c.abs());
783 -d
784 };
785 let _ = ax;
786 let _ = ay;
787 let _ = az;
788 let _ = new_val;
789 let candidate = if phi_c >= 0.0 {
790 axm.max(0.0).min(axp.max(0.0)).min(phi_c).max(0.0) + dx
791 } else {
792 (axm.min(0.0).max(axp.min(0.0)).max(phi_c).min(0.0)) - dx
793 };
794 if (candidate.abs() < phi_c.abs()) && (candidate * phi_c >= 0.0) {
795 field.set(ix, iy, iz, candidate);
796 }
797 }
798 }
799 }
800 }
801 }
802}
803#[derive(Debug, Clone)]
805pub struct McTriangle {
806 pub vertices: [[f64; 3]; 3],
808}
809pub struct IsosurfaceExtraction {
814 pub isovalue: f64,
816}
817impl IsosurfaceExtraction {
818 pub fn new(isovalue: f64) -> Self {
823 Self { isovalue }
824 }
825 pub fn extract(&self, field: &LevelSetField) -> Vec<McTriangle> {
830 let mut triangles = Vec::new();
831 let nx = field.nx;
832 let ny = field.ny;
833 let nz = field.nz;
834 if nx < 2 || ny < 2 || nz < 2 {
835 return triangles;
836 }
837 for iz in 0..nz - 1 {
838 for iy in 0..ny - 1 {
839 for ix in 0..nx - 1 {
840 self.process_cell(field, ix, iy, iz, &mut triangles);
841 }
842 }
843 }
844 triangles
845 }
846 fn process_cell(
848 &self,
849 field: &LevelSetField,
850 ix: usize,
851 iy: usize,
852 iz: usize,
853 triangles: &mut Vec<McTriangle>,
854 ) {
855 let v: [f64; 8] = [
856 field.get(ix, iy, iz),
857 field.get(ix + 1, iy, iz),
858 field.get(ix + 1, iy + 1, iz),
859 field.get(ix, iy + 1, iz),
860 field.get(ix, iy, iz + 1),
861 field.get(ix + 1, iy, iz + 1),
862 field.get(ix + 1, iy + 1, iz + 1),
863 field.get(ix, iy + 1, iz + 1),
864 ];
865 let p: [[f64; 3]; 8] = [
866 field.node_pos(ix, iy, iz),
867 field.node_pos(ix + 1, iy, iz),
868 field.node_pos(ix + 1, iy + 1, iz),
869 field.node_pos(ix, iy + 1, iz),
870 field.node_pos(ix, iy, iz + 1),
871 field.node_pos(ix + 1, iy, iz + 1),
872 field.node_pos(ix + 1, iy + 1, iz + 1),
873 field.node_pos(ix, iy + 1, iz + 1),
874 ];
875 let mut cube_idx = 0u8;
876 for (i, &vi) in v.iter().enumerate() {
877 if vi < self.isovalue {
878 cube_idx |= 1 << i;
879 }
880 }
881 if cube_idx == 0 || cube_idx == 255 {
882 return;
883 }
884 let edge_flags = MC_EDGE_TABLE[cube_idx as usize];
885 let mut edge_verts = [[0.0f64; 3]; 12];
886 for e in 0..12 {
887 if edge_flags & (1 << e) != 0 {
888 let (a, b) = MC_EDGE_CORNERS[e];
889 edge_verts[e] = interp_vertex(p[a], p[b], v[a], v[b], self.isovalue);
890 }
891 }
892 let tris = &MC_TRI_TABLE[cube_idx as usize];
893 let mut i = 0;
894 while i < tris.len() && tris[i] != -1 {
895 let tri = McTriangle {
896 vertices: [
897 edge_verts[tris[i] as usize],
898 edge_verts[tris[i + 1] as usize],
899 edge_verts[tris[i + 2] as usize],
900 ],
901 };
902 triangles.push(tri);
903 i += 3;
904 }
905 }
906 pub fn count_triangles(&self, field: &LevelSetField) -> usize {
908 self.extract(field).len()
909 }
910}