truck_geometry/specifieds/
plane.rs

1use super::*;
2
3impl Plane {
4    /// Creates a new plane from three points.
5    #[inline(always)]
6    pub const fn new(origin: Point3, one: Point3, another: Point3) -> Plane {
7        Plane {
8            o: origin,
9            p: one,
10            q: another,
11        }
12    }
13    /// Returns the origin
14    #[inline(always)]
15    pub const fn origin(&self) -> Point3 { self.o }
16    /// Returns the u-axis
17    #[inline(always)]
18    pub fn u_axis(&self) -> Vector3 { self.p - self.o }
19    /// Returns the v-axis
20    #[inline(always)]
21    pub fn v_axis(&self) -> Vector3 { self.q - self.o }
22    /// Returns the normal
23    /// # Examples
24    /// ```
25    /// use truck_geometry::prelude::*;
26    /// let plane = Plane::new(
27    ///     Point3::new(0.0, 0.0, 0.0),
28    ///     Point3::new(1.0, 0.0, 0.0),
29    ///     Point3::new(0.0, 1.0, 0.0),
30    /// );
31    /// assert_near!(plane.normal(), Vector3::unit_z());
32    /// ```
33    #[inline(always)]
34    pub fn normal(&self) -> Vector3 { self.u_axis().cross(self.v_axis()).normalize() }
35    /// Gets the parameter of `pt` in plane's matrix.
36    /// # Examples
37    /// ```
38    /// use truck_geometry::prelude::*;
39    /// let plane = Plane::new(
40    ///     Point3::new(1.0, 2.0, 3.0),
41    ///     Point3::new(2.0, 1.0, 3.0),
42    ///     Point3::new(3.0, 4.0, -1.0),
43    /// );
44    ///
45    /// let pt = Point3::new(2.1, -6.5, 4.7);
46    /// let prm = plane.get_parameter(pt);
47    /// let rev = plane.origin()
48    ///     + prm[0] * plane.u_axis()
49    ///     + prm[1] * plane.v_axis()
50    ///     + prm[2] * plane.normal();
51    /// assert_near!(pt, rev);
52    /// ```
53    #[inline(always)]
54    pub fn get_parameter(&self, pt: Point3) -> Vector3 {
55        let a = self.u_axis();
56        let b = self.v_axis();
57        let c = self.normal();
58        let mat = Matrix3::from_cols(a, b, c).invert().unwrap();
59        mat * (pt - self.o)
60    }
61    /// into B-spline surface
62    /// # Examples
63    /// ```
64    /// use truck_geometry::prelude::*;
65    /// let pt0 = Point3::new(0.0, 1.0, 2.0);
66    /// let pt1 = Point3::new(1.0, 1.0, 3.0);
67    /// let pt2 = Point3::new(0.0, 2.0, 3.0);
68    /// let plane: Plane = Plane::new(pt0, pt1, pt2);
69    /// let surface: BSplineSurface<Point3> = plane.into_bspline();
70    /// assert_eq!(surface.range_tuple(), ((0.0, 1.0), (0.0, 1.0)));
71    ///
72    /// const N: usize = 100;
73    /// for i in 0..=N {
74    ///     for j in 0..=N {
75    ///         let u = i as f64 / N as f64;
76    ///         let v = j as f64 / N as f64;
77    ///         let res = surface.subs(u, v);
78    ///         let ans = plane.subs(u, v);
79    ///         assert_near!(ans, res);
80    ///     }
81    /// }
82    /// ```
83    #[inline(always)]
84    pub fn into_bspline(&self) -> BSplineSurface<Point3> {
85        let o = self.o;
86        let p = self.p;
87        let q = self.q;
88        BSplineSurface::debug_new(
89            (KnotVec::bezier_knot(1), KnotVec::bezier_knot(1)),
90            vec![vec![o, q], vec![p, p + (q - o)]],
91        )
92    }
93    /// into NURBS surface
94    /// # Examples
95    /// ```
96    /// use truck_geometry::prelude::*;
97    /// let pt0 = Point3::new(0.0, 1.0, 2.0);
98    /// let pt1 = Point3::new(1.0, 1.0, 3.0);
99    /// let pt2 = Point3::new(0.0, 2.0, 3.0);
100    /// let plane: Plane = Plane::new(pt0, pt1, pt2);
101    /// let surface: NurbsSurface<Vector4> = plane.into_nurbs();
102    /// assert_eq!(surface.range_tuple(), ((0.0, 1.0), (0.0, 1.0)));
103    ///
104    /// const N: usize = 100;
105    /// for i in 0..=N {
106    ///     for j in 0..=N {
107    ///         let u = i as f64 / N as f64;
108    ///         let v = j as f64 / N as f64;
109    ///         let res = surface.subs(u, v);
110    ///         let ans = plane.subs(u, v);
111    ///         assert_near!(ans, res);
112    ///     }
113    /// }
114    /// ```
115    #[inline(always)]
116    pub fn into_nurbs(&self) -> NurbsSurface<Vector4> {
117        let o = self.o.to_homogeneous();
118        let p = self.p.to_homogeneous();
119        let q = self.q.to_homogeneous();
120        NurbsSurface::new(BSplineSurface::debug_new(
121            (KnotVec::bezier_knot(1), KnotVec::bezier_knot(1)),
122            vec![vec![o, q], vec![p, p + q - o]],
123        ))
124    }
125}
126
127impl ParametricSurface for Plane {
128    type Point = Point3;
129    type Vector = Vector3;
130    #[inline(always)]
131    fn subs(&self, u: f64, v: f64) -> Point3 {
132        self.o + u * (self.p - self.o) + v * (self.q - self.o)
133    }
134    #[inline(always)]
135    fn uder(&self, _: f64, _: f64) -> Vector3 { self.p - self.o }
136    #[inline(always)]
137    fn vder(&self, _: f64, _: f64) -> Vector3 { self.q - self.o }
138    #[inline(always)]
139    fn uuder(&self, _: f64, _: f64) -> Vector3 { Vector3::zero() }
140    #[inline(always)]
141    fn uvder(&self, _: f64, _: f64) -> Vector3 { Vector3::zero() }
142    #[inline(always)]
143    fn vvder(&self, _: f64, _: f64) -> Vector3 { Vector3::zero() }
144    /// as square
145    #[inline(always)]
146    fn parameter_range(&self) -> (ParameterRange, ParameterRange) {
147        let range = (Bound::Included(0.0), Bound::Included(1.0));
148        (range, range)
149    }
150}
151
152impl ParametricSurface3D for Plane {
153    #[inline(always)]
154    fn normal(&self, _: f64, _: f64) -> Vector3 { self.normal() }
155}
156
157impl BoundedSurface for Plane {}
158
159impl Invertible for Plane {
160    #[inline(always)]
161    fn inverse(&self) -> Self {
162        Plane {
163            o: self.o,
164            p: self.q,
165            q: self.p,
166        }
167    }
168    #[inline(always)]
169    fn invert(&mut self) { *self = self.inverse(); }
170}
171
172impl IncludeCurve<BSplineCurve<Point3>> for Plane {
173    #[inline(always)]
174    fn include(&self, curve: &BSplineCurve<Point3>) -> bool {
175        let origin = self.origin();
176        let normal = self.normal();
177        curve
178            .control_points()
179            .iter()
180            .all(|pt| (pt - origin).dot(normal).so_small())
181    }
182}
183
184impl IncludeCurve<NurbsCurve<Vector4>> for Plane {
185    fn include(&self, curve: &NurbsCurve<Vector4>) -> bool {
186        let origin = self.origin();
187        let normal = self.normal();
188        let (s, e) = (curve.front(), curve.back());
189        if !(s - origin).dot(normal).so_small() || !(e - origin).dot(normal).so_small() {
190            return false;
191        }
192        curve.non_rationalized().control_points().iter().all(|pt| {
193            if pt[3].so_small() {
194                true
195            } else {
196                let pt = Point3::from_homogeneous(*pt);
197                (pt - origin).dot(normal).so_small()
198            }
199        })
200    }
201}
202
203impl ParameterDivision2D for Plane {
204    #[inline(always)]
205    fn parameter_division(&self, range: ((f64, f64), (f64, f64)), _: f64) -> (Vec<f64>, Vec<f64>) {
206        (vec![range.0 .0, range.0 .1], vec![range.1 .0, range.1 .1])
207    }
208}
209
210impl<T: Transform3<Scalar = f64>> Transformed<T> for Plane {
211    #[inline(always)]
212    fn transform_by(&mut self, trans: T) {
213        self.o = trans.transform_point(self.o);
214        self.p = trans.transform_point(self.p);
215        self.q = trans.transform_point(self.q);
216    }
217    #[inline(always)]
218    fn transformed(&self, trans: T) -> Self {
219        Plane {
220            o: trans.transform_point(self.o),
221            p: trans.transform_point(self.p),
222            q: trans.transform_point(self.q),
223        }
224    }
225}
226
227impl SearchParameter<D2> for Plane {
228    type Point = Point3;
229    #[inline(always)]
230    fn search_parameter<H: Into<SPHint2D>>(
231        &self,
232        point: Point3,
233        _: H,
234        _: usize,
235    ) -> Option<(f64, f64)> {
236        let v = self.get_parameter(point);
237        match v[2].so_small() {
238            true => Some((v[0], v[1])),
239            false => None,
240        }
241    }
242}
243
244impl SearchNearestParameter<D2> for Plane {
245    type Point = Point3;
246    #[inline(always)]
247    fn search_nearest_parameter<H: Into<SPHint2D>>(
248        &self,
249        point: Point3,
250        _: H,
251        _: usize,
252    ) -> Option<(f64, f64)> {
253        let v = self.get_parameter(point);
254        Some((v[0], v[1]))
255    }
256}