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}