[4] | 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 |
---|