1 | /************************************************************** ggt-head beg |
---|
2 | * |
---|
3 | * GGT: Generic Graphics Toolkit |
---|
4 | * |
---|
5 | * Original Authors: |
---|
6 | * Allen Bierbaum |
---|
7 | * |
---|
8 | * ----------------------------------------------------------------- |
---|
9 | * File: Generate.h,v |
---|
10 | * Date modified: 2006/04/24 14:33:04 |
---|
11 | * Version: 1.91 |
---|
12 | * ----------------------------------------------------------------- |
---|
13 | * |
---|
14 | *********************************************************** ggt-head end */ |
---|
15 | /*************************************************************** ggt-cpr beg |
---|
16 | * |
---|
17 | * GGT: The Generic Graphics Toolkit |
---|
18 | * Copyright (C) 2001,2002 Allen Bierbaum |
---|
19 | * |
---|
20 | * This library is free software; you can redistribute it and/or |
---|
21 | * modify it under the terms of the GNU Lesser General Public |
---|
22 | * License as published by the Free Software Foundation; either |
---|
23 | * version 2.1 of the License, or (at your option) any later version. |
---|
24 | * |
---|
25 | * This library is distributed in the hope that it will be useful, |
---|
26 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
27 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
---|
28 | * Lesser General Public License for more details. |
---|
29 | * |
---|
30 | * You should have received a copy of the GNU Lesser General Public |
---|
31 | * License along with this library; if not, write to the Free Software |
---|
32 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
---|
33 | * |
---|
34 | ************************************************************ ggt-cpr end */ |
---|
35 | #ifndef _GMTL_GENERATE_H_ |
---|
36 | #define _GMTL_GENERATE_H_ |
---|
37 | |
---|
38 | #include <gmtl/Defines.h> |
---|
39 | #include <gmtl/Util/Assert.h> |
---|
40 | #include <gmtl/Util/StaticAssert.h> |
---|
41 | |
---|
42 | #include <gmtl/Vec.h> // for Vec |
---|
43 | #include <gmtl/VecOps.h> // for lengthSquared |
---|
44 | #include <gmtl/Quat.h> |
---|
45 | #include <gmtl/QuatOps.h> |
---|
46 | #include <gmtl/Coord.h> |
---|
47 | #include <gmtl/Matrix.h> |
---|
48 | #include <gmtl/Util/Meta.h> |
---|
49 | #include <gmtl/Math.h> |
---|
50 | #include <gmtl/Xforms.h> |
---|
51 | |
---|
52 | #include <gmtl/EulerAngle.h> |
---|
53 | #include <gmtl/AxisAngle.h> |
---|
54 | |
---|
55 | namespace gmtl |
---|
56 | { |
---|
57 | /** @ingroup Generate |
---|
58 | * @name Vec Generators |
---|
59 | * @{ |
---|
60 | */ |
---|
61 | |
---|
62 | /** create a vector from the vector component of a quaternion |
---|
63 | * @returns a vector of the quaternion's axis. quat = [v,0] = [v0,v1,v2,0] |
---|
64 | */ |
---|
65 | template <typename DATA_TYPE> |
---|
66 | inline Vec<DATA_TYPE, 3> makeVec( const Quat<DATA_TYPE>& quat ) |
---|
67 | { |
---|
68 | return Vec<DATA_TYPE, 3>( quat[Xelt], quat[Yelt], quat[Zelt] ); |
---|
69 | } |
---|
70 | |
---|
71 | /** create a normalized vector from the given vector. |
---|
72 | */ |
---|
73 | template <typename DATA_TYPE, unsigned SIZE> |
---|
74 | inline Vec<DATA_TYPE, SIZE> makeNormal( Vec<DATA_TYPE, SIZE> vec ) |
---|
75 | { |
---|
76 | normalize( vec ); |
---|
77 | return vec; |
---|
78 | } |
---|
79 | |
---|
80 | /** |
---|
81 | * Computes the cross product between v1 and v2 and returns the result. Note |
---|
82 | * that this only applies to 3-dimensional vectors. |
---|
83 | * |
---|
84 | * @pre v1 and v2 must be 3-D vectors |
---|
85 | * @post result = v1 x v2 |
---|
86 | * |
---|
87 | * @param v1 the first vector |
---|
88 | * @param v2 the second vector |
---|
89 | * |
---|
90 | * @return the result of the cross product between v1 and v2 |
---|
91 | */ |
---|
92 | template<class DATA_TYPE> |
---|
93 | Vec<DATA_TYPE,3> makeCross(const Vec<DATA_TYPE, 3>& v1, |
---|
94 | const Vec<DATA_TYPE, 3>& v2) |
---|
95 | { |
---|
96 | return Vec<DATA_TYPE,3>( ((v1[Yelt]*v2[Zelt]) - (v1[Zelt]*v2[Yelt])), |
---|
97 | ((v1[Zelt]*v2[Xelt]) - (v1[Xelt]*v2[Zelt])), |
---|
98 | ((v1[Xelt]*v2[Yelt]) - (v1[Yelt]*v2[Xelt])) ); |
---|
99 | } |
---|
100 | |
---|
101 | /** Set vector using translation portion of the matrix. |
---|
102 | * @pre if making an n x n matrix, then for |
---|
103 | * - <b>vector is homogeneous:</b> SIZE of vector needs to equal number of Matrix ROWS - 1 |
---|
104 | * - <b>vector has scale component:</b> SIZE of vector needs to equal number of Matrix ROWS |
---|
105 | * if making an n x n+1 matrix, then for |
---|
106 | * - <b>vector is homogeneous:</b> SIZE of vector needs to equal number of Matrix ROWS |
---|
107 | * - <b>vector has scale component:</b> SIZE of vector needs to equal number of Matrix ROWS + 1 |
---|
108 | * @post if preconditions are not met, then function is undefined (will not compile) |
---|
109 | */ |
---|
110 | template<typename VEC_TYPE, typename DATA_TYPE, unsigned ROWS, unsigned COLS > |
---|
111 | inline VEC_TYPE& setTrans( VEC_TYPE& result, const Matrix<DATA_TYPE, ROWS, COLS>& arg ) |
---|
112 | { |
---|
113 | // ASSERT: There are as many |
---|
114 | |
---|
115 | // if n x n then (homogeneous case) vecsize == rows-1 or (scale component case) vecsize == rows |
---|
116 | // if n x n+1 then (homogeneous case) vecsize == rows or (scale component case) vecsize == rows+1 |
---|
117 | gmtlASSERT( ((ROWS == COLS && ( VEC_TYPE::Size == (ROWS-1) || VEC_TYPE::Size == ROWS)) || |
---|
118 | (COLS == (ROWS+1) && ( VEC_TYPE::Size == ROWS || VEC_TYPE::Size == (ROWS+1)))) && |
---|
119 | "preconditions not met for vector size in call to makeTrans. Read your documentation." ); |
---|
120 | |
---|
121 | // homogeneous case... |
---|
122 | if ((ROWS == COLS && VEC_TYPE::Size == ROWS) // Square matrix and vec so assume homogeneous vector. ex. 4x4 with vec 4 |
---|
123 | || (COLS == (ROWS+1) && VEC_TYPE::Size == (ROWS+1))) // ex: 3x4 with vec4 |
---|
124 | { |
---|
125 | result[VEC_TYPE::Size-1] = 1.0f; |
---|
126 | } |
---|
127 | |
---|
128 | // non-homogeneous case... (SIZE == ROWS), |
---|
129 | //else |
---|
130 | //{} |
---|
131 | |
---|
132 | for (unsigned x = 0; x < COLS - 1; ++x) |
---|
133 | { |
---|
134 | result[x] = arg( x, COLS - 1 ); |
---|
135 | } |
---|
136 | |
---|
137 | return result; |
---|
138 | } |
---|
139 | |
---|
140 | /** @} */ |
---|
141 | |
---|
142 | /** @ingroup Generate |
---|
143 | * @name Quat Generators |
---|
144 | * @{ |
---|
145 | */ |
---|
146 | |
---|
147 | /** Set pure quaternion |
---|
148 | * @pre vec should be normalized |
---|
149 | * @param quat any quaternion object |
---|
150 | * @param vec a normalized vector representing an axis |
---|
151 | * @post quat will have vec as its axis, and no rotation |
---|
152 | */ |
---|
153 | template <typename DATA_TYPE> |
---|
154 | inline Quat<DATA_TYPE>& setPure( Quat<DATA_TYPE>& quat, const Vec<DATA_TYPE, 3>& vec ) |
---|
155 | { |
---|
156 | quat.set( vec[0], vec[1], vec[2], 0 ); |
---|
157 | return quat; |
---|
158 | } |
---|
159 | |
---|
160 | /** create a pure quaternion |
---|
161 | * @pre vec should be normalized |
---|
162 | * @param vec a normalized vector representing an axis |
---|
163 | * @return a quaternion with vec as its axis, and no rotation |
---|
164 | * @post quat = [v,0] = [v0,v1,v2,0] |
---|
165 | */ |
---|
166 | template <typename DATA_TYPE> |
---|
167 | inline Quat<DATA_TYPE> makePure( const Vec<DATA_TYPE, 3>& vec ) |
---|
168 | { |
---|
169 | return Quat<DATA_TYPE>( vec[0], vec[1], vec[2], 0 ); |
---|
170 | } |
---|
171 | |
---|
172 | /** Normalize a quaternion |
---|
173 | * @param quat a quaternion |
---|
174 | * @post quat is normalized |
---|
175 | */ |
---|
176 | template <typename DATA_TYPE> |
---|
177 | inline Quat<DATA_TYPE> makeNormal( const Quat<DATA_TYPE>& quat ) |
---|
178 | { |
---|
179 | Quat<DATA_TYPE> temporary( quat ); |
---|
180 | return normalize( temporary ); |
---|
181 | } |
---|
182 | |
---|
183 | /** quaternion complex conjugate. |
---|
184 | * @param quat any quaternion object |
---|
185 | * @post set result to the complex conjugate of result. |
---|
186 | * @post result'[x,y,z,w] == result[-x,-y,-z,w] |
---|
187 | * @see Quat |
---|
188 | */ |
---|
189 | template <typename DATA_TYPE> |
---|
190 | inline Quat<DATA_TYPE> makeConj( const Quat<DATA_TYPE>& quat ) |
---|
191 | { |
---|
192 | Quat<DATA_TYPE> temporary( quat ); |
---|
193 | return conj( temporary ); |
---|
194 | } |
---|
195 | |
---|
196 | /** create quaternion from the inverse of another quaternion. |
---|
197 | * @param quat any quaternion object |
---|
198 | * @return a quaternion that is the multiplicative inverse of quat |
---|
199 | * @see Quat |
---|
200 | */ |
---|
201 | template <typename DATA_TYPE> |
---|
202 | inline Quat<DATA_TYPE> makeInvert( const Quat<DATA_TYPE>& quat ) |
---|
203 | { |
---|
204 | Quat<DATA_TYPE> temporary( quat ); |
---|
205 | return invert( temporary ); |
---|
206 | } |
---|
207 | |
---|
208 | /** Convert an AxisAngle to a Quat. sets a rotation quaternion from an angle and an axis. |
---|
209 | * @pre AxisAngle::axis must be normalized to length == 1 prior to calling this. |
---|
210 | * @post q = [ cos(rad/2), sin(rad/2) * [x,y,z] ] |
---|
211 | */ |
---|
212 | template <typename DATA_TYPE> |
---|
213 | inline Quat<DATA_TYPE>& set( Quat<DATA_TYPE>& result, const AxisAngle<DATA_TYPE>& axisAngle ) |
---|
214 | { |
---|
215 | gmtlASSERT( (Math::isEqual( lengthSquared( axisAngle.getAxis() ), (DATA_TYPE)1.0, (DATA_TYPE)0.0001 )) && |
---|
216 | "you must pass in a normalized vector to setRot( quat, rad, vec )" ); |
---|
217 | |
---|
218 | DATA_TYPE half_angle = axisAngle.getAngle() * (DATA_TYPE)0.5; |
---|
219 | DATA_TYPE sin_half_angle = Math::sin( half_angle ); |
---|
220 | |
---|
221 | result[Welt] = Math::cos( half_angle ); |
---|
222 | result[Xelt] = sin_half_angle * axisAngle.getAxis()[0]; |
---|
223 | result[Yelt] = sin_half_angle * axisAngle.getAxis()[1]; |
---|
224 | result[Zelt] = sin_half_angle * axisAngle.getAxis()[2]; |
---|
225 | |
---|
226 | // should automagically be normalized (unit magnitude) now... |
---|
227 | return result; |
---|
228 | } |
---|
229 | |
---|
230 | /** Redundant duplication of the set(quat,axisangle) function, this is provided only for template compatibility. |
---|
231 | * unless you're writing template functions, you should use set(quat,axisangle). |
---|
232 | */ |
---|
233 | template <typename DATA_TYPE> |
---|
234 | inline Quat<DATA_TYPE>& setRot( Quat<DATA_TYPE>& result, const AxisAngle<DATA_TYPE>& axisAngle ) |
---|
235 | { |
---|
236 | return gmtl::set( result, axisAngle ); |
---|
237 | } |
---|
238 | |
---|
239 | /** Convert an EulerAngle rotation to a Quaternion rotation. |
---|
240 | * Sets a rotation quaternion using euler angles (each angle in radians). |
---|
241 | * @pre pass in your angles in the same order as the RotationOrder you specify |
---|
242 | */ |
---|
243 | template <typename DATA_TYPE, typename ROT_ORDER> |
---|
244 | inline Quat<DATA_TYPE>& set( Quat<DATA_TYPE>& result, const EulerAngle<DATA_TYPE, ROT_ORDER>& euler ) |
---|
245 | { |
---|
246 | // this might be faster if put into the switch statement... (testme) |
---|
247 | const int& order = ROT_ORDER::ID; |
---|
248 | const DATA_TYPE xRot = (order == XYZ::ID) ? euler[0] : ((order == ZXY::ID) ? euler[1] : euler[2]); |
---|
249 | const DATA_TYPE yRot = (order == XYZ::ID) ? euler[1] : ((order == ZXY::ID) ? euler[2] : euler[1]); |
---|
250 | const DATA_TYPE zRot = (order == XYZ::ID) ? euler[2] : ((order == ZXY::ID) ? euler[0] : euler[0]); |
---|
251 | |
---|
252 | // this could be written better for each rotation order, but this is really general... |
---|
253 | Quat<DATA_TYPE> qx, qy, qz; |
---|
254 | |
---|
255 | // precompute half angles |
---|
256 | DATA_TYPE xOver2 = xRot * (DATA_TYPE)0.5; |
---|
257 | DATA_TYPE yOver2 = yRot * (DATA_TYPE)0.5; |
---|
258 | DATA_TYPE zOver2 = zRot * (DATA_TYPE)0.5; |
---|
259 | |
---|
260 | // set the pitch quat |
---|
261 | qx[Xelt] = Math::sin( xOver2 ); |
---|
262 | qx[Yelt] = (DATA_TYPE)0.0; |
---|
263 | qx[Zelt] = (DATA_TYPE)0.0; |
---|
264 | qx[Welt] = Math::cos( xOver2 ); |
---|
265 | |
---|
266 | // set the yaw quat |
---|
267 | qy[Xelt] = (DATA_TYPE)0.0; |
---|
268 | qy[Yelt] = Math::sin( yOver2 ); |
---|
269 | qy[Zelt] = (DATA_TYPE)0.0; |
---|
270 | qy[Welt] = Math::cos( yOver2 ); |
---|
271 | |
---|
272 | // set the roll quat |
---|
273 | qz[Xelt] = (DATA_TYPE)0.0; |
---|
274 | qz[Yelt] = (DATA_TYPE)0.0; |
---|
275 | qz[Zelt] = Math::sin( zOver2 ); |
---|
276 | qz[Welt] = Math::cos( zOver2 ); |
---|
277 | |
---|
278 | // compose the three in pyr order... |
---|
279 | switch (order) |
---|
280 | { |
---|
281 | case XYZ::ID: result = qx * qy * qz; break; |
---|
282 | case ZYX::ID: result = qz * qy * qx; break; |
---|
283 | case ZXY::ID: result = qz * qx * qy; break; |
---|
284 | default: |
---|
285 | gmtlASSERT( false && "unknown rotation order passed to setRot" ); |
---|
286 | break; |
---|
287 | } |
---|
288 | |
---|
289 | // ensure the quaternion is normalized |
---|
290 | normalize( result ); |
---|
291 | return result; |
---|
292 | } |
---|
293 | |
---|
294 | /** Redundant duplication of the set(quat,eulerangle) function, this is provided only for template compatibility. |
---|
295 | * unless you're writing template functions, you should use set(quat,eulerangle). |
---|
296 | */ |
---|
297 | template <typename DATA_TYPE, typename ROT_ORDER> |
---|
298 | inline Quat<DATA_TYPE>& setRot( Quat<DATA_TYPE>& result, const EulerAngle<DATA_TYPE, ROT_ORDER>& euler ) |
---|
299 | { |
---|
300 | return gmtl::set( result, euler ); |
---|
301 | } |
---|
302 | |
---|
303 | /** Convert a Matrix to a Quat. |
---|
304 | * Sets the rotation quaternion using the given matrix |
---|
305 | * (3x3, 3x4, 4x3, or 4x4 are all valid sizes). |
---|
306 | */ |
---|
307 | template <typename DATA_TYPE, unsigned ROWS, unsigned COLS> |
---|
308 | inline Quat<DATA_TYPE>& set( Quat<DATA_TYPE>& quat, const Matrix<DATA_TYPE, ROWS, COLS>& mat ) |
---|
309 | { |
---|
310 | gmtlASSERT( ((ROWS == 3 && COLS == 3) || |
---|
311 | (ROWS == 3 && COLS == 4) || |
---|
312 | (ROWS == 4 && COLS == 3) || |
---|
313 | (ROWS == 4 && COLS == 4)) && |
---|
314 | "pre conditions not met on set( quat, pos, mat ) which only sets a quaternion to the rotation part of a 3x3, 3x4, 4x3, or 4x4 matrix." ); |
---|
315 | |
---|
316 | DATA_TYPE tr( mat( 0, 0 ) + mat( 1, 1 ) + mat( 2, 2 ) ), s( 0.0f ); |
---|
317 | |
---|
318 | // If diagonal is positive |
---|
319 | if (tr > (DATA_TYPE)0.0) |
---|
320 | { |
---|
321 | s = Math::sqrt( tr + (DATA_TYPE)1.0 ); |
---|
322 | quat[Welt] = s * (DATA_TYPE)0.5; |
---|
323 | s = DATA_TYPE(0.5) / s; |
---|
324 | |
---|
325 | quat[Xelt] = (mat( 2, 1 ) - mat( 1, 2 )) * s; |
---|
326 | quat[Yelt] = (mat( 0, 2 ) - mat( 2, 0 )) * s; |
---|
327 | quat[Zelt] = (mat( 1, 0 ) - mat( 0, 1 )) * s; |
---|
328 | } |
---|
329 | |
---|
330 | // when Diagonal is negative |
---|
331 | else |
---|
332 | { |
---|
333 | static const unsigned int nxt[3] = { 1, 2, 0 }; |
---|
334 | unsigned int i( Xelt ), j, k; |
---|
335 | |
---|
336 | if (mat( 1, 1 ) > mat( 0, 0 )) |
---|
337 | i = 1; |
---|
338 | |
---|
339 | if (mat( 2, 2 ) > mat( i, i )) |
---|
340 | i = 2; |
---|
341 | |
---|
342 | j = nxt[i]; |
---|
343 | k = nxt[j]; |
---|
344 | |
---|
345 | s = Math::sqrt( (mat( i, i )-(mat( j, j )+mat( k, k ))) + (DATA_TYPE)1.0 ); |
---|
346 | |
---|
347 | DATA_TYPE q[4]; |
---|
348 | q[i] = s * (DATA_TYPE)0.5; |
---|
349 | |
---|
350 | if (s != (DATA_TYPE)0.0) |
---|
351 | s = DATA_TYPE(0.5) / s; |
---|
352 | |
---|
353 | q[3] = (mat( k, j ) - mat( j, k )) * s; |
---|
354 | q[j] = (mat( j, i ) + mat( i, j )) * s; |
---|
355 | q[k] = (mat( k, i ) + mat( i, k )) * s; |
---|
356 | |
---|
357 | quat[Xelt] = q[0]; |
---|
358 | quat[Yelt] = q[1]; |
---|
359 | quat[Zelt] = q[2]; |
---|
360 | quat[Welt] = q[3]; |
---|
361 | } |
---|
362 | |
---|
363 | return quat; |
---|
364 | } |
---|
365 | |
---|
366 | /** Redundant duplication of the set(quat,mat) function, this is provided only for template compatibility. |
---|
367 | * unless you're writing template functions, you should use set(quat,mat). |
---|
368 | */ |
---|
369 | template <typename DATA_TYPE, unsigned ROWS, unsigned COLS> |
---|
370 | inline Quat<DATA_TYPE>& setRot( Quat<DATA_TYPE>& result, const Matrix<DATA_TYPE, ROWS, COLS>& mat ) |
---|
371 | { |
---|
372 | return gmtl::set( result, mat ); |
---|
373 | } |
---|
374 | /** @} */ |
---|
375 | |
---|
376 | /** @ingroup Generate |
---|
377 | * @name AxisAngle Generators |
---|
378 | * @{ |
---|
379 | */ |
---|
380 | |
---|
381 | /** Convert a rotation quaternion to an AxisAngle. |
---|
382 | * |
---|
383 | * @post returns an angle in radians, and a normalized axis equivilent to the quaternion's rotation. |
---|
384 | * @post returns rad and xyz such that |
---|
385 | * <ul> |
---|
386 | * <li> rad = acos( w ) * 2.0 |
---|
387 | * <li> vec = v / (asin( w ) * 2.0) [where v is the xyz or vector component of the quat] |
---|
388 | * </ul> |
---|
389 | * @post axisAngle = quat; |
---|
390 | */ |
---|
391 | template <typename DATA_TYPE> |
---|
392 | inline AxisAngle<DATA_TYPE>& set( AxisAngle<DATA_TYPE>& axisAngle, Quat<DATA_TYPE> quat ) |
---|
393 | { |
---|
394 | // set sure we don't get a NaN result from acos... |
---|
395 | if (Math::abs( quat[Welt] ) > (DATA_TYPE)1.0) |
---|
396 | { |
---|
397 | gmtl::normalize( quat ); |
---|
398 | } |
---|
399 | gmtlASSERT( Math::abs( quat[Welt] ) <= (DATA_TYPE)1.0 && "acos returns NaN when quat[Welt] > 1, try normalizing your quat." ); |
---|
400 | |
---|
401 | // [acos( w ) * 2.0, v / (asin( w ) * 2.0)] |
---|
402 | |
---|
403 | // set the angle - aCos is mathematically defined to be between 0 and PI |
---|
404 | DATA_TYPE rad = Math::aCos( quat[Welt] ) * (DATA_TYPE)2.0; |
---|
405 | axisAngle.setAngle( rad ); |
---|
406 | |
---|
407 | // set the axis: (use sin(rad) instead of asin(w)) |
---|
408 | DATA_TYPE sin_half_angle = Math::sin( rad * (DATA_TYPE)0.5 ); |
---|
409 | if (sin_half_angle >= (DATA_TYPE)0.0001) // because (PI >= rad >= 0) |
---|
410 | { |
---|
411 | DATA_TYPE sin_half_angle_inv = DATA_TYPE(1.0) / sin_half_angle; |
---|
412 | Vec<DATA_TYPE, 3> axis( quat[Xelt] * sin_half_angle_inv, |
---|
413 | quat[Yelt] * sin_half_angle_inv, |
---|
414 | quat[Zelt] * sin_half_angle_inv ); |
---|
415 | normalize( axis ); |
---|
416 | axisAngle.setAxis( axis ); |
---|
417 | } |
---|
418 | |
---|
419 | // avoid NAN |
---|
420 | else |
---|
421 | { |
---|
422 | // one of the terms should be a 1, |
---|
423 | // so we can maintain unit-ness |
---|
424 | // in case w is 0 (which here w is 0) |
---|
425 | axisAngle.setAxis( gmtl::Vec<DATA_TYPE, 3>( |
---|
426 | DATA_TYPE( 1.0 ) /*- gmtl::Math::abs( quat[Welt] )*/, |
---|
427 | (DATA_TYPE)0.0, |
---|
428 | (DATA_TYPE)0.0 ) ); |
---|
429 | } |
---|
430 | return axisAngle; |
---|
431 | } |
---|
432 | |
---|
433 | /** Redundant duplication of the set(axisangle,quat) function, this is provided only for template compatibility. |
---|
434 | * unless you're writing template functions, you should use set(axisangle,quat) for clarity. |
---|
435 | */ |
---|
436 | template <typename DATA_TYPE> |
---|
437 | inline AxisAngle<DATA_TYPE>& setRot( AxisAngle<DATA_TYPE>& result, Quat<DATA_TYPE> quat ) |
---|
438 | { |
---|
439 | return gmtl::set( result, quat ); |
---|
440 | } |
---|
441 | |
---|
442 | /** make the axis of an AxisAngle normalized */ |
---|
443 | template <typename DATA_TYPE> |
---|
444 | AxisAngle<DATA_TYPE> makeNormal( const AxisAngle<DATA_TYPE>& a ) |
---|
445 | { |
---|
446 | return AxisAngle<DATA_TYPE>( a.getAngle(), makeNormal( a.getAxis() ) ); |
---|
447 | } |
---|
448 | /** @} */ |
---|
449 | |
---|
450 | /** @ingroup Generate |
---|
451 | * @name EulerAngle Generators |
---|
452 | * @{ |
---|
453 | */ |
---|
454 | |
---|
455 | /** Convert Matrix to EulerAngle. |
---|
456 | * Set the Euler Angle from the given rotation portion (3x3) of the matrix. |
---|
457 | * |
---|
458 | * @param input order, mat |
---|
459 | * @param output param0, param1, param2 |
---|
460 | * |
---|
461 | * @pre pass in your args in the same order as the RotationOrder you specify |
---|
462 | * @post this function only reads 3x3, 3x4, 4x3, and 4x4 matrices, and is undefined otherwise |
---|
463 | * NOTE: Angles are returned in radians (this is always true in GMTL). |
---|
464 | */ |
---|
465 | template< typename DATA_TYPE, unsigned ROWS, unsigned COLS, typename ROT_ORDER > |
---|
466 | inline EulerAngle<DATA_TYPE, ROT_ORDER>& set( EulerAngle<DATA_TYPE, ROT_ORDER>& euler, |
---|
467 | const Matrix<DATA_TYPE, ROWS, COLS>& mat ) |
---|
468 | { |
---|
469 | // @todo set this a compile time assert... |
---|
470 | gmtlASSERT( ROWS >= 3 && COLS >= 3 && ROWS <= 4 && COLS <= 4 && |
---|
471 | "this is undefined for Matrix smaller than 3x3 or bigger than 4x4" ); |
---|
472 | |
---|
473 | // @todo metaprogram this! |
---|
474 | const int& order = ROT_ORDER::ID; |
---|
475 | switch (order) |
---|
476 | { |
---|
477 | case XYZ::ID: |
---|
478 | { |
---|
479 | #if 0 |
---|
480 | euler[2] = Math::aTan2( -mat(0,1), mat(0,0) ); // -(-cy*sz)/(cy*cz) - cy falls out |
---|
481 | euler[0] = Math::aTan2( -mat(1,2), mat(2,2) ); // -(sx*cy)/(cx*cy) - cy falls out |
---|
482 | DATA_TYPE cz = Math::cos( euler[2] ); |
---|
483 | euler[1] = Math::aTan2( mat(0,2), mat(0,0) / cz ); // (sy)/((cy*cz)/cz) |
---|
484 | #else |
---|
485 | DATA_TYPE x(0), y(0), z(0); |
---|
486 | y = Math::aSin( mat(0,2)); |
---|
487 | if (y < gmtl::Math::PI_OVER_2) |
---|
488 | { |
---|
489 | if(y > -gmtl::Math::PI_OVER_2) |
---|
490 | { |
---|
491 | x = Math::aTan2(-mat(1,2),mat(2,2)); |
---|
492 | z = Math::aTan2(-mat(0,1),mat(0,0)); |
---|
493 | } |
---|
494 | else // Non-unique (x - z constant) |
---|
495 | { |
---|
496 | x = -Math::aTan2(mat(1,0), mat(1,1)); |
---|
497 | z = 0; |
---|
498 | } |
---|
499 | } |
---|
500 | else |
---|
501 | { |
---|
502 | // not unique (x + z constant) |
---|
503 | x = Math::aTan2(mat(1,0), mat(1,1)); |
---|
504 | z = 0; |
---|
505 | } |
---|
506 | euler[0] = x; |
---|
507 | euler[1] = y; |
---|
508 | euler[2] = z; |
---|
509 | |
---|
510 | #endif |
---|
511 | } |
---|
512 | break; |
---|
513 | case ZYX::ID: |
---|
514 | { |
---|
515 | #if 0 |
---|
516 | euler[0] = Math::aTan2( mat(1,0), mat(0,0) ); // (cy*sz)/(cy*cz) - cy falls out |
---|
517 | euler[2] = Math::aTan2( mat(2,1), mat(2,2) ); // (sx*cy)/(cx*cy) - cy falls out |
---|
518 | DATA_TYPE sx = Math::sin( euler[2] ); |
---|
519 | euler[1] = Math::aTan2( -mat(2,0), mat(2,1) / sx ); // -(-sy)/((sx*cy)/sx) |
---|
520 | #else |
---|
521 | DATA_TYPE x(0), y(0), z(0); |
---|
522 | |
---|
523 | y = Math::aSin(-mat(2,0)); |
---|
524 | if(y < Math::PI_OVER_2) |
---|
525 | { |
---|
526 | if(y>-Math::PI_OVER_2) |
---|
527 | { |
---|
528 | z = Math::aTan2(mat(1,0), mat(0,0)); |
---|
529 | x = Math::aTan2(mat(2,1), mat(2,2)); |
---|
530 | } |
---|
531 | else // not unique (x + z constant) |
---|
532 | { |
---|
533 | z = Math::aTan2(-mat(0,1),-mat(0,2)); |
---|
534 | x = 0; |
---|
535 | } |
---|
536 | } |
---|
537 | else // not unique (x - z constant) |
---|
538 | { |
---|
539 | z = -Math::aTan2(mat(0,1), mat(0,2)); |
---|
540 | x = 0; |
---|
541 | } |
---|
542 | euler[0] = z; |
---|
543 | euler[1] = y; |
---|
544 | euler[2] = x; |
---|
545 | #endif |
---|
546 | } |
---|
547 | break; |
---|
548 | case ZXY::ID: |
---|
549 | { |
---|
550 | #if 0 |
---|
551 | // Extract the rotation directly from the matrix |
---|
552 | DATA_TYPE x_angle; |
---|
553 | DATA_TYPE y_angle; |
---|
554 | DATA_TYPE z_angle; |
---|
555 | DATA_TYPE cos_y, sin_y; |
---|
556 | DATA_TYPE cos_x, sin_x; |
---|
557 | DATA_TYPE cos_z, sin_z; |
---|
558 | |
---|
559 | sin_x = mat(2,1); |
---|
560 | x_angle = Math::aSin( sin_x ); // Get x angle |
---|
561 | cos_x = Math::cos( x_angle ); |
---|
562 | |
---|
563 | // Check if cos_x = Zero |
---|
564 | if (cos_x != 0.0f) // ASSERT: cos_x != 0 |
---|
565 | { |
---|
566 | // Get y Angle |
---|
567 | cos_y = mat(2,2) / cos_x; |
---|
568 | sin_y = -mat(2,0) / cos_x; |
---|
569 | y_angle = Math::aTan2( cos_y, sin_y ); |
---|
570 | |
---|
571 | // Get z Angle |
---|
572 | cos_z = mat(1,1) / cos_x; |
---|
573 | sin_z = -mat(0,1) / cos_x; |
---|
574 | z_angle = Math::aTan2( cos_z, sin_z ); |
---|
575 | } |
---|
576 | else |
---|
577 | { |
---|
578 | // Arbitrarily set z_angle = 0 |
---|
579 | z_angle = 0; |
---|
580 | |
---|
581 | // Get y Angle |
---|
582 | cos_y = mat(0,0); |
---|
583 | sin_y = mat(1,0); |
---|
584 | y_angle = Math::aTan2( cos_y, sin_y ); |
---|
585 | } |
---|
586 | |
---|
587 | euler[1] = x_angle; |
---|
588 | euler[2] = y_angle; |
---|
589 | euler[0] = z_angle; |
---|
590 | #else |
---|
591 | DATA_TYPE x,y,z; |
---|
592 | |
---|
593 | x = Math::aSin(mat(2,1)); |
---|
594 | if(x < Math::PI_OVER_2) |
---|
595 | { |
---|
596 | if(x > -Math::PI_OVER_2) |
---|
597 | { |
---|
598 | z = Math::aTan2(-mat(0,1), mat(1,1)); |
---|
599 | y = Math::aTan2(-mat(2,0), mat(2,2)); |
---|
600 | } |
---|
601 | else // not unique (y - z constant) |
---|
602 | { |
---|
603 | z = -Math::aTan2(mat(0,2), mat(0,0)); |
---|
604 | y = 0; |
---|
605 | } |
---|
606 | } |
---|
607 | else // not unique (y + z constant) |
---|
608 | { |
---|
609 | z = Math::aTan2(mat(0,2), mat(0,0)); |
---|
610 | y = 0; |
---|
611 | } |
---|
612 | euler[0] = z; |
---|
613 | euler[1] = x; |
---|
614 | euler[2] = y; |
---|
615 | #endif |
---|
616 | } |
---|
617 | break; |
---|
618 | default: |
---|
619 | gmtlASSERT( false && "unknown rotation order passed to setRot" ); |
---|
620 | break; |
---|
621 | } |
---|
622 | return euler; |
---|
623 | } |
---|
624 | |
---|
625 | /** Redundant duplication of the set(eulerangle,quat) function, this is provided only for template compatibility. |
---|
626 | * unless you're writing template functions, you should use set(eulerangle,quat) for clarity. |
---|
627 | */ |
---|
628 | template< typename DATA_TYPE, unsigned ROWS, unsigned COLS, typename ROT_ORDER > |
---|
629 | inline EulerAngle<DATA_TYPE, ROT_ORDER>& setRot( EulerAngle<DATA_TYPE, ROT_ORDER>& result, const Matrix<DATA_TYPE, ROWS, COLS>& mat ) |
---|
630 | { |
---|
631 | return gmtl::set( result, mat ); |
---|
632 | } |
---|
633 | /** @} */ |
---|
634 | |
---|
635 | /** @ingroup Generate |
---|
636 | * @name Matrix Generators |
---|
637 | * @{ |
---|
638 | */ |
---|
639 | |
---|
640 | /** Set an arbitrary projection matrix |
---|
641 | * @result: set a projection matrix (similar to glFrustum). |
---|
642 | */ |
---|
643 | template <typename T > |
---|
644 | inline Matrix<T, 4,4>& setFrustum( Matrix<T, 4, 4>& result, |
---|
645 | T left, T top, T right, |
---|
646 | T bottom, T nr, T fr ) |
---|
647 | { |
---|
648 | result.mData[0] = ( T( 2.0 ) * nr ) / ( right - left ); |
---|
649 | result.mData[1] = T( 0.0 ); |
---|
650 | result.mData[2] = T( 0.0 ); |
---|
651 | result.mData[3] = T( 0.0 ); |
---|
652 | |
---|
653 | result.mData[4] = T( 0.0 ); |
---|
654 | result.mData[5] = ( T( 2.0 ) * nr ) / ( top - bottom ); |
---|
655 | result.mData[6] = T( 0.0 ); |
---|
656 | result.mData[7] = T( 0.0 ); |
---|
657 | |
---|
658 | result.mData[8] = ( right + left ) / ( right - left ); |
---|
659 | result.mData[9] = ( top + bottom ) / ( top - bottom ); |
---|
660 | result.mData[10] = -( fr + nr ) / ( fr - nr ); |
---|
661 | result.mData[11] = T( -1.0 ); |
---|
662 | |
---|
663 | result.mData[12] = T( 0.0 ); |
---|
664 | result.mData[13] = T( 0.0 ); |
---|
665 | result.mData[14] = -( T( 2.0 ) * fr * nr ) / ( fr - nr ); |
---|
666 | result.mData[15] = T( 0.0 ); |
---|
667 | |
---|
668 | result.mState = Matrix<T, 4, 4>::FULL; // track state |
---|
669 | |
---|
670 | return result; |
---|
671 | } |
---|
672 | |
---|
673 | /** Set an orthographic projection matrix |
---|
674 | * creates a transformation that produces a parallel projection matrix. |
---|
675 | * @nr = -nr is the value of the near clipping plane (positive value for near is negative in the z direction) |
---|
676 | * @fr = -fr is the value of the far clipping plane (positive value for far is negative in the z direction) |
---|
677 | * @result: set a orthographic matrix (similar to glOrtho). |
---|
678 | */ |
---|
679 | template <typename T > |
---|
680 | inline Matrix<T, 4,4>& setOrtho( Matrix<T,4,4>& result, |
---|
681 | T left, T top, T right, |
---|
682 | T bottom, T nr, T fr ) |
---|
683 | { |
---|
684 | result.mData[1] = result.mData[2] = result.mData[3] = |
---|
685 | result.mData[4] = result.mData[6] = result.mData[7] = |
---|
686 | result.mData[8] = result.mData[9] = result.mData[11] = T(0); |
---|
687 | |
---|
688 | T rl_inv = T(1) / (right - left); |
---|
689 | T tb_inv = T(1) / (top - bottom); |
---|
690 | T nf_inv = T(1) / (fr - nr); |
---|
691 | |
---|
692 | result.mData[0] = T(2) * rl_inv; |
---|
693 | result.mData[5] = T(2) * tb_inv; |
---|
694 | result.mData[10] = -T(2) * nf_inv; |
---|
695 | |
---|
696 | result.mData[12] = -(right + left) * rl_inv; |
---|
697 | result.mData[13] = -(top + bottom) * tb_inv; |
---|
698 | result.mData[14] = -(fr + nr) * nf_inv; |
---|
699 | result.mData[15] = T(1); |
---|
700 | |
---|
701 | return result; |
---|
702 | } |
---|
703 | |
---|
704 | /** Set a symmetric perspective projection matrix |
---|
705 | * @param fovy |
---|
706 | * The field of view angle, in degrees, about the y-axis. |
---|
707 | * @param aspect |
---|
708 | * The aspect ratio that determines the field of view about the x-axis. |
---|
709 | * The aspect ratio is the ratio of x (width) to y (height). |
---|
710 | * @param zNear |
---|
711 | * The distance from the viewer to the near clipping plane (always positive). |
---|
712 | * @param zFar |
---|
713 | * The distance from the viewer to the far clipping plane (always positive). |
---|
714 | * @result Set matrix to perspective transform |
---|
715 | */ |
---|
716 | template <typename T> |
---|
717 | inline Matrix<T, 4,4>& setPerspective( Matrix<T, 4, 4>& result, |
---|
718 | T fovy, T aspect, T nr, T fr ) |
---|
719 | { |
---|
720 | gmtlASSERT( nr > 0 && fr > nr && "invalid near and far values" ); |
---|
721 | T theta = Math::deg2Rad( fovy * T( 0.5 ) ); |
---|
722 | T tangentTheta = Math::tan( theta ); |
---|
723 | |
---|
724 | // tan(theta) = right / nr |
---|
725 | // top = tan(theta) * nr |
---|
726 | // right = tan(theta) * nr * aspect |
---|
727 | |
---|
728 | T top = tangentTheta * nr; |
---|
729 | T right = top * aspect; // aspect determines the fieald of view in the x-axis |
---|
730 | |
---|
731 | // TODO: args need to match... |
---|
732 | return setFrustum( result, -right, top, right, -top, nr, fr ); |
---|
733 | } |
---|
734 | |
---|
735 | |
---|
736 | /* |
---|
737 | template< typename DATA_TYPE, unsigned ROWS, unsigned COLS, unsigned SIZE, typename REP > |
---|
738 | inline Matrix<DATA_TYPE, ROWS, COLS>& setTrans( Matrix<DATA_TYPE, ROWS, COLS>& result, |
---|
739 | const VecBase<DATA_TYPE, SIZE, REP>& trans ) |
---|
740 | { |
---|
741 | const Vec<DATA_TYPE,SIZE,meta::DefaultVecTag> temp_vec(trans); |
---|
742 | return setTrans(result,trans); |
---|
743 | } |
---|
744 | */ |
---|
745 | |
---|
746 | /** Set matrix translation from vec. |
---|
747 | * @pre if making an n x n matrix, then for |
---|
748 | * - <b>vector is homogeneous:</b> SIZE of vector needs to equal number of Matrix ROWS - 1 |
---|
749 | * - <b>vector has scale component:</b> SIZE of vector needs to equal number of Matrix ROWS |
---|
750 | * if making an n x n+1 matrix, then for |
---|
751 | * - <b>vector is homogeneous:</b> SIZE of vector needs to equal number of Matrix ROWS |
---|
752 | * - <b>vector has scale component:</b> SIZE of vector needs to equal number of Matrix ROWS + 1 |
---|
753 | * @post if preconditions are not met, then function is undefined (will not compile) |
---|
754 | */ |
---|
755 | #ifdef GMTL_NO_METAPROG |
---|
756 | template< typename DATA_TYPE, unsigned ROWS, unsigned COLS, unsigned SIZE > |
---|
757 | inline Matrix<DATA_TYPE, ROWS, COLS>& setTrans( Matrix<DATA_TYPE, ROWS, COLS>& result, |
---|
758 | const VecBase<DATA_TYPE, SIZE>& trans ) |
---|
759 | #else |
---|
760 | template< typename DATA_TYPE, unsigned ROWS, unsigned COLS, unsigned SIZE, typename REP > |
---|
761 | inline Matrix<DATA_TYPE, ROWS, COLS>& setTrans( Matrix<DATA_TYPE, ROWS, COLS>& result, |
---|
762 | const VecBase<DATA_TYPE, SIZE, REP>& trans ) |
---|
763 | #endif |
---|
764 | { |
---|
765 | /* @todo make this a compile time assert... */ |
---|
766 | // if n x n then (homogeneous case) vecsize == rows-1 or (scale component case) vecsize == rows |
---|
767 | // if n x n+1 then (homogeneous case) vecsize == rows or (scale component case) vecsize == rows+1 |
---|
768 | gmtlASSERT( ((ROWS == COLS && (SIZE == (ROWS-1) || SIZE == ROWS)) || |
---|
769 | (COLS == (ROWS+1) && (SIZE == ROWS || SIZE == (ROWS+1)))) && |
---|
770 | "preconditions not met for vector size in call to makeTrans. Read your documentation." ); |
---|
771 | |
---|
772 | // homogeneous case... |
---|
773 | if ((ROWS == COLS && SIZE == ROWS) /* Square matrix and vec so assume homogeneous vector. ex. 4x4 with vec 4 */ |
---|
774 | || (COLS == (ROWS+1) && SIZE == (ROWS+1))) /* ex: 3x4 with vec4 */ |
---|
775 | { |
---|
776 | DATA_TYPE homog_val = trans[SIZE-1]; |
---|
777 | for (unsigned x = 0; x < COLS - 1; ++x) |
---|
778 | result( x, COLS - 1 ) = trans[x] / homog_val; |
---|
779 | } |
---|
780 | |
---|
781 | // non-homogeneous case... |
---|
782 | else |
---|
783 | { |
---|
784 | for (unsigned x = 0; x < COLS - 1; ++x) |
---|
785 | result( x, COLS - 1 ) = trans[x]; |
---|
786 | } |
---|
787 | // track state, only override identity |
---|
788 | switch (result.mState) |
---|
789 | { |
---|
790 | case Matrix<DATA_TYPE, ROWS, COLS>::ORTHOGONAL: result.mState = Matrix<DATA_TYPE, ROWS, COLS>::AFFINE; break; |
---|
791 | case Matrix<DATA_TYPE, ROWS, COLS>::IDENTITY: result.mState = Matrix<DATA_TYPE, ROWS, COLS>::TRANS; break; |
---|
792 | } |
---|
793 | return result; |
---|
794 | } |
---|
795 | |
---|
796 | /** Set the scale part of a matrix. |
---|
797 | */ |
---|
798 | template< typename DATA_TYPE, unsigned ROWS, unsigned COLS, unsigned SIZE > |
---|
799 | inline Matrix<DATA_TYPE, ROWS, COLS>& setScale( Matrix<DATA_TYPE, ROWS, COLS>& result, const Vec<DATA_TYPE, SIZE>& scale ) |
---|
800 | { |
---|
801 | gmtlASSERT( ((SIZE == (ROWS-1) && SIZE == (COLS-1)) || (SIZE == (ROWS-1) && SIZE == COLS) || (SIZE == (COLS-1) && SIZE == ROWS)) && "the scale params must fit within the matrix, check your sizes." ); |
---|
802 | for (unsigned x = 0; x < SIZE; ++x) |
---|
803 | { |
---|
804 | result( x, x ) = scale[x]; |
---|
805 | } |
---|
806 | // track state: affine matrix with non-uniform scale now. |
---|
807 | result.mState = Matrix<DATA_TYPE, ROWS, COLS>::AFFINE; |
---|
808 | result.mState |= Matrix<DATA_TYPE, ROWS, COLS>::NON_UNISCALE; |
---|
809 | return result; |
---|
810 | } |
---|
811 | |
---|
812 | /** Sets the scale part of a matrix. |
---|
813 | */ |
---|
814 | template< typename DATA_TYPE, unsigned ROWS, unsigned COLS > |
---|
815 | inline Matrix<DATA_TYPE, ROWS, COLS>& setScale( Matrix<DATA_TYPE, ROWS, COLS>& result, const DATA_TYPE scale ) |
---|
816 | { |
---|
817 | for (unsigned x = 0; x < Math::Min( ROWS, COLS, Math::Max( ROWS, COLS ) - 1 ); ++x) // account for 2x4 or other weird sizes... |
---|
818 | { |
---|
819 | result( x, x ) = scale; |
---|
820 | } |
---|
821 | // track state: affine matrix with non-uniform scale now. |
---|
822 | result.mState = Matrix<DATA_TYPE, ROWS, COLS>::AFFINE; |
---|
823 | result.mState |= Matrix<DATA_TYPE, ROWS, COLS>::NON_UNISCALE; |
---|
824 | return result; |
---|
825 | } |
---|
826 | |
---|
827 | /** Create a scale matrix. |
---|
828 | * @param scale You'll typically pass in a Vec or a float here. |
---|
829 | * @seealso setScale() for all possible argument types for this function. |
---|
830 | */ |
---|
831 | template <typename MATRIX_TYPE, typename INPUT_TYPE> |
---|
832 | inline MATRIX_TYPE makeScale( const INPUT_TYPE& scale, |
---|
833 | Type2Type< MATRIX_TYPE > t = Type2Type< MATRIX_TYPE >() ) |
---|
834 | { |
---|
835 | gmtl::ignore_unused_variable_warning(t); |
---|
836 | MATRIX_TYPE temporary; |
---|
837 | return setScale( temporary, scale ); |
---|
838 | } |
---|
839 | |
---|
840 | /** Set the rotation portion of a rotation matrix using an axis and an angle (in radians). |
---|
841 | * Only writes to the rotation matrix (3x3) defined by the rotation part of M |
---|
842 | * @post this function only writes to 3x3, 3x4, 4x3, and 4x4 matrices, and is undefined otherwise |
---|
843 | * @pre you must pass a normalized vector in for the axis, results are undefined if not. |
---|
844 | */ |
---|
845 | template< typename DATA_TYPE, unsigned ROWS, unsigned COLS > |
---|
846 | inline Matrix<DATA_TYPE, ROWS, COLS>& setRot( Matrix<DATA_TYPE, ROWS, COLS>& result, const AxisAngle<DATA_TYPE>& axisAngle ) |
---|
847 | { |
---|
848 | /* @todo set this a compile time assert... */ |
---|
849 | gmtlASSERT( ROWS >= 3 && COLS >= 3 && ROWS <= 4 && COLS <= 4 && |
---|
850 | "this func is undefined for Matrix smaller than 3x3 or bigger than 4x4" ); |
---|
851 | gmtlASSERT( Math::isEqual( lengthSquared( axisAngle.getAxis() ), (DATA_TYPE)1.0, (DATA_TYPE)0.001 ) /* && |
---|
852 | "you must pass in a normalized vector to setRot( mat, rad, vec )" */ ); |
---|
853 | |
---|
854 | // GGI: pg 466 |
---|
855 | DATA_TYPE s = Math::sin( axisAngle.getAngle() ); |
---|
856 | DATA_TYPE c = Math::cos( axisAngle.getAngle() ); |
---|
857 | DATA_TYPE t = DATA_TYPE( 1.0 ) - c; |
---|
858 | DATA_TYPE x = axisAngle.getAxis()[0]; |
---|
859 | DATA_TYPE y = axisAngle.getAxis()[1]; |
---|
860 | DATA_TYPE z = axisAngle.getAxis()[2]; |
---|
861 | |
---|
862 | /* From: Introduction to robotic. Craig. Pg. 52 */ |
---|
863 | result( 0, 0 ) = (t*x*x)+c; result( 0, 1 ) = (t*x*y)-(s*z); result( 0, 2 ) = (t*x*z)+(s*y); |
---|
864 | result( 1, 0 ) = (t*x*y)+(s*z); result( 1, 1 ) = (t*y*y)+c; result( 1, 2 ) = (t*y*z)-(s*x); |
---|
865 | result( 2, 0 ) = (t*x*z)-(s*y); result( 2, 1 ) = (t*y*z)+(s*x); result( 2, 2 ) = (t*z*z)+c; |
---|
866 | |
---|
867 | // track state |
---|
868 | switch (result.mState) |
---|
869 | { |
---|
870 | case Matrix<DATA_TYPE, ROWS, COLS>::TRANS: result.mState = Matrix<DATA_TYPE, ROWS, COLS>::AFFINE; break; |
---|
871 | case Matrix<DATA_TYPE, ROWS, COLS>::IDENTITY: result.mState = Matrix<DATA_TYPE, ROWS, COLS>::ORTHOGONAL; break; |
---|
872 | } |
---|
873 | return result; |
---|
874 | } |
---|
875 | |
---|
876 | /** Set (only) the rotation part of a matrix using an EulerAngle (angles are in radians). |
---|
877 | * @post this function only produces 3x3, 3x4, 4x3, and 4x4 matrices, and is undefined otherwise |
---|
878 | * @see EulerAngle for angle ordering (usually ordered based on RotationOrder) |
---|
879 | */ |
---|
880 | template< typename DATA_TYPE, unsigned ROWS, unsigned COLS, typename ROT_ORDER > |
---|
881 | inline Matrix<DATA_TYPE, ROWS, COLS>& setRot( Matrix<DATA_TYPE, ROWS, COLS>& result, const EulerAngle<DATA_TYPE, ROT_ORDER>& euler ) |
---|
882 | { |
---|
883 | // @todo set this a compile time assert... |
---|
884 | gmtlASSERT( ROWS >= 3 && COLS >= 3 && ROWS <= 4 && COLS <= 4 && "this is undefined for Matrix smaller than 3x3 or bigger than 4x4" ); |
---|
885 | |
---|
886 | // this might be faster if put into the switch statement... (testme) |
---|
887 | const int& order = ROT_ORDER::ID; |
---|
888 | const DATA_TYPE xRot = (order == XYZ::ID) ? euler[0] : ((order == ZXY::ID) ? euler[1] : euler[2]); |
---|
889 | const DATA_TYPE yRot = (order == XYZ::ID) ? euler[1] : ((order == ZXY::ID) ? euler[2] : euler[1]); |
---|
890 | const DATA_TYPE zRot = (order == XYZ::ID) ? euler[2] : ((order == ZXY::ID) ? euler[0] : euler[0]); |
---|
891 | |
---|
892 | DATA_TYPE sx = Math::sin( xRot ); DATA_TYPE cx = Math::cos( xRot ); |
---|
893 | DATA_TYPE sy = Math::sin( yRot ); DATA_TYPE cy = Math::cos( yRot ); |
---|
894 | DATA_TYPE sz = Math::sin( zRot ); DATA_TYPE cz = Math::cos( zRot ); |
---|
895 | |
---|
896 | // @todo metaprogram this! |
---|
897 | switch (order) |
---|
898 | { |
---|
899 | case XYZ::ID: |
---|
900 | // Derived by simply multiplying out the matrices by hand X * Y * Z |
---|
901 | result( 0, 0 ) = cy*cz; result( 0, 1 ) = -cy*sz; result( 0, 2 ) = sy; |
---|
902 | result( 1, 0 ) = sx*sy*cz + cx*sz; result( 1, 1 ) = -sx*sy*sz + cx*cz; result( 1, 2 ) = -sx*cy; |
---|
903 | result( 2, 0 ) = -cx*sy*cz + sx*sz; result( 2, 1 ) = cx*sy*sz + sx*cz; result( 2, 2 ) = cx*cy; |
---|
904 | break; |
---|
905 | case ZYX::ID: |
---|
906 | // Derived by simply multiplying out the matrices by hand Z * Y * Z |
---|
907 | result( 0, 0 ) = cy*cz; result( 0, 1 ) = -cx*sz + sx*sy*cz; result( 0, 2 ) = sx*sz + cx*sy*cz; |
---|
908 | result( 1, 0 ) = cy*sz; result( 1, 1 ) = cx*cz + sx*sy*sz; result( 1, 2 ) = -sx*cz + cx*sy*sz; |
---|
909 | result( 2, 0 ) = -sy; result( 2, 1 ) = sx*cy; result( 2, 2 ) = cx*cy; |
---|
910 | break; |
---|
911 | case ZXY::ID: |
---|
912 | // Derived by simply multiplying out the matrices by hand Z * X * Y |
---|
913 | result( 0, 0 ) = cy*cz - sx*sy*sz; result( 0, 1 ) = -cx*sz; result( 0, 2 ) = sy*cz + sx*cy*sz; |
---|
914 | result( 1, 0 ) = cy*sz + sx*sy*cz; result( 1, 1 ) = cx*cz; result( 1, 2 ) = sy*sz - sx*cy*cz; |
---|
915 | result( 2, 0 ) = -cx*sy; result( 2, 1 ) = sx; result( 2, 2 ) = cx*cy; |
---|
916 | break; |
---|
917 | default: |
---|
918 | gmtlASSERT( false && "unknown rotation order passed to setRot" ); |
---|
919 | break; |
---|
920 | } |
---|
921 | |
---|
922 | // track state |
---|
923 | switch (result.mState) |
---|
924 | { |
---|
925 | case Matrix<DATA_TYPE, ROWS, COLS>::TRANS: result.mState = Matrix<DATA_TYPE, ROWS, COLS>::AFFINE; break; |
---|
926 | case Matrix<DATA_TYPE, ROWS, COLS>::IDENTITY: result.mState = Matrix<DATA_TYPE, ROWS, COLS>::ORTHOGONAL; break; |
---|
927 | } |
---|
928 | return result; |
---|
929 | } |
---|
930 | |
---|
931 | /** Convert an AxisAngle to a rotation matrix. |
---|
932 | * @post this function only writes to 3x3, 3x4, 4x3, and 4x4 matrices, and is undefined otherwise |
---|
933 | * @pre AxisAngle must be normalized (the axis part), results are undefined if not. |
---|
934 | */ |
---|
935 | template< typename DATA_TYPE, unsigned ROWS, unsigned COLS > |
---|
936 | inline Matrix<DATA_TYPE, ROWS, COLS>& set( Matrix<DATA_TYPE, ROWS, COLS>& result, const AxisAngle<DATA_TYPE>& axisAngle ) |
---|
937 | { |
---|
938 | gmtl::identity( result ); |
---|
939 | return setRot( result, axisAngle ); |
---|
940 | } |
---|
941 | |
---|
942 | /** Convert an EulerAngle to a rotation matrix. |
---|
943 | * @post this function only writes to 3x3, 3x4, 4x3, and 4x4 matrices, and is undefined otherwise |
---|
944 | */ |
---|
945 | template< typename DATA_TYPE, unsigned ROWS, unsigned COLS, typename ROT_ORDER > |
---|
946 | inline Matrix<DATA_TYPE, ROWS, COLS>& set( Matrix<DATA_TYPE, ROWS, COLS>& result, const EulerAngle<DATA_TYPE, ROT_ORDER>& euler ) |
---|
947 | { |
---|
948 | gmtl::identity( result ); |
---|
949 | return setRot( result, euler ); |
---|
950 | } |
---|
951 | |
---|
952 | /** |
---|
953 | * Extracts the Y axis rotation information from the matrix. |
---|
954 | * @post Returned value is from -PI to PI, where 0 is none. |
---|
955 | */ |
---|
956 | template< typename DATA_TYPE, unsigned ROWS, unsigned COLS > |
---|
957 | inline DATA_TYPE makeYRot( const Matrix<DATA_TYPE, ROWS, COLS>& mat ) |
---|
958 | { |
---|
959 | const gmtl::Vec<DATA_TYPE, 3> forward_point(0.0f, 0.0f, -1.0f); // -Z |
---|
960 | const gmtl::Vec<DATA_TYPE, 3> origin_point(0.0f, 0.0f, 0.0f); |
---|
961 | gmtl::Vec<DATA_TYPE, 3> end_point, start_point; |
---|
962 | |
---|
963 | gmtl::xform(end_point, mat, forward_point); |
---|
964 | gmtl::xform(start_point, mat, origin_point); |
---|
965 | gmtl::Vec<DATA_TYPE, 3> direction_vector = end_point - start_point; |
---|
966 | |
---|
967 | // Constrain the direction to XZ-plane only. |
---|
968 | direction_vector[1] = 0.0f; // Eliminate Y value |
---|
969 | gmtl::normalize(direction_vector); |
---|
970 | DATA_TYPE y_rot = gmtl::Math::aCos(gmtl::dot(direction_vector, |
---|
971 | forward_point)); |
---|
972 | |
---|
973 | gmtl::Vec<DATA_TYPE, 3> which_side = gmtl::makeCross(forward_point, |
---|
974 | direction_vector); |
---|
975 | |
---|
976 | // If direction vector to "right" (negative) side of forward |
---|
977 | if ( which_side[1] < 0.0f ) |
---|
978 | { |
---|
979 | y_rot = -y_rot; |
---|
980 | } |
---|
981 | |
---|
982 | return y_rot; |
---|
983 | } |
---|
984 | |
---|
985 | /** |
---|
986 | * Extracts the X-axis rotation information from the matrix. |
---|
987 | * @post Returned value is from -PI to PI, where 0 is no rotation. |
---|
988 | */ |
---|
989 | template< typename DATA_TYPE, unsigned ROWS, unsigned COLS > |
---|
990 | inline DATA_TYPE makeXRot( const Matrix<DATA_TYPE, ROWS, COLS>& mat ) |
---|
991 | { |
---|
992 | const gmtl::Vec<DATA_TYPE, 3> forward_point(0.0f, 0.0f, -1.0f); // -Z |
---|
993 | const gmtl::Vec<DATA_TYPE, 3> origin_point(0.0f, 0.0f, 0.0f); |
---|
994 | gmtl::Vec<DATA_TYPE, 3> end_point, start_point; |
---|
995 | |
---|
996 | gmtl::xform(end_point, mat, forward_point); |
---|
997 | gmtl::xform(start_point, mat, origin_point); |
---|
998 | gmtl::Vec<DATA_TYPE, 3> direction_vector = end_point - start_point; |
---|
999 | |
---|
1000 | // Constrain the direction to YZ-plane only. |
---|
1001 | direction_vector[0] = 0.0f; // Eliminate X value |
---|
1002 | gmtl::normalize(direction_vector); |
---|
1003 | DATA_TYPE x_rot = gmtl::Math::aCos(gmtl::dot(direction_vector, |
---|
1004 | forward_point)); |
---|
1005 | |
---|
1006 | gmtl::Vec<DATA_TYPE, 3> which_side = gmtl::makeCross(forward_point, |
---|
1007 | direction_vector); |
---|
1008 | |
---|
1009 | // If direction vector to "bottom" (negative) side of forward |
---|
1010 | if ( which_side[0] < 0.0f ) |
---|
1011 | { |
---|
1012 | x_rot = -x_rot; |
---|
1013 | } |
---|
1014 | |
---|
1015 | return x_rot; |
---|
1016 | } |
---|
1017 | |
---|
1018 | /** |
---|
1019 | * Extracts the Z-axis rotation information from the matrix. |
---|
1020 | * @post Returned value is from -PI to PI, where 0 is no rotation. |
---|
1021 | */ |
---|
1022 | template< typename DATA_TYPE, unsigned ROWS, unsigned COLS > |
---|
1023 | inline DATA_TYPE makeZRot( const Matrix<DATA_TYPE, ROWS, COLS>& mat ) |
---|
1024 | { |
---|
1025 | const gmtl::Vec<DATA_TYPE, 3> forward_point(1.0f, 0.0f, 0.0f); // +x |
---|
1026 | const gmtl::Vec<DATA_TYPE, 3> origin_point(0.0f, 0.0f, 0.0f); |
---|
1027 | gmtl::Vec<DATA_TYPE, 3> end_point, start_point; |
---|
1028 | |
---|
1029 | gmtl::xform(end_point, mat, forward_point); |
---|
1030 | gmtl::xform(start_point, mat, origin_point); |
---|
1031 | gmtl::Vec<DATA_TYPE, 3> direction_vector = end_point - start_point; |
---|
1032 | |
---|
1033 | // Constrain the direction to XY-plane only. |
---|
1034 | direction_vector[2] = 0.0f; // Eliminate Z value |
---|
1035 | gmtl::normalize(direction_vector); |
---|
1036 | DATA_TYPE z_rot = gmtl::Math::aCos(gmtl::dot(direction_vector, |
---|
1037 | forward_point)); |
---|
1038 | |
---|
1039 | gmtl::Vec<DATA_TYPE, 3> which_side = gmtl::makeCross(forward_point, |
---|
1040 | direction_vector); |
---|
1041 | |
---|
1042 | // If direction vector to "right" (negative) side of forward |
---|
1043 | if ( which_side[2] < 0.0f ) |
---|
1044 | { |
---|
1045 | z_rot = -z_rot; |
---|
1046 | } |
---|
1047 | |
---|
1048 | return z_rot; |
---|
1049 | } |
---|
1050 | |
---|
1051 | /** create a rotation matrix that will rotate from SrcAxis to DestAxis. |
---|
1052 | * xSrcAxis, ySrcAxis, zSrcAxis is the base rotation to go from and defaults to xSrcAxis(1,0,0), ySrcAxis(0,1,0), zSrcAxis(0,0,1) if you only pass in 3 axes. |
---|
1053 | * |
---|
1054 | * If the two coordinate frames are labeled: SRC and TARGET, the matrix produced is: src_M_target |
---|
1055 | * this means that it will transform a point in TARGET to SRC but moves the base frame from SRC to TARGET. |
---|
1056 | * |
---|
1057 | * @pre pass in 3 axes, and setDirCos will give you the rotation from MATRIX_IDENTITY to DestAxis |
---|
1058 | * @pre pass in 6 axes, and setDirCos will give you the rotation from your 3-axis rotation to your second 3-axis rotation |
---|
1059 | * @post this function only produces 3x3, 3x4, 4x3, and 4x4 matrices |
---|
1060 | */ |
---|
1061 | template< typename DATA_TYPE, unsigned ROWS, unsigned COLS > |
---|
1062 | inline Matrix<DATA_TYPE, ROWS, COLS>& setDirCos( Matrix<DATA_TYPE, ROWS, COLS>& result, |
---|
1063 | const Vec<DATA_TYPE, 3>& xDestAxis, |
---|
1064 | const Vec<DATA_TYPE, 3>& yDestAxis, const Vec<DATA_TYPE, 3>& zDestAxis, |
---|
1065 | const Vec<DATA_TYPE, 3>& xSrcAxis = Vec<DATA_TYPE, 3>(1,0,0), |
---|
1066 | const Vec<DATA_TYPE, 3>& ySrcAxis = Vec<DATA_TYPE, 3>(0,1,0), |
---|
1067 | const Vec<DATA_TYPE, 3>& zSrcAxis = Vec<DATA_TYPE, 3>(0,0,1) ) |
---|
1068 | { |
---|
1069 | // @todo set this a compile time assert... |
---|
1070 | gmtlASSERT( ROWS >= 3 && COLS >= 3 && ROWS <= 4 && COLS <= 4 && "this is undefined for Matrix smaller than 3x3 or bigger than 4x4" ); |
---|
1071 | |
---|
1072 | DATA_TYPE Xa, Xb, Xc; // Direction cosines of the secondary x-axis |
---|
1073 | DATA_TYPE Ya, Yb, Yc; // Direction cosines of the secondary y-axis |
---|
1074 | DATA_TYPE Za, Zb, Zc; // Direction cosines of the secondary z-axis |
---|
1075 | |
---|
1076 | Xa = dot(xDestAxis, xSrcAxis); Xb = dot(xDestAxis, ySrcAxis); Xc = dot(xDestAxis, zSrcAxis); |
---|
1077 | Ya = dot(yDestAxis, xSrcAxis); Yb = dot(yDestAxis, ySrcAxis); Yc = dot(yDestAxis, zSrcAxis); |
---|
1078 | Za = dot(zDestAxis, xSrcAxis); Zb = dot(zDestAxis, ySrcAxis); Zc = dot(zDestAxis, zSrcAxis); |
---|
1079 | |
---|
1080 | // Set the matrix correctly |
---|
1081 | result( 0, 0 ) = Xa; result( 0, 1 ) = Ya; result( 0, 2 ) = Za; |
---|
1082 | result( 1, 0 ) = Xb; result( 1, 1 ) = Yb; result( 1, 2 ) = Zb; |
---|
1083 | result( 2, 0 ) = Xc; result( 2, 1 ) = Yc; result( 2, 2 ) = Zc; |
---|
1084 | |
---|
1085 | // track state |
---|
1086 | switch (result.mState) |
---|
1087 | { |
---|
1088 | case Matrix<DATA_TYPE, ROWS, COLS>::TRANS: result.mState = Matrix<DATA_TYPE, ROWS, COLS>::AFFINE; break; |
---|
1089 | case Matrix<DATA_TYPE, ROWS, COLS>::IDENTITY: result.mState = Matrix<DATA_TYPE, ROWS, COLS>::ORTHOGONAL; break; |
---|
1090 | } |
---|
1091 | |
---|
1092 | return result; |
---|
1093 | } |
---|
1094 | |
---|
1095 | /** set the matrix given the raw coordinate axes. |
---|
1096 | * @post this function only produces 3x3, 3x4, 4x3, and 4x4 matrices, and is undefined otherwise |
---|
1097 | * @post these axes are copied direct to the 3x3 in the matrix |
---|
1098 | */ |
---|
1099 | template< typename DATA_TYPE, unsigned ROWS, unsigned COLS > |
---|
1100 | inline Matrix<DATA_TYPE, ROWS, COLS>& setAxes( Matrix<DATA_TYPE, ROWS, COLS>& result, |
---|
1101 | const Vec<DATA_TYPE, 3>& xAxis, |
---|
1102 | const Vec<DATA_TYPE, 3>& yAxis, |
---|
1103 | const Vec<DATA_TYPE, 3>& zAxis ) |
---|
1104 | { |
---|
1105 | // @todo set this a compile time assert... |
---|
1106 | gmtlASSERT( ROWS >= 3 && COLS >= 3 && ROWS <= 4 && COLS <= 4 && "this is undefined for Matrix smaller than 3x3 or bigger than 4x4" ); |
---|
1107 | |
---|
1108 | result( 0, 0 ) = xAxis[0]; |
---|
1109 | result( 1, 0 ) = xAxis[1]; |
---|
1110 | result( 2, 0 ) = xAxis[2]; |
---|
1111 | |
---|
1112 | result( 0, 1 ) = yAxis[0]; |
---|
1113 | result( 1, 1 ) = yAxis[1]; |
---|
1114 | result( 2, 1 ) = yAxis[2]; |
---|
1115 | |
---|
1116 | result( 0, 2 ) = zAxis[0]; |
---|
1117 | result( 1, 2 ) = zAxis[1]; |
---|
1118 | result( 2, 2 ) = zAxis[2]; |
---|
1119 | |
---|
1120 | // track state |
---|
1121 | switch (result.mState) |
---|
1122 | { |
---|
1123 | case Matrix<DATA_TYPE, ROWS, COLS>::TRANS: result.mState = Matrix<DATA_TYPE, ROWS, COLS>::AFFINE; break; |
---|
1124 | case Matrix<DATA_TYPE, ROWS, COLS>::IDENTITY: result.mState = Matrix<DATA_TYPE, ROWS, COLS>::ORTHOGONAL; break; |
---|
1125 | } |
---|
1126 | return result; |
---|
1127 | } |
---|
1128 | |
---|
1129 | /** set the matrix given the raw coordinate axes. |
---|
1130 | * @post this function only produces 3x3, 3x4, 4x3, and 4x4 matrices, and is undefined otherwise |
---|
1131 | * @post these axes are copied direct to the 3x3 in the matrix |
---|
1132 | */ |
---|
1133 | template< typename ROTATION_TYPE > |
---|
1134 | inline ROTATION_TYPE makeAxes( const Vec<typename ROTATION_TYPE::DataType, 3>& xAxis, |
---|
1135 | const Vec<typename ROTATION_TYPE::DataType, 3>& yAxis, |
---|
1136 | const Vec<typename ROTATION_TYPE::DataType, 3>& zAxis, |
---|
1137 | Type2Type< ROTATION_TYPE > t = Type2Type< ROTATION_TYPE >() ) |
---|
1138 | { |
---|
1139 | gmtl::ignore_unused_variable_warning(t); |
---|
1140 | ROTATION_TYPE temporary; |
---|
1141 | return setAxes( temporary, xAxis, yAxis, zAxis ); |
---|
1142 | } |
---|
1143 | |
---|
1144 | /** create a matrix transposed from the source. |
---|
1145 | * @post returns the transpose of m |
---|
1146 | * @see Quat |
---|
1147 | */ |
---|
1148 | template < typename DATA_TYPE, unsigned ROWS, unsigned COLS > |
---|
1149 | inline Matrix<DATA_TYPE, ROWS, COLS> makeTranspose( const Matrix<DATA_TYPE, ROWS, COLS>& m ) |
---|
1150 | { |
---|
1151 | Matrix<DATA_TYPE, ROWS, COLS> temporary( m ); |
---|
1152 | return transpose( temporary ); |
---|
1153 | } |
---|
1154 | |
---|
1155 | /** |
---|
1156 | * Creates a matrix that is the inverse of the given source matrix. |
---|
1157 | * |
---|
1158 | * @param src the matrix to compute the inverse of |
---|
1159 | * |
---|
1160 | * @return the inverse of source |
---|
1161 | */ |
---|
1162 | template< typename DATA_TYPE, unsigned ROWS, unsigned COLS > |
---|
1163 | inline Matrix<DATA_TYPE, ROWS, COLS> makeInvert(const Matrix<DATA_TYPE, ROWS, COLS>& src) |
---|
1164 | { |
---|
1165 | Matrix<DATA_TYPE, ROWS, COLS> result; |
---|
1166 | return invert( result, src ); |
---|
1167 | } |
---|
1168 | |
---|
1169 | /** Set the rotation portion of a matrix (3x3) from a rotation quaternion. |
---|
1170 | * @pre only 3x3, 3x4, 4x3, or 4x4 matrices are allowed, function is undefined otherwise. |
---|
1171 | */ |
---|
1172 | template <typename DATA_TYPE, unsigned ROWS, unsigned COLS> |
---|
1173 | Matrix<DATA_TYPE, ROWS, COLS>& setRot( Matrix<DATA_TYPE, ROWS, COLS>& mat, const Quat<DATA_TYPE>& q ) |
---|
1174 | { |
---|
1175 | gmtlASSERT( ((ROWS == 3 && COLS == 3) || |
---|
1176 | (ROWS == 3 && COLS == 4) || |
---|
1177 | (ROWS == 4 && COLS == 3) || |
---|
1178 | (ROWS == 4 && COLS == 4)) && |
---|
1179 | "pre conditions not met on set( mat, quat ) which only sets a quaternion to the rotation part of a 3x3, 3x4, 4x3, or 4x4 matrix." ); |
---|
1180 | |
---|
1181 | // From Watt & Watt |
---|
1182 | DATA_TYPE wx, wy, wz, xx, yy, yz, xy, xz, zz, xs, ys, zs; |
---|
1183 | |
---|
1184 | xs = q[Xelt] + q[Xelt]; ys = q[Yelt] + q[Yelt]; zs = q[Zelt] + q[Zelt]; |
---|
1185 | xx = q[Xelt] * xs; xy = q[Xelt] * ys; xz = q[Xelt] * zs; |
---|
1186 | yy = q[Yelt] * ys; yz = q[Yelt] * zs; zz = q[Zelt] * zs; |
---|
1187 | wx = q[Welt] * xs; wy = q[Welt] * ys; wz = q[Welt] * zs; |
---|
1188 | |
---|
1189 | mat( 0, 0 ) = DATA_TYPE(1.0) - (yy + zz); |
---|
1190 | mat( 1, 0 ) = xy + wz; |
---|
1191 | mat( 2, 0 ) = xz - wy; |
---|
1192 | |
---|
1193 | mat( 0, 1 ) = xy - wz; |
---|
1194 | mat( 1, 1 ) = DATA_TYPE(1.0) - (xx + zz); |
---|
1195 | mat( 2, 1 ) = yz + wx; |
---|
1196 | |
---|
1197 | mat( 0, 2 ) = xz + wy; |
---|
1198 | mat( 1, 2 ) = yz - wx; |
---|
1199 | mat( 2, 2 ) = DATA_TYPE(1.0) - (xx + yy); |
---|
1200 | |
---|
1201 | // track state |
---|
1202 | switch (mat.mState) |
---|
1203 | { |
---|
1204 | case Matrix<DATA_TYPE, ROWS, COLS>::TRANS: mat.mState = Matrix<DATA_TYPE, ROWS, COLS>::AFFINE; break; |
---|
1205 | case Matrix<DATA_TYPE, ROWS, COLS>::IDENTITY: mat.mState = Matrix<DATA_TYPE, ROWS, COLS>::ORTHOGONAL; break; |
---|
1206 | } |
---|
1207 | return mat; |
---|
1208 | } |
---|
1209 | |
---|
1210 | /** Convert a Coord to a Matrix |
---|
1211 | * Note: It is set directly, but this is equivalent to T*R where T is the translation matrix and R is the rotation matrix. |
---|
1212 | * @see Coord |
---|
1213 | * @see Matrix |
---|
1214 | */ |
---|
1215 | template <typename DATATYPE, typename POS_TYPE, typename ROT_TYPE, unsigned MATCOLS, unsigned MATROWS > |
---|
1216 | inline Matrix<DATATYPE, MATROWS, MATCOLS>& set( Matrix<DATATYPE, MATROWS, MATCOLS>& mat, |
---|
1217 | const Coord<POS_TYPE, ROT_TYPE>& coord ) |
---|
1218 | { |
---|
1219 | // set to ident first... |
---|
1220 | gmtl::identity( mat ); |
---|
1221 | |
---|
1222 | // set translation |
---|
1223 | // @todo metaprogram this out for 3x3 and 2x2 matrices |
---|
1224 | if (MATCOLS == 4) |
---|
1225 | { |
---|
1226 | setTrans( mat, coord.getPos() );// filtered (only sets the trans part). |
---|
1227 | } |
---|
1228 | setRot( mat, coord.getRot() ); // filtered (only sets the rot part). |
---|
1229 | return mat; |
---|
1230 | } |
---|
1231 | |
---|
1232 | /** Convert a Quat to a rotation Matrix. |
---|
1233 | * @pre only 3x3, 3x4, 4x3, or 4x4 matrices are allowed, function is undefined otherwise. |
---|
1234 | * @post Matrix is entirely overwritten. |
---|
1235 | * @todo Implement using setRot |
---|
1236 | */ |
---|
1237 | template <typename DATA_TYPE, unsigned ROWS, unsigned COLS> |
---|
1238 | Matrix<DATA_TYPE, ROWS, COLS>& set( Matrix<DATA_TYPE, ROWS, COLS>& mat, const Quat<DATA_TYPE>& q ) |
---|
1239 | { |
---|
1240 | if (ROWS == 4) |
---|
1241 | { |
---|
1242 | mat( 3, 0 ) = DATA_TYPE(0.0); |
---|
1243 | mat( 3, 1 ) = DATA_TYPE(0.0); |
---|
1244 | mat( 3, 2 ) = DATA_TYPE(0.0); |
---|
1245 | } |
---|
1246 | |
---|
1247 | if (COLS == 4) |
---|
1248 | { |
---|
1249 | mat( 0, 3 ) = DATA_TYPE(0.0); |
---|
1250 | mat( 1, 3 ) = DATA_TYPE(0.0); |
---|
1251 | mat( 2, 3 ) = DATA_TYPE(0.0); |
---|
1252 | } |
---|
1253 | |
---|
1254 | if (ROWS == 4 && COLS == 4) |
---|
1255 | mat( 3, 3 ) = DATA_TYPE(1.0); |
---|
1256 | |
---|
1257 | // track state |
---|
1258 | mat.mState = Matrix<DATA_TYPE, ROWS, COLS>::IDENTITY; |
---|
1259 | |
---|
1260 | return setRot( mat, q ); |
---|
1261 | } |
---|
1262 | |
---|
1263 | /** @} */ |
---|
1264 | |
---|
1265 | /** @ingroup Generate |
---|
1266 | * @name Coord Generators |
---|
1267 | * @{ |
---|
1268 | */ |
---|
1269 | |
---|
1270 | /** convert Matrix to Coord */ |
---|
1271 | template <typename DATATYPE, typename POS_TYPE, typename ROT_TYPE, unsigned MATCOLS, unsigned MATROWS > |
---|
1272 | inline Coord<POS_TYPE, ROT_TYPE>& set( Coord<POS_TYPE, ROT_TYPE>& eulercoord, const Matrix<DATATYPE, MATROWS, MATCOLS>& mat ) |
---|
1273 | { |
---|
1274 | gmtl::setTrans( eulercoord.pos(), mat ); |
---|
1275 | gmtl::set( eulercoord.rot(), mat ); |
---|
1276 | return eulercoord; |
---|
1277 | } |
---|
1278 | |
---|
1279 | /** Redundant duplication of the set(coord,mat) function, this is provided only for template compatibility. |
---|
1280 | * unless you're writing template functions, you should use set(coord,mat) for clarity. |
---|
1281 | */ |
---|
1282 | template <typename DATATYPE, typename POS_TYPE, typename ROT_TYPE, unsigned MATCOLS, unsigned MATROWS > |
---|
1283 | inline Coord<POS_TYPE, ROT_TYPE>& setRot( Coord<POS_TYPE, ROT_TYPE>& result, const Matrix<DATATYPE, MATROWS, MATCOLS>& mat ) |
---|
1284 | { |
---|
1285 | return gmtl::set( result, mat ); |
---|
1286 | } |
---|
1287 | |
---|
1288 | /** @} */ |
---|
1289 | |
---|
1290 | /** @ingroup Generate |
---|
1291 | * @name Generic Generators (any type) |
---|
1292 | * @{ |
---|
1293 | */ |
---|
1294 | |
---|
1295 | /** Construct an object from another object of a different type. |
---|
1296 | * This allows us to automatically convert from any type to any |
---|
1297 | * other type. |
---|
1298 | * @pre must have a set() function defined that converts between the |
---|
1299 | * two types. |
---|
1300 | * @param src the object to use for creation |
---|
1301 | * @return a new object with values based on the src variable |
---|
1302 | * @see OpenSGGenerate.h for an example |
---|
1303 | */ |
---|
1304 | template <typename TARGET_TYPE, typename SOURCE_TYPE> |
---|
1305 | inline TARGET_TYPE make( const SOURCE_TYPE& src, |
---|
1306 | Type2Type< TARGET_TYPE > t = Type2Type< TARGET_TYPE >() ) |
---|
1307 | { |
---|
1308 | gmtl::ignore_unused_variable_warning(t); |
---|
1309 | TARGET_TYPE target; |
---|
1310 | return gmtl::set( target, src ); |
---|
1311 | } |
---|
1312 | |
---|
1313 | /** Create a rotation datatype from another rotation datatype. |
---|
1314 | * @post converts the source rotation to a to another type (usually Matrix, Quat, Euler, AxisAngle), |
---|
1315 | * @post returns a temporary object. |
---|
1316 | */ |
---|
1317 | template <typename ROTATION_TYPE, typename SOURCE_TYPE > |
---|
1318 | inline ROTATION_TYPE makeRot( const SOURCE_TYPE& coord, |
---|
1319 | Type2Type< ROTATION_TYPE > t = Type2Type< ROTATION_TYPE >() ) |
---|
1320 | { |
---|
1321 | gmtl::ignore_unused_variable_warning(t); |
---|
1322 | ROTATION_TYPE temporary; |
---|
1323 | return gmtl::set( temporary, coord ); |
---|
1324 | } |
---|
1325 | |
---|
1326 | /** Create a rotation matrix or quaternion (or any other rotation data type) using direction cosines. |
---|
1327 | * |
---|
1328 | * If the two coordinate frames are labeled: SRC and TARGET, the matrix produced is: src_M_target |
---|
1329 | * this means that it will transform a point in TARGET to SRC but moves the base frame from SRC to TARGET. |
---|
1330 | * |
---|
1331 | * @param DestAxis required to specify |
---|
1332 | * @param SrcAxis optional to specify |
---|
1333 | * @pre specify 1 axis (3 vectors), or 2 axes (6 vectors). |
---|
1334 | * @post Creates a rotation from SrcAxis to DestAxis |
---|
1335 | * @post this function only produces 3x3, 3x4, 4x3, and 4x4 matrices, and is undefined otherwise |
---|
1336 | */ |
---|
1337 | template< typename ROTATION_TYPE > |
---|
1338 | inline ROTATION_TYPE makeDirCos( const Vec<typename ROTATION_TYPE::DataType, 3>& xDestAxis, |
---|
1339 | const Vec<typename ROTATION_TYPE::DataType, 3>& yDestAxis, |
---|
1340 | const Vec<typename ROTATION_TYPE::DataType, 3>& zDestAxis, |
---|
1341 | const Vec<typename ROTATION_TYPE::DataType, 3>& xSrcAxis = Vec<typename ROTATION_TYPE::DataType, 3>(1,0,0), |
---|
1342 | const Vec<typename ROTATION_TYPE::DataType, 3>& ySrcAxis = Vec<typename ROTATION_TYPE::DataType, 3>(0,1,0), |
---|
1343 | const Vec<typename ROTATION_TYPE::DataType, 3>& zSrcAxis = Vec<typename ROTATION_TYPE::DataType, 3>(0,0,1), |
---|
1344 | Type2Type< ROTATION_TYPE > t = Type2Type< ROTATION_TYPE >() ) |
---|
1345 | { |
---|
1346 | gmtl::ignore_unused_variable_warning(t); |
---|
1347 | ROTATION_TYPE temporary; |
---|
1348 | return setDirCos( temporary, xDestAxis, yDestAxis, zDestAxis, xSrcAxis, ySrcAxis, zSrcAxis ); |
---|
1349 | } |
---|
1350 | |
---|
1351 | /** |
---|
1352 | * Make a translation datatype from another translation datatype. |
---|
1353 | * Typically this is from Matrix to Vec or Vec to Matrix. |
---|
1354 | * This function reads only translation information from the src datatype. |
---|
1355 | * |
---|
1356 | * @param arg the matrix to extract the translation from |
---|
1357 | * |
---|
1358 | * @pre if making an n x n matrix, then for |
---|
1359 | * - <b>vector is homogeneous:</b> SIZE of vector needs to equal number of Matrix ROWS - 1 |
---|
1360 | * - <b>vector has scale component:</b> SIZE of vector needs to equal number of Matrix ROWS |
---|
1361 | * <br>if making an n x n+1 matrix, then for |
---|
1362 | * - <b>vector is homogeneous:</b> SIZE of vector needs to equal number of Matrix ROWS |
---|
1363 | * - <b>vector has scale component:</b> SIZE of vector needs to equal number of Matrix ROWS + 1 |
---|
1364 | * @post if preconditions are not met, then function is undefined (will not compile) |
---|
1365 | */ |
---|
1366 | template<typename TRANS_TYPE, typename SRC_TYPE > |
---|
1367 | inline TRANS_TYPE makeTrans( const SRC_TYPE& arg, |
---|
1368 | Type2Type< TRANS_TYPE > t = Type2Type< TRANS_TYPE >()) |
---|
1369 | { |
---|
1370 | gmtl::ignore_unused_variable_warning(t); |
---|
1371 | TRANS_TYPE temporary; |
---|
1372 | return setTrans( temporary, arg ); |
---|
1373 | } |
---|
1374 | |
---|
1375 | /** Create a rotation datatype that will xform first vector to the second. |
---|
1376 | * @pre each vec needs to be normalized. |
---|
1377 | * @post This function returns a temporary object. |
---|
1378 | */ |
---|
1379 | template< typename ROTATION_TYPE > |
---|
1380 | inline ROTATION_TYPE makeRot( const Vec<typename ROTATION_TYPE::DataType, 3>& from, |
---|
1381 | const Vec<typename ROTATION_TYPE::DataType, 3>& to ) |
---|
1382 | { |
---|
1383 | ROTATION_TYPE temporary; |
---|
1384 | return setRot( temporary, from, to ); |
---|
1385 | } |
---|
1386 | |
---|
1387 | /** set a rotation datatype that will xform first vector to the second. |
---|
1388 | * @pre each vec needs to be normalized. |
---|
1389 | * @post generate rotation datatype that is the rotation between the vectors. |
---|
1390 | * @note: only sets the rotation component of result, if result is a matrix, only sets the 3x3. |
---|
1391 | */ |
---|
1392 | template <typename DEST_TYPE, typename DATA_TYPE> |
---|
1393 | inline DEST_TYPE& setRot( DEST_TYPE& result, const Vec<DATA_TYPE, 3>& from, const Vec<DATA_TYPE, 3>& to ) |
---|
1394 | { |
---|
1395 | // @todo should assert that DEST_TYPE::DataType == DATA_TYPE |
---|
1396 | const DATA_TYPE epsilon = (DATA_TYPE)0.00001; |
---|
1397 | |
---|
1398 | gmtlASSERT( gmtl::Math::isEqual( gmtl::length( from ), (DATA_TYPE)1.0, epsilon ) && |
---|
1399 | gmtl::Math::isEqual( gmtl::length( to ), (DATA_TYPE)1.0, epsilon ) /* && |
---|
1400 | "input params not normalized" */); |
---|
1401 | |
---|
1402 | DATA_TYPE cosangle = dot( from, to ); |
---|
1403 | |
---|
1404 | // if cosangle is close to 1, so the vectors are close to being coincident |
---|
1405 | // Need to generate an angle of zero with any vector we like |
---|
1406 | // We'll choose identity (no rotation) |
---|
1407 | if ( Math::isEqual( cosangle, (DATA_TYPE)1.0, epsilon ) ) |
---|
1408 | { |
---|
1409 | return result = DEST_TYPE(); |
---|
1410 | } |
---|
1411 | |
---|
1412 | // vectors are close to being opposite, so rotate one a little... |
---|
1413 | else if ( Math::isEqual( cosangle, (DATA_TYPE)-1.0, epsilon ) ) |
---|
1414 | { |
---|
1415 | Vec<DATA_TYPE, 3> to_rot( to[0] + (DATA_TYPE)0.3, to[1] - (DATA_TYPE)0.15, to[2] - (DATA_TYPE)0.15 ), axis; |
---|
1416 | normalize( cross( axis, from, to_rot ) ); // setRot requires normalized vec |
---|
1417 | DATA_TYPE angle = Math::aCos( cosangle ); |
---|
1418 | return setRot( result, gmtl::AxisAngle<DATA_TYPE>( angle, axis ) ); |
---|
1419 | } |
---|
1420 | |
---|
1421 | // This is the usual situation - take a cross-product of vec1 and vec2 |
---|
1422 | // and that is the axis around which to rotate. |
---|
1423 | else |
---|
1424 | { |
---|
1425 | Vec<DATA_TYPE, 3> axis; |
---|
1426 | normalize( cross( axis, from, to ) ); // setRot requires normalized vec |
---|
1427 | DATA_TYPE angle = Math::aCos( cosangle ); |
---|
1428 | return setRot( result, gmtl::AxisAngle<DATA_TYPE>( angle, axis ) ); |
---|
1429 | } |
---|
1430 | } |
---|
1431 | |
---|
1432 | /** @} */ |
---|
1433 | |
---|
1434 | /** Accesses a particular row in the matrix by copying the values in the row |
---|
1435 | * into the given vector. |
---|
1436 | * |
---|
1437 | * @param dest the vector in which the values of the row will be placed |
---|
1438 | * @param src the matrix being accessed |
---|
1439 | * @param row the row of the matrix to access |
---|
1440 | */ |
---|
1441 | template< typename DATA_TYPE, unsigned ROWS, unsigned COLS > |
---|
1442 | void setRow(Vec<DATA_TYPE, COLS>& dest, const Matrix<DATA_TYPE, ROWS, COLS>& src, unsigned row) |
---|
1443 | { |
---|
1444 | for (unsigned i=0; i<COLS; ++i) |
---|
1445 | { |
---|
1446 | dest[i] = src[row][i]; |
---|
1447 | } |
---|
1448 | } |
---|
1449 | |
---|
1450 | /** Accesses a particular row in the matrix by creating a new vector |
---|
1451 | * containing the values in the given matrix. |
---|
1452 | * |
---|
1453 | * @param src the matrix being accessed |
---|
1454 | * @param row the row of the matrix to access |
---|
1455 | * |
---|
1456 | * @return a vector containing the values in the requested row |
---|
1457 | */ |
---|
1458 | template< typename DATA_TYPE, unsigned ROWS, unsigned COLS > |
---|
1459 | Vec<DATA_TYPE, COLS> makeRow(const Matrix<DATA_TYPE, ROWS, COLS>& src, unsigned row) |
---|
1460 | { |
---|
1461 | Vec<DATA_TYPE, COLS> result; |
---|
1462 | setRow(result, src, row); |
---|
1463 | return result; |
---|
1464 | } |
---|
1465 | |
---|
1466 | /** Accesses a particular column in the matrix by copying the values in the |
---|
1467 | * column into the given vector. |
---|
1468 | * |
---|
1469 | * @param dest the vector in which the values of the column will be placed |
---|
1470 | * @param src the matrix being accessed |
---|
1471 | * @param col the column of the matrix to access |
---|
1472 | */ |
---|
1473 | template< typename DATA_TYPE, unsigned ROWS, unsigned COLS > |
---|
1474 | void setColumn(Vec<DATA_TYPE, ROWS>& dest, const Matrix<DATA_TYPE, ROWS, COLS>& src, unsigned col) |
---|
1475 | { |
---|
1476 | for (unsigned i=0; i<ROWS; ++i) |
---|
1477 | { |
---|
1478 | dest[i] = src[i][col]; |
---|
1479 | } |
---|
1480 | } |
---|
1481 | |
---|
1482 | /** Accesses a particular column in the matrix by creating a new vector |
---|
1483 | * containing the values in the given matrix. |
---|
1484 | * |
---|
1485 | * @param src the matrix being accessed |
---|
1486 | * @param col the column of the matrix to access |
---|
1487 | * |
---|
1488 | * @return a vector containing the values in the requested column |
---|
1489 | */ |
---|
1490 | template< typename DATA_TYPE, unsigned ROWS, unsigned COLS > |
---|
1491 | Vec<DATA_TYPE, ROWS> makeColumn(const Matrix<DATA_TYPE, ROWS, COLS>& src, unsigned col) |
---|
1492 | { |
---|
1493 | Vec<DATA_TYPE, ROWS> result; |
---|
1494 | setColumn(result, src, col); |
---|
1495 | return result; |
---|
1496 | } |
---|
1497 | |
---|
1498 | } // end gmtl namespace. |
---|
1499 | |
---|
1500 | #endif |
---|