1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
//! Triply‑Periodic Minimal Surfaces rewritten to leverage the generic
//! signed‑distance mesher in `sdf.rs`.
use crate::float_types::Real;
use crate::mesh::Mesh;
use crate::traits::CSG;
use nalgebra::Point3;
use std::fmt::Debug;
impl<S: Clone + Debug + Send + Sync> Mesh<S> {
/// **Generic helper** – build a TPMS inside `self` from the provided SDF.
///
/// * `sdf_fn` – smooth signed‑distance field _f(p)_; 0‑level set is the surface
/// * `resolution` – voxel grid sampling resolution `(nx, ny, nz)`
/// * `iso_value` – iso‑contour value (normally 0.0)
///
/// The result is intersected against `self`, so the surface only appears inside
/// the original solid's bounding box / volume.
#[inline]
fn tpms_from_sdf<F>(
&self,
sdf_fn: F,
resolution: (usize, usize, usize),
iso_value: Real,
metadata: Option<S>,
) -> Mesh<S>
where
F: Fn(&Point3<Real>) -> Real + Send + Sync,
{
let aabb = self.bounding_box();
let min_pt = aabb.mins;
let max_pt = aabb.maxs;
// Mesh the implicit surface with the generic surface‑nets backend
let surf = Mesh::sdf(sdf_fn, resolution, min_pt, max_pt, iso_value, metadata);
// Clip the infinite TPMS down to the original shape's volume
surf.intersection(self)
}
// ------------ Specific minimal‑surface flavours --------------------
/// Gyroid surface: `sin x cos y + sin y cos z + sin z cos x = iso`
/// (`period` rescales the spatial frequency; larger => slower repeat)
/// **Mathematical Foundation**: Gyroid is a triply periodic minimal surface with zero mean curvature.
/// **Optimization**: Pre-compute trigonometric values for better performance.
pub fn gyroid(
&self,
resolution: usize,
period: Real,
iso_value: Real,
metadata: Option<S>,
) -> Mesh<S> {
let res = (resolution.max(2), resolution.max(2), resolution.max(2));
let period_inv = 1.0 / period;
self.tpms_from_sdf(
move |p: &Point3<Real>| {
// Pre-compute scaled coordinates for efficiency
let x_scaled = p.x * period_inv;
let y_scaled = p.y * period_inv;
let z_scaled = p.z * period_inv;
// Pre-compute trigonometric values to avoid redundant calculations
let (sin_x, cos_x) = x_scaled.sin_cos();
let (sin_y, cos_y) = y_scaled.sin_cos();
let (sin_z, cos_z) = z_scaled.sin_cos();
// **Mathematical Formula**: Gyroid surface equation
// G(x,y,z) = sin(x)cos(y) + sin(y)cos(z) + sin(z)cos(x)
(sin_x * cos_y) + (sin_y * cos_z) + (sin_z * cos_x)
},
res,
iso_value,
metadata,
)
}
/// Schwarz‑P surface: `cos x + cos y + cos z = iso` (default iso = 0)
/// **Mathematical Foundation**: Schwarz P-surface has constant mean curvature and cubic symmetry.
/// **Optimization**: Use direct cosine computation for this simpler surface equation.
pub fn schwarz_p(
&self,
resolution: usize,
period: Real,
iso_value: Real,
metadata: Option<S>,
) -> Mesh<S> {
let res = (resolution.max(2), resolution.max(2), resolution.max(2));
let period_inv = 1.0 / period;
self.tpms_from_sdf(
move |p: &Point3<Real>| {
// Pre-compute scaled coordinates
let x_scaled = p.x * period_inv;
let y_scaled = p.y * period_inv;
let z_scaled = p.z * period_inv;
// **Mathematical Formula**: Schwarz P-surface equation
// P(x,y,z) = cos(x) + cos(y) + cos(z)
x_scaled.cos() + y_scaled.cos() + z_scaled.cos()
},
res,
iso_value,
metadata,
)
}
/// Schwarz‑D (Diamond) surface: `sin x sin y sin z + sin x cos y cos z + ... = iso`
/// **Mathematical Foundation**: Diamond surface exhibits tetrahedral symmetry and is self-intersecting.
/// **Optimization**: Pre-compute all trigonometric values for maximum efficiency.
pub fn schwarz_d(
&self,
resolution: usize,
period: Real,
iso_value: Real,
metadata: Option<S>,
) -> Mesh<S> {
let res = (resolution.max(2), resolution.max(2), resolution.max(2));
let period_inv = 1.0 / period;
self.tpms_from_sdf(
move |p: &Point3<Real>| {
// Pre-compute scaled coordinates
let x_scaled = p.x * period_inv;
let y_scaled = p.y * period_inv;
let z_scaled = p.z * period_inv;
// Pre-compute all trigonometric values once
let (sin_x, cos_x) = x_scaled.sin_cos();
let (sin_y, cos_y) = y_scaled.sin_cos();
let (sin_z, cos_z) = z_scaled.sin_cos();
// **Mathematical Formula**: Schwarz Diamond surface equation
// D(x,y,z) = sin(x)sin(y)sin(z) + sin(x)cos(y)cos(z) + cos(x)sin(y)cos(z) + cos(x)cos(y)sin(z)
(sin_x * sin_y * sin_z)
+ (sin_x * cos_y * cos_z)
+ (cos_x * sin_y * cos_z)
+ (cos_x * cos_y * sin_z)
},
res,
iso_value,
metadata,
)
}
}