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