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
use alga::general::RealField;
use na;
use num_traits::Float;
use {BoundingBox, Object};
#[derive(Clone, Debug, PartialEq)]
pub struct Cylinder<S: RealField> {
radius: S,
bbox: BoundingBox<S>,
}
impl<S: RealField + Float> Cylinder<S> {
pub fn new(r: S) -> Self {
Cylinder {
radius: r,
bbox: BoundingBox::new(
&na::Point3::new(-r, -r, S::neg_infinity()),
&na::Point3::new(r, r, S::infinity()),
),
}
}
}
impl<S: ::std::fmt::Debug + RealField + From<f32> + Float> Object<S> for Cylinder<S> {
fn approx_value(&self, p: &na::Point3<S>, slack: S) -> S {
let approx = self.bbox.distance(p);
if approx <= slack {
let zero: S = From::from(0f32);
let pv = na::Vector3::new(p.x, p.y, zero);
pv.norm() - self.radius
} else {
approx
}
}
fn bbox(&self) -> &BoundingBox<S> {
&self.bbox
}
fn normal(&self, p: &na::Point3<S>) -> na::Vector3<S> {
let zero: S = From::from(0f32);
let pv = na::Vector3::new(p.x, p.y, zero);
pv.normalize()
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct Cone<S: RealField> {
slope: S,
distance_multiplier: S,
offset: S,
normal_multiplier: S,
bbox: BoundingBox<S>,
}
impl<S: RealField + Float + From<f32>> Cone<S> {
pub fn new(slope: S, offset: S) -> Self {
let one: S = From::from(1f32);
Cone {
slope,
distance_multiplier: one / Float::sqrt(slope * slope + one),
offset,
normal_multiplier: slope / Float::sqrt(slope * slope + one),
bbox: BoundingBox::infinity(),
}
}
}
impl<S: ::std::fmt::Debug + RealField + From<f32> + Float> Object<S> for Cone<S> {
fn bbox(&self) -> &BoundingBox<S> {
&self.bbox
}
fn set_bbox(&mut self, bbox: &BoundingBox<S>) {
self.bbox = bbox.clone();
}
fn approx_value(&self, p: &na::Point3<S>, _: S) -> S {
let radius = Float::abs(self.slope * (p.z + self.offset));
let zero: S = From::from(0f32);
let pv = na::Vector3::new(p.x, p.y, zero);
(pv.norm() - radius) * self.distance_multiplier
}
fn normal(&self, p: &na::Point3<S>) -> na::Vector3<S> {
let s = Float::signum(p.z + self.offset);
let zero: S = From::from(0f32);
let mut pv = na::Vector3::new(p.x, p.y, zero);
pv.normalize_mut();
pv *= self.distance_multiplier;
pv.z = -s * self.normal_multiplier;
pv
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn cylinder() {
let cyl = Cylinder::new(1.0);
assert_ulps_eq!(cyl.approx_value(&na::Point3::new(0., 0., 0.), 0.), -1.);
assert_ulps_eq!(cyl.approx_value(&na::Point3::new(1., 0., 0.), 0.), 0.);
assert_ulps_eq!(cyl.approx_value(&na::Point3::new(0., 1., 0.), 0.), 0.);
assert_ulps_eq!(cyl.approx_value(&na::Point3::new(0., 10., 0.), 0.), 9.);
assert_ulps_eq!(cyl.approx_value(&na::Point3::new(0., 10., 1000.), 0.), 9.);
}
#[test]
fn cone() {
let c = Cone::new(2., 10.);
assert_ulps_eq!(c.approx_value(&na::Point3::new(0., 0., -10.), 0.), 0.);
assert_ulps_eq!(c.approx_value(&na::Point3::new(2., 0., -11.), 0.), 0.);
}
}