1use crate::{BoundingBox, Object, RealField};
2use num_traits::Float;
3
4pub trait Axis: ::std::fmt::Debug + Clone + ::std::marker::Sync + ::std::marker::Send {
5 fn value() -> usize;
6 fn inverted() -> bool;
7}
8
9#[derive(Clone, Debug)]
10pub struct AxisX {}
11impl Axis for AxisX {
12 fn value() -> usize {
13 0
14 }
15 fn inverted() -> bool {
16 false
17 }
18}
19
20#[derive(Clone, Debug)]
21pub struct AxisNegX {}
22impl Axis for AxisNegX {
23 fn value() -> usize {
24 0
25 }
26 fn inverted() -> bool {
27 true
28 }
29}
30
31#[derive(Clone, Debug)]
32pub struct AxisY {}
33impl Axis for AxisY {
34 fn value() -> usize {
35 1
36 }
37 fn inverted() -> bool {
38 false
39 }
40}
41
42#[derive(Clone, Debug)]
43pub struct AxisNegY {}
44impl Axis for AxisNegY {
45 fn value() -> usize {
46 1
47 }
48 fn inverted() -> bool {
49 true
50 }
51}
52
53#[derive(Clone, Debug)]
54pub struct AxisZ {}
55impl Axis for AxisZ {
56 fn value() -> usize {
57 2
58 }
59 fn inverted() -> bool {
60 false
61 }
62}
63
64#[derive(Clone, Debug)]
65pub struct AxisNegZ {}
66impl Axis for AxisNegZ {
67 fn value() -> usize {
68 2
69 }
70 fn inverted() -> bool {
71 true
72 }
73}
74
75#[derive(Clone, Debug, PartialEq)]
76pub struct Plane<A: Axis, S: RealField> {
77 distance_from_zero: S,
78 bbox: BoundingBox<S>,
79 normal: na::Vector3<S>,
80 _phantom: ::std::marker::PhantomData<A>,
81}
82
83impl<A: Axis, S: From<f32> + RealField + Float> Plane<A, S> {
84 pub fn new(distance_from_zero: S) -> Self {
85 let d = distance_from_zero;
86 let mut p_neg = na::Point3::new(S::neg_infinity(), S::neg_infinity(), S::neg_infinity());
87 let mut p_pos = na::Point3::new(S::infinity(), S::infinity(), S::infinity());
88 let zero: S = From::from(0f32);
89 let mut normal = na::Vector3::new(zero, zero, zero);
90
91 if A::inverted() {
92 p_neg[A::value()] = -d;
93 normal[A::value()] = From::from(-1.);
94 } else {
95 p_pos[A::value()] = d;
96 normal[A::value()] = From::from(1.);
97 }
98
99 Plane {
100 distance_from_zero: d,
101 bbox: BoundingBox::new(&p_neg, &p_pos),
102 normal,
103 _phantom: ::std::marker::PhantomData,
104 }
105 }
106}
107
108impl<A: 'static + Axis, S: Float + From<f32> + RealField> Object<S> for Plane<A, S> {
109 fn approx_value(&self, p: &na::Point3<S>, _: S) -> S {
110 let p: S = p[A::value()];
111 let ap: S = Float::abs(p);
112 if Float::is_sign_positive(p) != A::inverted() {
113 ap - self.distance_from_zero
114 } else {
115 -ap - self.distance_from_zero
116 }
117 }
118 fn bbox(&self) -> &BoundingBox<S> {
119 &self.bbox
120 }
121 fn normal(&self, _: &na::Point3<S>) -> na::Vector3<S> {
122 self.normal
123 }
124}
125
126pub type PlaneX<S> = Plane<AxisX, S>;
128pub type PlaneNegX<S> = Plane<AxisNegX, S>;
130pub type PlaneY<S> = Plane<AxisY, S>;
132pub type PlaneNegY<S> = Plane<AxisNegY, S>;
134pub type PlaneZ<S> = Plane<AxisZ, S>;
136pub type PlaneNegZ<S> = Plane<AxisNegZ, S>;
138
139#[derive(Clone, Debug, PartialEq)]
141pub struct NormalPlane<S: RealField> {
142 bbox: BoundingBox<S>,
143 normal: na::Vector3<S>,
144 p: S,
145}
146
147impl<S: From<f32> + RealField + Float> NormalPlane<S> {
148 pub fn from_normal_and_p(normal: na::Vector3<S>, p: S) -> Self {
150 NormalPlane {
151 bbox: BoundingBox::infinity(),
152 normal,
153 p,
154 }
155 }
156 pub fn from_3_points(a: &na::Point3<S>, b: &na::Point3<S>, c: &na::Point3<S>) -> Self {
158 let v1 = a - c;
159 let v2 = b - c;
160 let normal = v1.cross(&v2).normalize();
161 let p = normal.dot(&a.coords);
162 NormalPlane {
163 bbox: BoundingBox::infinity(),
164 normal,
165 p,
166 }
167 }
168}
169
170impl<S: Float + From<f32> + RealField> Object<S> for NormalPlane<S> {
171 fn approx_value(&self, x0: &na::Point3<S>, _: S) -> S {
172 self.normal.dot(&x0.coords) - self.p
173 }
174 fn bbox(&self) -> &BoundingBox<S> {
175 &self.bbox
176 }
177 fn normal(&self, _: &na::Point3<S>) -> na::Vector3<S> {
178 self.normal
179 }
180}
181
182#[cfg(test)]
183mod test {
184 use crate::*;
185
186 #[test]
187 fn simple() {
188 let px = PlaneX::new(10.);
189 assert_ulps_eq!(px.approx_value(&na::Point3::new(0., 0., 0.), 0.), -10.);
190 assert_ulps_eq!(px.approx_value(&na::Point3::new(10., 0., 0.), 0.), 0.);
191 assert_ulps_eq!(px.approx_value(&na::Point3::new(20., 0., 0.), 0.), 10.);
192 assert_ulps_eq!(
193 px.approx_value(&na::Point3::new(20., 1000., 1000.), 0.),
194 10.
195 );
196 }
197
198 #[test]
199 fn hessian_x() {
200 let px = NormalPlane::from_normal_and_p(na::Vector3::new(1., 0., 0.), 0.);
201 assert_ulps_eq!(px.approx_value(&na::Point3::new(0., 0., 0.), 0.), 0.);
202 assert_ulps_eq!(px.approx_value(&na::Point3::new(0., 10., 100.), 0.), 0.);
203 assert_ulps_eq!(px.approx_value(&na::Point3::new(10., 0., 0.), 0.), 10.);
204 }
205
206 #[test]
207 fn hessian_xyz() {
208 let p = NormalPlane::from_normal_and_p(na::Vector3::new(1., 1., 1.).normalize(), 1.);
209 assert_ulps_eq!(p.approx_value(&na::Point3::new(0., 0., 0.), 0.), -1.);
210 assert_ulps_eq!(
211 p.approx_value(&na::Point3::new(1., 1., 1.), 0.),
212 Float::sqrt(3.) - 1.0
213 );
214 assert_ulps_eq!(
215 p.approx_value(&na::Point3::new(2., 2., 2.), 0.),
216 Float::sqrt(12.) - 1.0
217 );
218 }
219
220 #[test]
221 fn hessian_3points_x() {
222 let p = NormalPlane::from_3_points(
223 &na::Point3::new(10., 0., 0.),
224 &na::Point3::new(10., 1., 0.),
225 &na::Point3::new(10., 0., 1.),
226 );
227 assert_ulps_eq!(p.approx_value(&na::Point3::new(0., 0., 0.), 0.), -10.);
228 assert_ulps_eq!(p.approx_value(&na::Point3::new(1., 1., 1.), 0.), -9.0);
229 assert_ulps_eq!(p.approx_value(&na::Point3::new(100., 100., 100.), 0.), 90.);
230 }
231
232 #[test]
233 fn hessian_3points() {
234 let p = NormalPlane::from_3_points(
235 &na::Point3::new(0., 1., 1.),
236 &na::Point3::new(1., 0., 1.),
237 &na::Point3::new(1., 1., 0.),
238 );
239 assert_ulps_eq!(
240 p.approx_value(&na::Point3::new(0., 0., 0.), 0.),
241 -Float::sqrt(4. / 3.)
242 );
243 assert_ulps_eq!(
244 p.approx_value(&na::Point3::new(1., 1., 1.), 0.),
245 Float::sqrt(3.) - Float::sqrt(4. / 3.)
246 );
247 assert_ulps_eq!(
248 p.approx_value(&na::Point3::new(2., 2., 2.), 0.),
249 Float::sqrt(12.) - Float::sqrt(4. / 3.)
250 );
251 }
252}