truck_base/
cgmath_extend_traits.rs

1use cgmath::*;
2
3/// declare control point
4pub mod control_point {
5    use super::*;
6    use std::fmt::Debug;
7    use std::ops::*;
8    /// trait for abstract control points of polylines and B-splines
9    pub trait ControlPoint<S>:
10        Add<Self::Diff, Output = Self>
11        + Sub<Self::Diff, Output = Self>
12        + Sub<Self, Output = Self::Diff>
13        + Mul<S, Output = Self>
14        + Div<S, Output = Self>
15        + AddAssign<Self::Diff>
16        + SubAssign<Self::Diff>
17        + MulAssign<S>
18        + DivAssign<S>
19        + Copy
20        + Clone
21        + Debug {
22        /// differential vector
23        type Diff: Add<Self::Diff, Output = Self::Diff>
24            + Sub<Self::Diff, Output = Self::Diff>
25            + Mul<S, Output = Self::Diff>
26            + Div<S, Output = Self::Diff>
27            + AddAssign<Self::Diff>
28            + SubAssign<Self::Diff>
29            + MulAssign<S>
30            + DivAssign<S>
31            + Zero
32            + Copy
33            + Clone
34            + Debug;
35        /// origin
36        fn origin() -> Self;
37        /// into the vector
38        fn to_vec(self) -> Self::Diff;
39    }
40
41    impl<S: BaseFloat> ControlPoint<S> for Point1<S> {
42        type Diff = Vector1<S>;
43        fn origin() -> Self { EuclideanSpace::origin() }
44        fn to_vec(self) -> Self::Diff { EuclideanSpace::to_vec(self) }
45    }
46    impl<S: BaseFloat> ControlPoint<S> for Point2<S> {
47        type Diff = Vector2<S>;
48        fn origin() -> Self { EuclideanSpace::origin() }
49        fn to_vec(self) -> Self::Diff { EuclideanSpace::to_vec(self) }
50    }
51    impl<S: BaseFloat> ControlPoint<S> for Point3<S> {
52        type Diff = Vector3<S>;
53        fn origin() -> Self { EuclideanSpace::origin() }
54        fn to_vec(self) -> Self::Diff { EuclideanSpace::to_vec(self) }
55    }
56    impl<S: BaseFloat> ControlPoint<S> for Vector1<S> {
57        type Diff = Vector1<S>;
58        fn origin() -> Self { Zero::zero() }
59        fn to_vec(self) -> Self { self }
60    }
61    impl<S: BaseFloat> ControlPoint<S> for Vector2<S> {
62        type Diff = Vector2<S>;
63        fn origin() -> Self { Zero::zero() }
64        fn to_vec(self) -> Self { self }
65    }
66    impl<S: BaseFloat> ControlPoint<S> for Vector3<S> {
67        type Diff = Vector3<S>;
68        fn origin() -> Self { Zero::zero() }
69        fn to_vec(self) -> Self { self }
70    }
71    impl<S: BaseFloat> ControlPoint<S> for Vector4<S> {
72        type Diff = Vector4<S>;
73        fn origin() -> Self { Zero::zero() }
74        fn to_vec(self) -> Self { self }
75    }
76}
77
78/// Tangent spaces of euclidean spaces
79/// The inverse of [`EuclideanSpace::Diff`](../cgmath/trait.EuclideanSpace.html)
80pub trait TangentSpace<S: BaseFloat>: VectorSpace<Scalar = S> {
81    /// The Euclidean space whose tangent space is `Self`.
82    type Space: EuclideanSpace<Scalar = S, Diff = Self>;
83}
84impl<S: BaseFloat> TangentSpace<S> for Vector1<S> {
85    type Space = Point1<S>;
86}
87impl<S: BaseFloat> TangentSpace<S> for Vector2<S> {
88    type Space = Point2<S>;
89}
90impl<S: BaseFloat> TangentSpace<S> for Vector3<S> {
91    type Space = Point3<S>;
92}
93
94/// Homogeneous coordinate of an Euclidean space and a vector space.
95/// # Examples
96/// ```
97/// use truck_base::cgmath64::*;
98/// use truck_base::cgmath_extend_traits::*;
99/// assert_eq!(Vector4::new(8.0, 6.0, 4.0, 2.0).truncate(), Vector3::new(8.0, 6.0, 4.0));
100/// assert_eq!(Vector4::new(8.0, 6.0, 4.0, 2.0).weight(), 2.0);
101/// assert_eq!(Vector4::new(8.0, 6.0, 4.0, 2.0).to_point(), Point3::new(4.0, 3.0, 2.0));
102/// assert_eq!(Vector4::from_point(Point3::new(4.0, 3.0, 2.0)), Vector4::new(4.0, 3.0, 2.0, 1.0));
103/// ```
104pub trait Homogeneous<S: BaseFloat>: VectorSpace<Scalar = S> {
105    /// The point expressed by homogeneous coordinate
106    type Point: EuclideanSpace<Scalar = S>;
107    /// Returns the first dim - 1 components.
108    fn truncate(self) -> <Self::Point as EuclideanSpace>::Diff;
109    /// Returns the last component.
110    fn weight(self) -> S;
111    /// Returns homogeneous coordinate.
112    fn from_point(point: Self::Point) -> Self;
113    /// Returns homogeneous coordinate from point and weight.
114    #[inline(always)]
115    fn from_point_weight(point: Self::Point, weight: S) -> Self { Self::from_point(point) * weight }
116    /// Returns the projection to the plane whose the last component is `1.0`.
117    #[inline(always)]
118    fn to_point(self) -> Self::Point { Self::Point::from_vec(self.truncate() / self.weight()) }
119    /// Returns the derivation of the rational curve.
120    ///
121    /// For a curve c(t) = (c_0(t), c_1(t), c_2(t), c_3(t)), returns the derivation
122    /// of the projected curve (c_0 / c_3, c_1 / c_3, c_2 / c_3, 1.0).
123    /// # Arguments
124    /// * `self` - the point of the curve c(t)
125    /// * `der` - the derivation c'(t) of the curve
126    /// # Examples
127    /// ```
128    /// use truck_base::cgmath64::*;
129    /// use truck_base::cgmath_extend_traits::*;
130    /// // calculate the derivation at t = 1.5
131    /// let t = 1.5;
132    /// // the curve: c(t) = (t^2, t^3, t^4, t)
133    /// let pt = Vector4::new(t * t, t * t * t, t * t * t * t, t);
134    /// // the derivation: c'(t) = (2t, 3t^2, 4t^3, 1)
135    /// let der = Vector4::new(2.0 * t, 3.0 * t * t, 4.0 * t * t * t, 1.0);
136    /// // the projected curve: \bar{c}(t) = (t, t^2, t^3, 1)
137    /// // the derivation of the proj'ed curve: \bar{c}'(t) = (1, 2t, 3t^2, 0)
138    /// let ans = Vector3::new(1.0, 2.0 * t, 3.0 * t * t);
139    /// assert_eq!(pt.rat_der(der), ans);
140    /// ```
141    #[inline(always)]
142    fn rat_der(self, der: Self) -> <Self::Point as EuclideanSpace>::Diff {
143        let res = (der * self.weight() - self * der.weight()) / (self.weight() * self.weight());
144        res.truncate()
145    }
146    /// Returns the 2nd-ord derivation of the rational curve.
147    ///
148    /// For a curve c(t) = (c_0(t), c_1(t), c_2(t), c_3(t)), returns the 2nd ordered derivation
149    /// of the projected curve (c_0 / c_3, c_1 / c_3, c_2 / c_3).
150    /// # Arguments
151    /// * `self` - the point of the curve c(t)
152    /// * `der` - the derivation c'(t) of the curve
153    /// * `der2` - the 2nd ordered derivation c''(t) of the curve
154    /// # Examples
155    /// ```
156    /// use truck_base::cgmath64::*;
157    /// use truck_base::cgmath_extend_traits::*;
158    /// // calculate the derivation at t = 1.5
159    /// let t = 1.5;
160    /// // the curve: c(t) = (t^2, t^3, t^4, t)
161    /// let pt = Vector4::new(t * t, t * t * t, t * t * t * t, t);
162    /// // the derivation: c'(t) = (2t, 3t^2, 4t^3, 1)
163    /// let der = Vector4::new(2.0 * t, 3.0 * t * t, 4.0 * t * t * t, 1.0);
164    /// // the 2nd ord. deri.: c''(t) = (2, 6t, 12t^2, 0)
165    /// let der2 = Vector4::new(2.0, 6.0 * t, 12.0 * t * t, 0.0);
166    /// // the projected curve: \bar{c}(t) = (t, t^2, t^3, 1)
167    /// // the derivation of the proj'ed curve: \bar{c}'(t) = (1, 2t, 3t^2, 0)
168    /// // the 2nd ord. deri. of the proj'ed curve: \bar{c}''(t) = (0, 2, 6t, 0)
169    /// let ans = Vector3::new(0.0, 2.0, 6.0 * t);
170    /// assert_eq!(pt.rat_der2(der, der2), ans);
171    /// ```
172    #[inline(always)]
173    fn rat_der2(self, der: Self, der2: Self) -> <Self::Point as EuclideanSpace>::Diff {
174        let pre_coef1 = der.weight() / (self.weight() * self.weight());
175        let coef1 = pre_coef1 + pre_coef1;
176        let der_last2 = der.weight() * der.weight();
177        let coef2 = (der_last2 + der_last2 - der2.weight() * self.weight())
178            / (self.weight() * self.weight() * self.weight());
179        let res = der2 / self.weight() - der * coef1 + self * coef2;
180        res.truncate()
181    }
182    /// Returns the cross derivation of the rational surface.
183    ///
184    /// For a surface s(u, v) = (s_0(u, v), s_1(u, v), s_2(u, v), s_3(u, v)), returns the derivation
185    /// of the projected surface (s_0 / s_3, s_1 / s_3, s_2 / s_3) by both u and v.
186    /// # Arguments
187    /// * `self` - the point of the surface s(u, v)
188    /// * `uder` - the u-derivation s_u(u, v) of the surface
189    /// * `vder` - the v-derivation s_v(u, v) of the surface
190    /// * `uvder` - the 2nd ordered derivation s_{uv}(u, v) of the surface
191    /// # Examples
192    /// ```
193    /// use truck_base::cgmath64::*;
194    /// // calculate the derivation at (u, v) = (1.0, 2.0).
195    /// let (u, v) = (1.0, 2.0);
196    /// // the curve: s(u, v) = (u^3 v^2, u^2 v^3, u v, u)
197    /// let pt = Vector4::new(
198    ///     u * u * u * v * v,
199    ///     u * u * v * v * v,
200    ///     u * v,
201    ///     u,
202    /// );
203    /// // the u-derivation: s_u(u, v) = (3u^2 v^2, 2u * v^3, v, 1)
204    /// let uder = Vector4::new(
205    ///     3.0 * u * u * v * v,
206    ///     2.0 * u * v * v * v,
207    ///     v,
208    ///     1.0,
209    /// );
210    /// // the v-derivation: s_v(u, v) = (2u^3 v, 3u^2 v^2, u, 0)
211    /// let vder = Vector4::new(
212    ///     2.0 * u * u * u * v,
213    ///     3.0 * u * u * v * v,
214    ///     u,
215    ///     0.0,
216    /// );
217    /// // s_{uv}(u, v) = (6u^2 v, 6u v^2, 1, 0)
218    /// let uvder = Vector4::new(6.0 * u * u * v, 6.0 * u * v * v, 1.0, 0.0);
219    /// // the projected surface: \bar{s}(u, v) = (u^2 v^2, u v^3, v)
220    /// // \bar{s}_u(u, v) = (2u v^2, v^3, 0)
221    /// // \bar{s}_v(u, v) = (2u^2 v, 3u v^2, 1)
222    /// // \bar{s}_{uv}(u, v) = (4uv, 3v^2, 0)
223    /// let ans = Vector3::new(4.0 * u * v, 3.0 * v * v, 0.0);
224    /// assert_eq!(pt.rat_cross_der(uder, vder, uvder), ans);
225    /// ```
226    #[inline(always)]
227    fn rat_cross_der(
228        &self,
229        uder: Self,
230        vder: Self,
231        uvder: Self,
232    ) -> <Self::Point as EuclideanSpace>::Diff {
233        let self_weight2 = self.weight() * self.weight();
234        let coef1 = vder.weight() / self_weight2;
235        let coef2 = uder.weight() / self_weight2;
236        let der_weight2 = uder.weight() * vder.weight();
237        let coef3 = (der_weight2 + der_weight2 - uvder.weight() * self.weight())
238            / (self_weight2 * self.weight());
239        let res = uvder / self.weight() - uder * coef1 - vder * coef2 + *self * coef3;
240        res.truncate()
241    }
242}
243
244impl<S: BaseFloat> Homogeneous<S> for Vector2<S> {
245    type Point = Point1<S>;
246    #[inline(always)]
247    fn truncate(self) -> Vector1<S> { Vector1::new(self[0]) }
248    #[inline(always)]
249    fn weight(self) -> S { self[1] }
250    #[inline(always)]
251    fn from_point(point: Self::Point) -> Self { Vector2::new(point[0], S::one()) }
252}
253
254impl<S: BaseFloat> Homogeneous<S> for Vector3<S> {
255    type Point = Point2<S>;
256    #[inline(always)]
257    fn truncate(self) -> Vector2<S> { self.truncate() }
258    #[inline(always)]
259    fn weight(self) -> S { self[2] }
260    #[inline(always)]
261    fn from_point(point: Self::Point) -> Self { Vector3::new(point[0], point[1], S::one()) }
262}
263
264impl<S: BaseFloat> Homogeneous<S> for Vector4<S> {
265    type Point = Point3<S>;
266    #[inline(always)]
267    fn truncate(self) -> Vector3<S> { self.truncate() }
268    #[inline(always)]
269    fn weight(self) -> S { self[3] }
270    #[inline(always)]
271    fn from_point(point: Self::Point) -> Self { point.to_homogeneous() }
272}