00001 /* 00002 Computes a 2D transform in homogeneous coordinates. 00003 00004 Copyright (C) 2010 - 2014 Christoph Haenisch 00005 00006 Chair of Medical Engineering (mediTEC) 00007 RWTH Aachen University 00008 Pauwelsstr. 20 00009 52074 Aachen 00010 Germany 00011 00012 See license.txt for more information. 00013 00014 Version 0.1.2 (2011-09-24) 00015 */ 00016 00021 /* Note: The concatenation of several affine matrices to one single 00022 * matrix is possible without any problems. However, if a 00023 * non-affine transform (e.g. a projective transform) is used, 00024 * it may only be used once and at the very end (i.e. multiplied 00025 * from left) due to the subsequent non-linear normalisation step. 00026 */ 00027 00028 00029 #ifndef TRANSFORM2D_HPP_9785873423 00030 #define TRANSFORM2D_HPP_9785873423 00031 00032 00033 #include <cassert> 00034 #include <cmath> 00035 #include <Eigen/Core> 00036 #include <Eigen/Dense> 00037 00038 #include "Coordinate.hpp" 00039 #include "ErrorObj.hpp" 00040 #include "Tools.hpp" 00041 00042 00043 namespace TRTK 00044 { 00045 00046 00200 template <class T> 00201 class Transform2D 00202 { 00203 public: 00204 00205 EIGEN_MAKE_ALIGNED_OPERATOR_NEW 00206 00207 enum Unit {DEGREES, RADIANS}; 00208 00209 enum Error {DIVISION_BY_ZERO, 00210 INVALID_ARGUMENT, 00211 INVALID_UNIT, 00212 UNKNOWN_ERROR, 00213 WRONG_COORDINATE_SIZE}; 00214 00215 typedef T value_type; 00216 typedef Eigen::Matrix<T, 3, 3> Matrix3T; 00217 typedef Eigen::Matrix<T, 3, 1> Vector3T; 00218 typedef Eigen::Matrix<T, 2, 1> Vector2T; 00219 typedef Coordinate<T> coordinate_type; 00220 00221 Transform2D(); 00222 00223 Transform2D(const Matrix3T &); 00224 00225 Transform2D(T a11, T a12, T a13, 00226 T a21, T a22, T a23, 00227 T a31, T a32, T a33); 00228 00229 template <class U> 00230 Transform2D(const Transform2D<U> & transform2D); 00231 00232 virtual ~Transform2D(); 00233 00234 T & a11(); 00235 T & a12(); 00236 T & a13(); 00237 T & a21(); 00238 T & a22(); 00239 T & a23(); 00240 T & a31(); 00241 T & a32(); 00242 T & a33(); 00243 00244 const T & a11() const; 00245 const T & a12() const; 00246 const T & a13() const; 00247 const T & a21() const; 00248 const T & a22() const; 00249 const T & a23() const; 00250 const T & a31() const; 00251 const T & a32() const; 00252 const T & a33() const; 00253 00254 const Coordinate<T> operator* (const Coordinate<T> &) const; 00255 const Matrix3T operator* (const Matrix3T &) const; 00256 const Vector2T operator* (const Vector2T &) const; 00257 const Vector3T operator* (const Vector3T &) const; 00258 const Transform2D operator* (const Transform2D &) const; 00259 const Transform2D operator>> (const Transform2D &) const; 00260 00261 Matrix3T & getTransformationMatrix(); 00262 const Matrix3T & getTransformationMatrix() const; 00263 00264 const Transform2D inverse() const; 00265 00266 Transform2D & reset(); 00267 00268 Transform2D & rotate(const double angle, const Unit unit = RADIANS); 00269 00270 Transform2D & scale(const T sx, const T sy); 00271 00272 Transform2D & shear(const T sx, const T sy); 00273 00274 Transform2D & translate(const T dx, const T dy); 00275 Transform2D & translate(const Coordinate<T> & position); 00276 00277 bool is_affine() const; 00278 00279 static const double pi; 00280 00281 private: 00282 00283 void normalize(Vector3T &) const; 00284 00285 Matrix3T m_matrix; 00286 bool m_is_affine; 00287 }; 00288 00289 00290 template <class T> 00291 const double Transform2D<T>::pi = 3.14159265358979323846264338327950288419716939937510; 00292 00293 00303 template <class T> 00304 Transform2D<T>::Transform2D() : m_is_affine(true) 00305 { 00306 m_matrix.setIdentity(); 00307 } 00308 00309 00321 template <class T> 00322 Transform2D<T>::Transform2D(const Matrix3T & matrix) 00323 { 00324 using Tools::isEqual; 00325 00326 m_matrix = matrix; 00327 00328 if (isEqual<T>(matrix(2,0), 0) && 00329 isEqual<T>(matrix(2,1), 0) && 00330 isEqual<T>(matrix(2,2), 1)) 00331 { 00332 m_is_affine = true; 00333 } 00334 else 00335 { 00336 m_is_affine = false; 00337 } 00338 } 00339 00340 00350 template <class T> 00351 Transform2D<T>::Transform2D(T a11, T a12, T a13, 00352 T a21, T a22, T a23, 00353 T a31, T a32, T a33) 00354 { 00355 using Tools::isEqual; 00356 00357 m_matrix << a11, a12, a13, 00358 a21, a22, a23, 00359 a31, a32, a33; 00360 00361 if (isEqual<T>(a31, 0) && 00362 isEqual<T>(a32, 0) && 00363 isEqual<T>(a33, 1)) 00364 { 00365 m_is_affine = true; 00366 } 00367 else 00368 { 00369 m_is_affine = false; 00370 } 00371 } 00372 00373 00382 template <class T> 00383 template <class U> 00384 Transform2D<T>::Transform2D(const Transform2D<U> & transform2D) 00385 { 00386 const int rows = transform2D.getTransformationMatrix().rows(); 00387 const int cols = transform2D.getTransformationMatrix().cols(); 00388 00389 m_matrix.resize(rows, cols); 00390 00391 for (int m = 0; m < rows; ++m) 00392 { 00393 for (int n = 0; n < cols; ++n) 00394 { 00395 m_matrix(m, n) = T(transform2D.getTransformationMatrix()(m, n)); 00396 } 00397 } 00398 00399 m_is_affine = transform2D.is_affine(); 00400 } 00401 00402 00408 template <class T> 00409 Transform2D<T>::~Transform2D() 00410 { 00411 } 00412 00413 00423 template <class T> 00424 T & Transform2D<T>::a11() 00425 { 00426 return m_matrix(0, 0); 00427 } 00428 00429 00439 template <class T> 00440 T & Transform2D<T>::a12() 00441 { 00442 return m_matrix(0, 1); 00443 } 00444 00445 00455 template <class T> 00456 T & Transform2D<T>::a13() 00457 { 00458 return m_matrix(0, 2); 00459 } 00460 00461 00471 template <class T> 00472 T & Transform2D<T>::a21() 00473 { 00474 return m_matrix(1, 0); 00475 } 00476 00477 00487 template <class T> 00488 T & Transform2D<T>::a22() 00489 { 00490 return m_matrix(1, 1); 00491 } 00492 00493 00503 template <class T> 00504 T & Transform2D<T>::a23() 00505 { 00506 return m_matrix(1, 2); 00507 } 00508 00509 00519 template <class T> 00520 T & Transform2D<T>::a31() 00521 { 00522 m_is_affine = false; 00523 return m_matrix(2, 0); 00524 } 00525 00526 00536 template <class T> 00537 T & Transform2D<T>::a32() 00538 { 00539 m_is_affine = false; 00540 return m_matrix(2, 1); 00541 } 00542 00543 00553 template <class T> 00554 T & Transform2D<T>::a33() 00555 { 00556 m_is_affine = false; 00557 return m_matrix(2, 2); 00558 } 00559 00560 00570 template <class T> 00571 const T & Transform2D<T>::a11() const 00572 { 00573 return m_matrix(0, 0); 00574 } 00575 00576 00586 template <class T> 00587 const T & Transform2D<T>::a12() const 00588 { 00589 return m_matrix(0, 1); 00590 } 00591 00592 00602 template <class T> 00603 const T & Transform2D<T>::a13() const 00604 { 00605 return m_matrix(0, 2); 00606 } 00607 00608 00618 template <class T> 00619 const T & Transform2D<T>::a21() const 00620 { 00621 return m_matrix(1, 0); 00622 } 00623 00624 00634 template <class T> 00635 const T & Transform2D<T>::a22() const 00636 { 00637 return m_matrix(1, 1); 00638 } 00639 00640 00650 template <class T> 00651 const T & Transform2D<T>::a23() const 00652 { 00653 return m_matrix(1, 2); 00654 } 00655 00656 00666 template <class T> 00667 const T & Transform2D<T>::a31() const 00668 { 00669 return m_matrix(2, 0); 00670 } 00671 00672 00682 template <class T> 00683 const T & Transform2D<T>::a32() const 00684 { 00685 return m_matrix(2, 1); 00686 } 00687 00688 00698 template <class T> 00699 const T & Transform2D<T>::a33() const 00700 { 00701 return m_matrix(2, 2); 00702 } 00703 00704 00737 template <class T> 00738 const Coordinate<T> Transform2D<T>::operator* (const Coordinate<T> & coordinate) const 00739 { 00740 // 'coordinate' must be of size two or three. If 'coordinate' has a size 00741 // of three, it is assumed that the third component is equal to one. 00742 00743 const int size = coordinate.size(); 00744 00745 if (!(size == 2 || size == 3)) 00746 { 00747 ErrorObj error; 00748 error.setClassName("Transform2D<T>"); 00749 error.setFunctionName("operator*"); 00750 error.setErrorMessage("'coordinate' must be of size two or three."); 00751 error.setErrorCode(WRONG_COORDINATE_SIZE); 00752 throw error; 00753 } 00754 00755 assert(coordinate.size() == 2 || (coordinate.size() == 3 && coordinate.w() == 1)); 00756 00757 Vector3T vector(coordinate.x(), coordinate.y(), 1); 00758 Vector3T result = m_matrix * vector; 00759 00760 if (!is_affine()) 00761 { 00762 normalize(result); 00763 } 00764 00765 if (size == 2) 00766 { 00767 return Coordinate<T>(result(0), result(1)); 00768 } 00769 else // size == 3 00770 { 00771 return Coordinate<T>(result(0), result(1), 1); 00772 } 00773 } 00774 00775 00806 template <class T> 00807 const typename Transform2D<T>::Vector2T Transform2D<T>::operator* (const Vector2T & vector) const 00808 { 00809 Vector3T vector3D(vector(0), vector(1), 1); 00810 Vector3T result = m_matrix * vector3D; 00811 00812 if (!is_affine()) 00813 { 00814 normalize(result); 00815 } 00816 00817 return result.head(2); 00818 } 00819 00820 00855 template <class T> 00856 const typename Transform2D<T>::Vector3T Transform2D<T>::operator* (const Vector3T & vector) const 00857 { 00858 assert(Tools::isEqual<T>(vector(2), 1)); 00859 00860 Vector3T result = m_matrix * vector; 00861 00862 if (!is_affine()) 00863 { 00864 normalize(result); 00865 } 00866 00867 return result; 00868 } 00869 00870 00912 template <class T> 00913 const typename Transform2D<T>::Matrix3T Transform2D<T>::operator* (const Matrix3T & matrix) const 00914 { 00915 typename Transform2D<T>::Matrix3T result = m_matrix * matrix; 00916 00917 return result; 00918 } 00919 00920 00963 template <class T> 00964 const Transform2D<T> Transform2D<T>::operator* (const Transform2D & transform) const 00965 { 00966 Transform2D<T> result = (m_matrix * transform.m_matrix).eval(); 00967 result.m_is_affine = m_is_affine && transform.m_is_affine; 00968 00969 return result; 00970 } 00971 00972 01015 template <class T> 01016 const Transform2D<T> Transform2D<T>::operator>> (const Transform2D & transform) const 01017 { 01018 Transform2D<T> result = (transform.m_matrix * m_matrix).eval(); 01019 result.m_is_affine = m_is_affine && transform.m_is_affine; 01020 01021 return result; 01022 } 01023 01024 01032 template <class T> 01033 typename Transform2D<T>::Matrix3T & Transform2D<T>::getTransformationMatrix() 01034 { 01035 return m_matrix; 01036 } 01037 01038 01046 template <class T> 01047 const typename Transform2D<T>::Matrix3T & Transform2D<T>::getTransformationMatrix() const 01048 { 01049 return m_matrix; 01050 } 01051 01052 01060 template <class T> 01061 const Transform2D<T> Transform2D<T>::inverse() const 01062 { 01063 return Transform2D(m_matrix.inverse()); 01064 } 01065 01066 01074 template <class T> 01075 Transform2D<T> & Transform2D<T>::reset() 01076 { 01077 m_matrix.setIdentity(); 01078 m_is_affine = true; 01079 01080 return *this; 01081 } 01082 01083 01094 template <class T> 01095 Transform2D<T> & Transform2D<T>::rotate(const double angle, const Unit unit) 01096 { 01097 double angle_in_rad; 01098 01099 switch (unit) 01100 { 01101 case RADIANS: 01102 angle_in_rad = angle; 01103 break; 01104 01105 case DEGREES: 01106 angle_in_rad = angle / 180.0 * pi; 01107 break; 01108 01109 default: 01110 ErrorObj error; 01111 error.setClassName("Transform2D<T>"); 01112 error.setFunctionName("rotateX"); 01113 error.setErrorMessage("Invalid unit."); 01114 error.setErrorCode(INVALID_UNIT); 01115 throw error; 01116 } 01117 01118 Matrix3T rotation; 01119 01120 const double c = std::cos(angle_in_rad); 01121 const double s = std::sin(angle_in_rad); 01122 01123 rotation << c, -s, 0, 01124 s, c, 0, 01125 0, 0, 1; 01126 01127 m_matrix = rotation * m_matrix; 01128 01129 return *this; 01130 } 01131 01132 01146 template <class T> 01147 Transform2D<T> & Transform2D<T>::scale(const T sx, const T sy) 01148 { 01149 Matrix3T scale; 01150 01151 scale << sx, 0, 0, 01152 0, sy, 0, 01153 0, 0, 1; 01154 01155 m_matrix = scale * m_matrix; 01156 01157 return *this; 01158 } 01159 01160 01174 template <class T> 01175 Transform2D<T> & Transform2D<T>::shear(const T sx, const T sy) 01176 { 01177 Matrix3T shear; 01178 01179 shear << 1, sx, 0, 01180 sy, 1, 0, 01181 0, 0, 1; 01182 01183 m_matrix = shear * m_matrix; 01184 01185 return *this; 01186 } 01187 01188 01201 template <class T> 01202 Transform2D<T> & Transform2D<T>::translate(const T dx, const T dy) 01203 { 01204 Matrix3T translation; 01205 01206 translation << 1, 0, dx, 01207 0, 1, dy, 01208 0, 0, 1; 01209 01210 m_matrix = translation * m_matrix; 01211 01212 return *this; 01213 } 01214 01215 01227 template <class T> 01228 Transform2D<T> & Transform2D<T>::translate(const Coordinate<T> & position) 01229 { 01230 assert(position.size() == 2); 01231 01232 Matrix3T translation; 01233 01234 translation << 1, 0, position.x(), 01235 0, 1, position.y(), 01236 0, 0, 1; 01237 01238 m_matrix = translation * m_matrix; 01239 01240 return *this; 01241 } 01242 01243 01251 template <class T> 01252 inline bool Transform2D<T>::is_affine() const 01253 { 01254 return m_is_affine; 01255 } 01256 01257 01273 template <class T> 01274 inline void Transform2D<T>::normalize(Vector3T & vec) const 01275 { 01276 if (Tools::isZero<T>(vec(2))) 01277 { 01278 ErrorObj error; 01279 error.setClassName("Transform2D"); 01280 error.setFunctionName("normalize"); 01281 error.setErrorMessage("Division by zero."); 01282 error.setErrorCode(DIVISION_BY_ZERO); 01283 throw error; 01284 } 01285 else 01286 { 01287 vec(0) /= vec(2); 01288 vec(1) /= vec(2); 01289 vec(2) = 1; 01290 } 01291 } 01292 01293 01294 } // namespace TRTK 01295 01296 01297 #endif // TRANSFORM2D_HPP_9785873423
Documentation generated by Doxygen