implement a Spiral region

this isn't 100% what i need for my buffer, but i should be able to
create some morph that wraps this cylinder-like spiral into a torus
spiral.
This commit is contained in:
2021-12-24 13:30:02 -08:00
parent 1f6aaf91f5
commit 44624f4e39

View File

@@ -157,6 +157,36 @@ impl Region for Cube {
}
}
/// a Spiral traces out a circle on the xy plane as z increases.
#[derive(Copy, Clone, Serialize, Deserialize)]
pub struct Spiral {
/// radius of the spiral
major: f32,
/// effective "width" of the spiral.
/// any point within this distance from the 1-dimensional spiral is considered to be in the
/// region.
minor: f32,
/// determines how stretched the spiral is in z-space.
/// the xy plane at z=0 looks identical again at t=period.
period: f32,
}
impl Spiral {
pub fn new(major: f32, minor: f32, period: f32) -> Self {
Self { major, minor, period }
}
}
#[typetag::serde]
impl Region for Spiral {
fn contains(&self, p: Meters) -> bool {
let revs = p.z() / self.period;
let expected_angle = (revs % 1.0) * std::f32::consts::PI * 2.0;
let expected = Meters::new(self.major * expected_angle.cos(), self.major * expected_angle.sin(), p.z());
p.distance_sq(*expected) < self.minor * self.minor
}
}
#[cfg(test)]
mod test {
use super::*;
@@ -286,6 +316,62 @@ mod test {
assert!(tor.contains(Meters::new(1.0, 2.0, 12.0)));
assert!(!tor.contains(Meters::new(1.0, 2.0, 13.0)));
}
#[test]
fn test_spiral_doesnt_contain_zero() {
let spiral = Spiral::new(10.0, 1.0, 4.0);
assert!(!spiral.contains(Meters::new(0.0, 0.0, 0.0)));
assert!(!spiral.contains(Meters::new(0.0, 0.0, 1.0)));
assert!(!spiral.contains(Meters::new(0.0, 0.0, 2.0)));
assert!(!spiral.contains(Meters::new(0.0, 0.0, 3.0)));
assert!(!spiral.contains(Meters::new(0.0, 0.0, 4.0)));
assert!(!spiral.contains(Meters::new(0.0, 0.0, 5.0)));
assert!(!spiral.contains(Meters::new(0.0, 0.0, 6.0)));
assert!(!spiral.contains(Meters::new(0.0, 0.0, 7.0)));
assert!(!spiral.contains(Meters::new(0.0, 0.0, 8.0)));
assert!(!spiral.contains(Meters::new(0.0, 0.0, 9.0)));
assert!(!spiral.contains(Meters::new(0.0, 0.0, 10.0)));
assert!(!spiral.contains(Meters::new(0.0, 0.0, 11.0)));
}
#[test]
fn test_spiral_exactly_on_course() {
let spiral = Spiral::new(10.0, 1.0, 4.0);
assert!(spiral.contains(Meters::new(10.0, 0.0, 0.0)));
assert!(spiral.contains(Meters::new(0.0, 10.0, 1.0)));
assert!(spiral.contains(Meters::new(-10.0, 0.0, 2.0)));
assert!(spiral.contains(Meters::new(0.0, -10.0, 3.0)));
assert!(spiral.contains(Meters::new(10.0, 0.0, 4.0)));
assert!(spiral.contains(Meters::new(0.0, 10.0, 5.0)));
}
#[test]
fn test_spiral_exactly_on_course_negative() {
let spiral = Spiral::new(10.0, 1.0, 4.0);
assert!(spiral.contains(Meters::new(0.0, -10.0, -1.0)));
assert!(spiral.contains(Meters::new(-10.0, 0.0, -2.0)));
assert!(spiral.contains(Meters::new(0.0, 10.0, -3.0)));
assert!(spiral.contains(Meters::new(10.0, 0.0, -4.0)));
assert!(spiral.contains(Meters::new(0.0, -10.0, -5.0)));
}
#[test]
fn test_spiral_within_minor_radius() {
let spiral = Spiral::new(10.0, 1.0, 4.0);
assert!(spiral.contains(Meters::new(10.5, 0.0, 0.0)));
assert!(spiral.contains(Meters::new(10.5, -0.5, 0.0)));
assert!(spiral.contains(Meters::new(9.1, 0.0, 0.0)));
assert!(!spiral.contains(Meters::new(8.9, 0.0, 0.0)));
assert!(!spiral.contains(Meters::new(9.1, 0.9, 0.0)));
assert!(spiral.contains(Meters::new(0.5, 10.5, 1.0)));
assert!(spiral.contains(Meters::new(-0.9, 10.0, 1.0)));
assert!(!spiral.contains(Meters::new(-0.9, 10.9, 1.0)));
assert!(spiral.contains(Meters::new(-10.9, 0.0, 2.0)));
assert!(spiral.contains(Meters::new(-10.0, 0.6, 2.0)));
assert!(!spiral.contains(Meters::new(-10.8, 0.8, 2.0)));
}
}