library of assembled shared sources

http://lass.cocamware.com

transformation_2d.inl

Go to the documentation of this file.
00001 /** @file
00002  *  @author Bram de Greve (bramz@users.sourceforge.net)
00003  *  @author Tom De Muer (tomdemuer@users.sourceforge.net)
00004  *
00005  *  *** BEGIN LICENSE INFORMATION ***
00006  *  
00007  *  The contents of this file are subject to the Common Public Attribution License 
00008  *  Version 1.0 (the "License"); you may not use this file except in compliance with 
00009  *  the License. You may obtain a copy of the License at 
00010  *  http://lass.sourceforge.net/cpal-license. The License is based on the 
00011  *  Mozilla Public License Version 1.1 but Sections 14 and 15 have been added to cover 
00012  *  use of software over a computer network and provide for limited attribution for 
00013  *  the Original Developer. In addition, Exhibit A has been modified to be consistent 
00014  *  with Exhibit B.
00015  *  
00016  *  Software distributed under the License is distributed on an "AS IS" basis, WITHOUT 
00017  *  WARRANTY OF ANY KIND, either express or implied. See the License for the specific 
00018  *  language governing rights and limitations under the License.
00019  *  
00020  *  The Original Code is LASS - Library of Assembled Shared Sources.
00021  *  
00022  *  The Initial Developer of the Original Code is Bram de Greve and Tom De Muer.
00023  *  The Original Developer is the Initial Developer.
00024  *  
00025  *  All portions of the code written by the Initial Developer are:
00026  *  Copyright (C) 2004-2007 the Initial Developer.
00027  *  All Rights Reserved.
00028  *  
00029  *  Contributor(s):
00030  *
00031  *  Alternatively, the contents of this file may be used under the terms of the 
00032  *  GNU General Public License Version 2 or later (the GPL), in which case the 
00033  *  provisions of GPL are applicable instead of those above.  If you wish to allow use
00034  *  of your version of this file only under the terms of the GPL and not to allow 
00035  *  others to use your version of this file under the CPAL, indicate your decision by 
00036  *  deleting the provisions above and replace them with the notice and other 
00037  *  provisions required by the GPL License. If you do not delete the provisions above,
00038  *  a recipient may use your version of this file under either the CPAL or the GPL.
00039  *  
00040  *  *** END LICENSE INFORMATION ***
00041  */
00042 
00043 #ifndef LASS_GUARDIAN_OF_INCLUSION_PRIM_TRANSFORMATION_2D_INL
00044 #define LASS_GUARDIAN_OF_INCLUSION_PRIM_TRANSFORMATION_2D_INL
00045 
00046 #include "transformation_2d.h"
00047 
00048 namespace lass
00049 {
00050 
00051 namespace prim
00052 {
00053 
00054 // --- public --------------------------------------------------------------------------------------
00055 
00056 /** construct an identity transformation.
00057  *  An identity transformation transforms every point to itself.
00058  */
00059 template <typename T>
00060 Transformation2D<T>::Transformation2D():
00061     matrix_(impl::allocateArray<T>(matrixSize_)),
00062     inverseMatrix_(0)
00063 {
00064     matrix_[ 0] = TNumTraits::one;
00065     matrix_[ 1] = TNumTraits::zero;
00066     matrix_[ 2] = TNumTraits::zero;
00067     matrix_[ 3] = TNumTraits::one;
00068     matrix_[ 4] = TNumTraits::zero;
00069     matrix_[ 5] = TNumTraits::zero;
00070     matrix_[ 6] = TNumTraits::one;
00071     matrix_[ 7] = TNumTraits::zero;
00072     matrix_[ 8] = TNumTraits::zero;
00073 }
00074 
00075 
00076 
00077 /** construct a transformation from a 3x3 tranformation matrix.
00078  *  The elements of the 3x3 matrix will represented in a row major way by an iterator
00079  *  range [first, last) of 9 elements.
00080  */
00081 template <typename T>
00082 template <typename InputIterator>
00083 Transformation2D<T>::Transformation2D(InputIterator first, InputIterator last):
00084     matrix_(impl::allocateArray<T>(matrixSize_)),
00085     inverseMatrix_(0)
00086 {
00087     LASS_ENFORCE(std::distance(first, last) == matrixSize_);
00088     std::copy(first, last, matrix_.get());
00089 }
00090 
00091 
00092 
00093 /** return the inverse transformation.
00094  *  The inverse is calculated on the first call, and then cached for later use.
00095  *  For the transformation, we've use the C version of Cramer's rule as described in
00096  *  the Intel (R) article "Streaming SIMD Extensions -Inverse of 4x4 Matrix" which
00097  *  can be found here: http://www.intel.com/design/pentiumiii/sml/245043.htm
00098  */
00099 template <typename T>
00100 const Transformation2D<T>
00101 Transformation2D<T>::inverse() const
00102 {
00103     if (inverseMatrix_.isEmpty())
00104     {
00105         TMatrix inverseMatrix(impl::allocateArray<T>(matrixSize_));
00106         const TValue* const mat = matrix_.get();
00107         TValue* const inv = inverseMatrix.get();
00108 
00109         inv[0] = mat[4] * mat[8] - mat[5] * mat[7];
00110         inv[1] = mat[7] * mat[2] - mat[8] * mat[1];
00111         inv[2] = mat[1] * mat[5] - mat[2] * mat[4];
00112 
00113         inv[3] = mat[6] * mat[5] - mat[8] * mat[3];
00114         inv[4] = mat[0] * mat[8] - mat[2] * mat[6];
00115         inv[5] = mat[3] * mat[2] - mat[5] * mat[0];
00116 
00117         inv[6] = mat[3] * mat[7] - mat[4] * mat[6];
00118         inv[7] = mat[6] * mat[1] - mat[7] * mat[0];
00119         inv[8] = mat[0] * mat[4] - mat[1] * mat[3];
00120 
00121         const TValue det = mat[0] * inv[0] + mat[1] * inv[3] + mat[2] * inv[6];
00122         if (det == TNumTraits::zero)
00123         {
00124             inverseMatrix.reset();
00125             LASS_THROW_EX(SingularityError, "transformation not invertible");
00126         }
00127         const TValue invDet = num::inv(det);
00128         for (int i = 0; i < 9; ++i)
00129         {
00130             inv[i] *= invDet;
00131         }
00132 
00133         sync_.lock();
00134         inverseMatrix_.swap(inverseMatrix);
00135         sync_.unlock();
00136     }
00137 
00138     LASS_ASSERT(inverseMatrix_ && matrix_);
00139     return TSelf(inverseMatrix_, matrix_, false);
00140 }
00141 
00142 
00143 
00144 /** Return pointer to row major matrix representation of transformation.
00145  *  This is for immediate use only, like @c std::basic_string::data().
00146  */
00147 template <typename T> inline
00148 const typename Transformation2D<T>::TValue*
00149 Transformation2D<T>::matrix() const
00150 {
00151     return matrix_.get();
00152 }
00153 
00154 
00155 
00156 template <typename T>
00157 void Transformation2D<T>::swap(TSelf& other)
00158 {
00159     matrix_.swap(other.matrix_);
00160     inverseMatrix_.swap(other.inverseMatrix_);
00161 }
00162 
00163 
00164 
00165 /** make a 2D identity transformation 
00166  */
00167 template <typename T> 
00168 const Transformation2D<T> Transformation2D<T>::identity()
00169 {
00170     return TSelf();
00171 }
00172 
00173 
00174 
00175 /** make a 2D transformation representing a translation
00176  */
00177 template <typename T>
00178 const Transformation2D<T> Transformation2D<T>::translation(const Vector2D<T>& offset)
00179 {
00180     Transformation2D<T> result;
00181     result.matrix_[2] = offset.x;
00182     result.matrix_[5] = offset.y;
00183     result.matrix_[8] = offset.z;
00184     return result;
00185 }
00186 
00187 
00188 
00189 /** make a 3D transformation representing a uniform scaling
00190  */
00191 template <typename T>
00192 const Transformation2D<T> Transformation2D<T>::scaler(const T& scale)
00193 {
00194     Transformation2D<T> result;
00195     result.matrix_[0] = scale;
00196     result.matrix_[4] = scale;
00197     return result;
00198 }
00199 
00200 
00201 
00202 /** make a 3D transformation representing a scaling with different factors per axis
00203  */
00204 template <typename T>
00205 const Transformation2D<T> Transformation2D<T>::scaler(const Vector2D<T>& scale)
00206 {
00207     Transformation2D<T> result;
00208     result.matrix_[0] = scale.x;
00209     result.matrix_[4] = scale.y;
00210     return result;
00211 }
00212 
00213 
00214 
00215 /** make a 3D transformation representing a counterclockwise rotation
00216  */
00217 template <typename T>
00218 const Transformation2D<T> Transformation2D<T>::rotation(TParam radians)
00219 {
00220     const T c = num::cos(radians);
00221     const T s = num::sin(radians);
00222 
00223     Transformation2D<T> result;
00224     result.matrix_[0] = c;
00225     result.matrix_[4] = c;
00226     result.matrix_[1] = -s;
00227     result.matrix_[3] = s;
00228     return result;
00229 }
00230 
00231 
00232 
00233 // --- protected -----------------------------------------------------------------------------------
00234 
00235 
00236 
00237 // --- private -------------------------------------------------------------------------------------
00238 
00239 template <typename T> inline
00240 Transformation2D<T>::Transformation2D(const TMatrix& matrix, const TMatrix& inverseMatrix, bool):
00241     matrix_(matrix),
00242     inverseMatrix_(inverseMatrix)
00243 {
00244 }
00245 
00246 
00247 
00248 // --- free ----------------------------------------------------------------------------------------
00249 
00250 /** concatenate two transformations @a first and @a second in one.
00251  *  @relates Transformation2D
00252  *  The result is one transformation that performs the same actions as first performing
00253  *  @a first and then @a second.  Hence, the following lines of code are equivalent (ignoring
00254  *  numerical imprecions):
00255  *
00256  *  @code
00257  *  y = transform(x, concatenate(first, second));
00258  *  y = transform(transform(x, first), second);
00259  *  @endcode
00260  */
00261 template <typename T>
00262 Transformation2D<T> concatenate(const Transformation2D<T>& first, const Transformation2D<T>& second)
00263 {
00264     // right-handed vector product, so it's @a second * @a first instead of @a first * @a second
00265     const T* const a = second.matrix();
00266     const T* const b = first.matrix();
00267     T result[9];
00268     for (size_t i = 0; i < 9; i += 3)
00269     {
00270         for (size_t j = 0; j < 3; ++j)
00271         {
00272             result[i + j] = 
00273                 a[i    ] * b[    j] + 
00274                 a[i + 1] * b[3 + j] + 
00275                 a[i + 2] * b[6 + j];
00276         }
00277     }
00278     return Transformation2D<T>(result, result + 9);
00279 }
00280 
00281 
00282 
00283 /** apply transformation to a vector
00284  *  @relates Transformation2D
00285  */
00286 template <typename T>
00287 Vector2D<T> transform(const Vector2D<T>& subject, const Transformation2D<T>& transformation)
00288 {
00289     const T* const mat = transformation.matrix();
00290     return Vector2D<T>(
00291         mat[0] * subject.x + mat[1] * subject.y,
00292         mat[3] * subject.x + mat[4] * subject.y);
00293 }
00294 
00295 
00296 
00297 /** apply transformation to a point
00298  *  @relates Transformation2D
00299  */
00300 template <typename T>
00301 Point2D<T> transform(const Point2D<T>& subject, const Transformation2D<T>& transformation)
00302 {
00303     const T* const mat = transformation.matrix();
00304     const T weight = num::inv(mat[6] * subject.x + mat[7] * subject.y + mat[8]);
00305     return Point2D<T>(
00306         weight * (mat[0] * subject.x + mat[1] * subject.y + mat[2]),
00307         weight * (mat[3] * subject.x + mat[4] * subject.y + mat[5]));
00308 
00309 }
00310 
00311 
00312 
00313 /** apply transformation to a normal vector.
00314  *  @relates Transformation2D
00315  *  Vectors that represent a normal vector should transform differentely than ordinary
00316  *  vectors.  Use this transformation function for normals.
00317  */
00318 template <typename T>
00319 Vector2D<T> normalTransform(const Vector2D<T>& subject, const Transformation2D<T>& transformation)
00320 {
00321     const T* const invMat = transformation.inverse().matrix();
00322     return Vector2D<T>(
00323         invMat[0] * subject.x + invMat[3] * subject.y,
00324         invMat[1] * subject.x + invMat[4] * subject.y);
00325 }
00326 
00327 
00328 
00329 /** apply transformation to a 3D normal vector.
00330  *  @relates Transformation2D
00331  *  Vectors that represent a normal vector should transform differentely than ordinary
00332  *  vectors.  Use this transformation function for normals.
00333  *
00334  *  Cartesian lines have a 3D normal vector that must be transformed in 2D.  Use this
00335  *  function to do it:
00336  *
00337  *  @code
00338  *  // ax + by + c == 0
00339  *  normalTransform(std::make_pair(Vector2D<float>(a, b), c), transformation);
00340  *  @endcode
00341  */
00342 template <typename T>
00343 std::pair<Vector2D<T>, T> normalTransform(const std::pair<Vector2D<T>, T>& subject, 
00344                                           const Transformation2D<T>& transformation)
00345 {
00346     const T* const invMat = transformation.inverse().matrix();
00347     const Vector2D<T>& n = subject.first;
00348     const T c = subject.second;
00349     return std::make_pair(
00350         Vector2D<T>(
00351             invMat[0] * n.x + invMat[3] * n.y + invMat[6] * c,
00352             invMat[1] * n.x + invMat[4] * n.y + invMat[7] * c),
00353         invMat[2] * n.x + invMat[5] * n.y + invMat[8] * c);
00354 }
00355 
00356 
00357 
00358 /** @relates Transformation2D
00359  */
00360 template<typename T, typename Char, typename Traits>
00361 std::basic_ostream<Char, Traits>& operator<<(std::basic_ostream<Char, Traits>& stream,
00362                                              const Transformation2D<T>& transformation)
00363 {
00364     const T* const mat = transformation.matrix();
00365     LASS_ENFORCE_STREAM(stream) << "(("
00366         << mat[0] << ", " << mat[1] << ", " << mat[2] << "), ("
00367         << mat[3] << ", " << mat[4] << ", " << mat[5] << "), ("
00368         << mat[6] << ", " << mat[7] << ", " << mat[9] << "))";
00369     return stream;
00370 }
00371 
00372 
00373 
00374 /** @relates Transformation2D
00375  */
00376 template<typename T>
00377 io::XmlOStream& operator<<(io::XmlOStream& stream, const Transformation2D<T>& transformation)
00378 {
00379     const T* const mat = transformation.matrix();
00380     LASS_ENFORCE_STREAM(stream) << "<Transformation2D>"
00381         << mat[0] << " " << mat[1] << " " << mat[2] << " "
00382         << mat[3] << " " << mat[4] << " " << mat[5] << " "
00383         << mat[6] << " " << mat[7] << " " << mat[9]
00384         << "</Transformation2D>\n";
00385     return stream;
00386 }
00387 
00388 
00389 
00390 }
00391 
00392 }
00393 
00394 #endif

Generated on Mon Nov 10 14:21:40 2008 for Library of Assembled Shared Sources by doxygen 1.5.7.1
SourceForge.net Logo