Bspline
use cadrum::{DQuat, DVec3, Solid}; use std::f64::consts::TAU; // 2 field-period stellarator-like torus. // `Solid::bspline` is fed a 2D control-point grid to build a periodic B-spline solid. // Every variation below is invariant under phi → phi+π (or shifts by a multiple // of 2π), so the resulting shape has 180° rotational symmetry around the Z axis: // a(phi) = 1.8 + 0.6 * sin(2φ) radial semi-axis // b(phi) = 1.0 + 0.4 * cos(2φ) Z semi-axis // psi(phi) = 2 * phi cross-section twist (2 turns per loop) // z_shift(phi) = 1.0 * sin(2φ) vertical undulation const M: usize = 48; // toroidal (U) — must be even for 180° symmetry const N: usize = 24; // poloidal (V) — arbitrary const RING_R: f64 = 6.0; fn point(i: usize, j: usize) -> DVec3 { let phi = TAU * (i as f64) / (M as f64); let theta = TAU * (j as f64) / (N as f64); let two_phi = 2.0 * phi; let a = 1.8 + 0.6 * two_phi.sin(); let b = 1.0 + 0.4 * two_phi.cos(); let psi = two_phi; // twist: 2 full turns per toroidal loop let z_shift = 1.0 * two_phi.sin(); // 1. Local cross-section (pre-twist ellipse in the (X, Z) plane) let local_raw = DVec3::X * (a * theta.cos()) + DVec3::Z * (b * theta.sin()); // 2. Rotate by psi around the local Y axis (major-circle tangent) — the twist let local_twisted = DQuat::from_axis_angle(DVec3::Y, psi) * local_raw; // 3. Undulate vertically in the local frame let local_shifted = local_twisted + DVec3::Z * z_shift; // 4. Push outward along the major radius by RING_R let translated = local_shifted + DVec3::X * RING_R; // 5. Rotate the whole point around the global Z axis by phi DQuat::from_axis_angle(DVec3::Z, phi) * translated } fn main() -> Result<(), cadrum::Error> { let example_name = std::path::Path::new(file!()).file_stem().unwrap().to_str().unwrap(); let plasma = Solid::bspline(M, N, true, point).expect("2-period bspline torus should succeed"); let objects = [plasma.color("cyan")]; Solid::write_step(&objects, &mut std::fs::File::create(format!("{example_name}.step")).unwrap())?; let mesh = Solid::mesh(&objects, Default::default())?; let scene = mesh.scene(cadrum::SceneOption { view: DVec3::new(0.05, 0.05, 1.0), up: DVec3::Y, hidden_edges: false, shading: true }); scene.write_svg(&mut std::fs::File::create(format!("{example_name}.svg")).unwrap())?; scene.write_png([640, 640], &mut std::fs::File::create(format!("{example_name}.png")).unwrap())?; mesh.write_stl(&mut std::fs::File::create(format!("{example_name}.stl")).unwrap())?; mesh.write_gltf_binary(&mut std::fs::File::create(format!("{example_name}.glb")).unwrap())?; println!("wrote {example_name}.step / {example_name}.svg / {example_name}.png"); Ok(()) }
Output: 09_bspline.png | 09_bspline.step | 09_bspline.glb | 09_bspline.stl | 09_bspline.svg