Files
rustytorch/demos/rtx-digital-twin-demo/src/presets.rs
T
osobhandClaude Opus 4.6 02d382d5f6 style: apply rustfmt across all crates and demos
Consistent formatting pass: line wrapping, import sorting, trailing
whitespace removal, let-chain indentation, merged derive attributes,
and unsafe block reformatting.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
2026-04-12 07:01:58 -07:00

214 lines
6.9 KiB
Rust

//! Preset geometries for Digital Twin demo.
use rtx_digital_twin::{OrganGeometry, TissueLabel, TissueType};
use rtx_digital_twin_shared::{DigitalTwinDemoError, DigitalTwinDemoResult};
/// Preset geometry generator.
pub struct GeometryPresets;
impl GeometryPresets {
/// Create geometry from preset name.
pub fn create(
name: &str,
resolution: [usize; 3],
spacing: [f32; 3],
) -> DigitalTwinDemoResult<OrganGeometry> {
match name.to_lowercase().as_str() {
"liver_tumor" => Self::liver_with_tumor(resolution, spacing),
"kidney" => Self::kidney(resolution, spacing),
"brain" => Self::brain(resolution, spacing),
"simple_sphere" => Self::simple_sphere(resolution, spacing),
_ => Err(DigitalTwinDemoError::InvalidConfig(format!(
"Unknown preset: {name}"
))),
}
}
/// List available preset names.
#[must_use]
pub fn available() -> Vec<&'static str> {
vec!["liver_tumor", "kidney", "brain", "simple_sphere"]
}
/// Create liver with embedded tumor.
fn liver_with_tumor(
resolution: [usize; 3],
spacing: [f32; 3],
) -> DigitalTwinDemoResult<OrganGeometry> {
let [nx, ny, nz] = resolution;
let mut geometry = OrganGeometry::new(resolution, spacing);
// Create ellipsoidal liver
let center = [nx as f32 / 2.0, ny as f32 / 2.0, nz as f32 / 2.0];
let radii = [nx as f32 * 0.4, ny as f32 * 0.3, nz as f32 * 0.35];
for z in 0..nz {
for y in 0..ny {
for x in 0..nx {
let dx = (x as f32 - center[0]) / radii[0];
let dy = (y as f32 - center[1]) / radii[1];
let dz = (z as f32 - center[2]) / radii[2];
if dx * dx + dy * dy + dz * dz <= 1.0 {
geometry.set_label(x, y, z, TissueLabel::from(TissueType::Liver));
}
}
}
}
// Add tumor
let tumor_center = [center[0] + radii[0] * 0.2, center[1], center[2]];
let tumor_radius = nx as f32 * 0.1;
geometry.create_sphere(
[
tumor_center[0] * spacing[0],
tumor_center[1] * spacing[1],
tumor_center[2] * spacing[2],
],
tumor_radius * spacing[0],
TissueLabel::from(TissueType::Tumor),
);
Ok(geometry)
}
/// Create kidney geometry.
fn kidney(resolution: [usize; 3], spacing: [f32; 3]) -> DigitalTwinDemoResult<OrganGeometry> {
let [nx, ny, nz] = resolution;
let mut geometry = OrganGeometry::new(resolution, spacing);
// Bean-shaped kidney approximation
let center = [nx as f32 / 2.0, ny as f32 / 2.0, nz as f32 / 2.0];
for z in 0..nz {
for y in 0..ny {
for x in 0..nx {
let dx = (x as f32 - center[0]) / (nx as f32 * 0.25);
let dy = (y as f32 - center[1]) / (ny as f32 * 0.35);
let dz = (z as f32 - center[2]) / (nz as f32 * 0.2);
// Outer ellipsoid
let dist = dx * dx + dy * dy + dz * dz;
// Create indentation on one side
let indent = if dx > 0.0 {
0.3 * (-dy * dy * 4.0).exp()
} else {
0.0
};
if dist <= 1.0 + indent {
geometry.set_label(x, y, z, TissueLabel::from(TissueType::Kidney));
}
}
}
}
Ok(geometry)
}
/// Create brain geometry.
fn brain(resolution: [usize; 3], spacing: [f32; 3]) -> DigitalTwinDemoResult<OrganGeometry> {
let [nx, ny, nz] = resolution;
let mut geometry = OrganGeometry::new(resolution, spacing);
// Simplified brain as two hemispheres
let center = [nx as f32 / 2.0, ny as f32 / 2.0, nz as f32 / 2.0];
for z in 0..nz {
for y in 0..ny {
for x in 0..nx {
let dx = (x as f32 - center[0]) / (nx as f32 * 0.35);
let dy = (y as f32 - center[1]) / (ny as f32 * 0.4);
let dz = (z as f32 - center[2]) / (nz as f32 * 0.3);
// Main brain shape
let dist = dx * dx + dy * dy + dz * dz;
// Create central fissure
let x_f = x as f32;
let fissure = if x_f > center[0] - 2.0 && x_f < center[0] + 2.0 {
0.1
} else {
0.0
};
if dist <= 1.0 - fissure {
geometry.set_label(x, y, z, TissueLabel::from(TissueType::BrainGrayMatter));
}
}
}
}
Ok(geometry)
}
/// Create simple sphere for testing.
fn simple_sphere(
resolution: [usize; 3],
spacing: [f32; 3],
) -> DigitalTwinDemoResult<OrganGeometry> {
let [nx, ny, nz] = resolution;
let mut geometry = OrganGeometry::new(resolution, spacing);
let center = [
nx as f32 / 2.0 * spacing[0],
ny as f32 / 2.0 * spacing[1],
nz as f32 / 2.0 * spacing[2],
];
let radius = nx.min(ny).min(nz) as f32 / 3.0 * spacing[0];
geometry.create_sphere(center, radius, TissueLabel::from(TissueType::Muscle));
Ok(geometry)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_available_presets() {
let presets = GeometryPresets::available();
assert!(presets.contains(&"liver_tumor"));
assert!(presets.contains(&"kidney"));
}
#[test]
fn test_create_liver_tumor() {
let geometry =
GeometryPresets::create("liver_tumor", [32, 32, 32], [1.0, 1.0, 1.0]).unwrap();
assert_eq!(geometry.shape(), [32, 32, 32]);
// Should have liver and tumor tissue
let histogram = geometry.tissue_histogram();
assert!(histogram.get(&TissueType::Liver).unwrap_or(&0) > &0);
assert!(histogram.get(&TissueType::Tumor).unwrap_or(&0) > &0);
}
#[test]
fn test_create_kidney() {
let geometry = GeometryPresets::create("kidney", [32, 32, 32], [1.0, 1.0, 1.0]).unwrap();
let histogram = geometry.tissue_histogram();
assert!(histogram.get(&TissueType::Kidney).unwrap_or(&0) > &0);
}
#[test]
fn test_create_brain() {
let geometry = GeometryPresets::create("brain", [32, 32, 32], [1.0, 1.0, 1.0]).unwrap();
let histogram = geometry.tissue_histogram();
assert!(histogram.get(&TissueType::BrainGrayMatter).unwrap_or(&0) > &0);
}
#[test]
fn test_unknown_preset() {
let result = GeometryPresets::create("unknown", [32, 32, 32], [1.0, 1.0, 1.0]);
assert!(result.is_err());
}
}