Skip to main content

implicit3d/
plane.rs

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
126/// A YZ-Plane.
127pub type PlaneX<S> = Plane<AxisX, S>;
128/// A negative YZ-Plane.
129pub type PlaneNegX<S> = Plane<AxisNegX, S>;
130/// A XZ-Plane
131pub type PlaneY<S> = Plane<AxisY, S>;
132/// A negative XZ-Plane
133pub type PlaneNegY<S> = Plane<AxisNegY, S>;
134/// A XY-Plane
135pub type PlaneZ<S> = Plane<AxisZ, S>;
136/// A negative XZ-Plane
137pub type PlaneNegZ<S> = Plane<AxisNegZ, S>;
138
139/// An arbitrary (not axis aligned) plane.
140#[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    /// Create a plane in hessian form.
149    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    /// Create a plane from 3 points.
157    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}