1use crate::{BoundingBox, Object, RealField};
2use nalgebra as na;
3use num_traits::Float;
4
5#[derive(Clone, Debug, PartialEq)]
7pub struct Cylinder<S: RealField> {
8 radius: S,
9 bbox: BoundingBox<S>,
10}
11
12impl<S: RealField + Float> Cylinder<S> {
13 pub fn new(r: S) -> Self {
15 Cylinder {
16 radius: r,
17 bbox: BoundingBox::new(
18 &na::Point3::new(-r, -r, S::neg_infinity()),
19 &na::Point3::new(r, r, S::infinity()),
20 ),
21 }
22 }
23}
24
25impl<S: std::fmt::Debug + RealField + From<f32> + Float> Object<S> for Cylinder<S> {
26 fn approx_value(&self, p: &na::Point3<S>, slack: S) -> S {
27 let approx = self.bbox.distance(p);
28 if approx <= slack {
29 let zero: S = From::from(0f32);
30 let pv = na::Vector3::new(p.x, p.y, zero);
31 pv.norm() - self.radius
32 } else {
33 approx
34 }
35 }
36 fn bbox(&self) -> &BoundingBox<S> {
37 &self.bbox
38 }
39 fn normal(&self, p: &na::Point3<S>) -> na::Vector3<S> {
40 let zero: S = From::from(0f32);
41 let pv = na::Vector3::new(p.x, p.y, zero);
42 pv.normalize()
43 }
44}
45
46#[derive(Clone, Debug, PartialEq)]
48pub struct Cone<S: RealField> {
49 slope: S,
50 distance_multiplier: S,
51 offset: S, normal_multiplier: S, bbox: BoundingBox<S>,
54}
55
56impl<S: RealField + Float + From<f32>> Cone<S> {
57 pub fn new(slope: S, offset: S) -> Self {
59 let one: S = From::from(1f32);
60 Cone {
61 slope,
62 distance_multiplier: one / Float::sqrt(slope * slope + one), offset,
64 normal_multiplier: slope / Float::sqrt(slope * slope + one), bbox: BoundingBox::infinity(),
66 }
67 }
68}
69
70impl<S: std::fmt::Debug + RealField + From<f32> + Float> Object<S> for Cone<S> {
71 fn bbox(&self) -> &BoundingBox<S> {
72 &self.bbox
73 }
74 fn set_bbox(&mut self, bbox: &BoundingBox<S>) {
75 self.bbox = bbox.clone();
76 }
77 fn approx_value(&self, p: &na::Point3<S>, _: S) -> S {
78 let radius = Float::abs(self.slope * (p.z + self.offset));
79 let zero: S = From::from(0f32);
80 let pv = na::Vector3::new(p.x, p.y, zero);
81 (pv.norm() - radius) * self.distance_multiplier
82 }
83 fn normal(&self, p: &na::Point3<S>) -> na::Vector3<S> {
84 let s = Float::signum(p.z + self.offset);
85 let zero: S = From::from(0f32);
86 let mut pv = na::Vector3::new(p.x, p.y, zero);
87 pv.normalize_mut();
88 pv *= self.distance_multiplier;
89 pv.z = -s * self.normal_multiplier;
90 pv
91 }
92}
93
94#[cfg(test)]
95mod test {
96 use approx::assert_ulps_eq;
97 use crate::*;
98 use nalgebra as na;
99
100 #[test]
101 fn cylinder() {
102 let cyl = Cylinder::new(1.0);
103 assert_ulps_eq!(cyl.approx_value(&na::Point3::new(0., 0., 0.), 0.), -1.);
104 assert_ulps_eq!(cyl.approx_value(&na::Point3::new(1., 0., 0.), 0.), 0.);
105 assert_ulps_eq!(cyl.approx_value(&na::Point3::new(0., 1., 0.), 0.), 0.);
106 assert_ulps_eq!(cyl.approx_value(&na::Point3::new(0., 10., 0.), 0.), 9.);
107 assert_ulps_eq!(cyl.approx_value(&na::Point3::new(0., 10., 1000.), 0.), 9.);
108 }
109
110 #[test]
111 fn cone() {
112 let c = Cone::new(2., 10.);
113 assert_ulps_eq!(c.approx_value(&na::Point3::new(0., 0., -10.), 0.), 0.);
114 assert_ulps_eq!(c.approx_value(&na::Point3::new(2., 0., -11.), 0.), 0.);
115 }
116}