math3d.h
Go to the documentation of this file.
00001 /********************************************************************************
00002 Copyright (c) 2015, TRACLabs, Inc.
00003 All rights reserved.
00004 
00005 Redistribution and use in source and binary forms, with or without modification,
00006  are permitted provided that the following conditions are met:
00007 
00008     1. Redistributions of source code must retain the above copyright notice, 
00009        this list of conditions and the following disclaimer.
00010 
00011     2. Redistributions in binary form must reproduce the above copyright notice,
00012        this list of conditions and the following disclaimer in the documentation 
00013        and/or other materials provided with the distribution.
00014 
00015     3. Neither the name of the copyright holder nor the names of its contributors
00016        may be used to endorse or promote products derived from this software 
00017        without specific prior written permission.
00018 
00019 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
00020 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 
00021 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
00022 IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
00023 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
00024 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 
00025 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
00026 LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 
00027 OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
00028 OF THE POSSIBILITY OF SUCH DAMAGE.
00029 ********************************************************************************/
00030 
00031 #ifndef MATH3D_H
00032 #define MATH3D_H
00033 
00034 #include <string>
00035 #include <iostream>
00036 #include <cmath>
00037 #include <vector>
00038 #include <stdexcept>
00039 #include <cstdlib>
00040 
00041 #ifndef M_PI
00042 #define M_PI (3.14159265358979323846)
00043 #endif
00044 
00045 typedef unsigned char uint8_t;
00046 typedef unsigned int uint32_t;
00047 
00048 namespace math3d {
00049 
00050   static const double pi = M_PI;
00051   static const double rad_on_deg = pi / 180.;
00052   static const double deg_on_rad = 180. / pi;
00053 
00054   template <typename T>
00055     inline bool almost_zero(T a, double e)
00056     {
00057       return (a == T(0)) || (a > 0 && a < e) || (a < 0 && a > -e);
00058     }
00059 
00060   struct color_rgb24
00061   {
00062     uint8_t r, g, b;
00063   color_rgb24(uint8_t R, uint8_t G, uint8_t B) : r(R), g(G), b(B) {}
00064   };
00065 
00066   template <typename T>
00067     struct vec3d
00068     {
00069       T x,y,z;
00070 
00071       explicit vec3d() : x(0), y(0), z(0) {}
00072     vec3d(T x_, T y_, T z_) : x(x_), y(y_), z(z_) {}
00073 
00074       template <typename S>
00075       vec3d(const vec3d<S>& s) : x(T(s.x)), y(T(s.y)), z(T(s.z)) {}
00076 
00077       template <typename S>
00078       vec3d(const S* s) : x(T(s[0])), y(T(s[1])), z(T(s[2])) {}
00079 
00080       vec3d<T> operator+(const vec3d<T>& p) const
00081       {
00082         return vec3d<T>(x + p.x, y + p.y, z + p.z);
00083       }
00084 
00085       vec3d<T> operator-(const vec3d<T>& p) const
00086       {
00087         return vec3d<T>(x - p.x, y - p.y, z - p.z);
00088       }
00089 
00090       vec3d<T> operator-() const
00091       {
00092         return vec3d<T>(-x, -y, -z);
00093       }
00094 
00095       template <typename S>
00096       vec3d<T>& operator+=(const vec3d<S>& p) {
00097         x += T(p.x);
00098         y += T(p.y);
00099         z += T(p.z);
00100         return *this;
00101       }
00102 
00103       // rules for partial ordering of function templates say that the new overload
00104       // is a better match, when it matches
00105 
00106       vec3d<T>& operator+=(const vec3d<T>& p)
00107       {
00108         x += p.x;
00109         y += p.y;
00110         z += p.z;
00111         return *this;
00112       }
00113 
00114       template <typename S>
00115       vec3d<T>& operator-=(const vec3d<S>& p)
00116       {
00117         x -= T(p.x);
00118         y -= T(p.y);
00119         z -= T(p.z);
00120         return *this;
00121       }
00122 
00123       vec3d<T>& operator-=(const vec3d<T>& p) {
00124         x -= p.x;
00125         y -= p.y;
00126         z -= p.z;
00127         return *this;
00128       }
00129 
00130       template <typename Scalar>
00131       vec3d<T>& operator/=(const Scalar& s) {
00132         const T i = T(1) / T(s);
00133         x *= i;
00134         y *= i;
00135         z *= i;
00136         return *this;
00137       }
00138 
00139       template <typename Scalar>
00140       vec3d<T>& operator*=(const Scalar& s) {
00141         x *= T(s);
00142         y *= T(s);
00143         z *= T(s);
00144         return *this;
00145       }
00146 
00147       bool operator==(const vec3d& o) const { return (x == o.x) && (y == o.y) && (z == o.z); }
00148 
00149       template <typename S>
00150       bool operator==(const vec3d<S>& o) const {
00151         return (x == T(o.x) && y == T(o.y) && z == T(o.z));
00152       }
00153 
00154       bool operator!=(const vec3d& o) const { return !(*this==o); }
00155 
00156       template <typename S>
00157       bool operator!=(const vec3d<S>& o) const {
00158         return !(*this == o);
00159       }
00160 
00161       template <typename Scalar>
00162       friend vec3d<T> operator*(const vec3d<T>& p, const Scalar& s) {
00163         return vec3d<T>(s * p.x, s * p.y, s * p.z);
00164       }
00165 
00166       template <typename Scalar>
00167       friend vec3d<T> operator*(const Scalar& s, const vec3d<T>& p) {
00168         return p*s;
00169       }
00170 
00171       template <typename Scalar>
00172       friend vec3d<T> operator/(const vec3d<T>& p, const Scalar& s) {
00173         return vec3d<T>(p.x / T(s), p.y / T(s), p.z / T(s));
00174       }
00175 
00176       friend std::ostream& operator<<(std::ostream& os, const vec3d<T>& p) {
00177         return (os << p.x << " " << p.y << " " << p.z);
00178       }
00179 
00180       friend std::istream& operator>>(std::istream& is, vec3d<T>& p) {
00181         return (is >> p.x >> p.y >> p.z);
00182       }
00183 
00184     };
00185 
00186   typedef vec3d<double> normal3d;
00187   typedef vec3d<double> point3d;
00188 
00189   class oriented_point3d : public point3d {
00190   public:
00191     normal3d n;
00192 
00193     explicit oriented_point3d() : point3d() {}
00194   oriented_point3d(const point3d& p) : point3d(p) {}
00195   oriented_point3d(double xx, double yy, double zz) : point3d(xx,yy,zz) {}
00196   oriented_point3d(const oriented_point3d& p) : point3d(p), n(p.n) {}
00197   oriented_point3d(const point3d& p, const normal3d& nn) : point3d(p), n(nn) {}
00198   };
00199 
00200 
00201   struct triangle
00202   {
00203     oriented_point3d p0, p1, p2;
00204     int id0, id1, id2; // indices to vertices p0, p1, p2
00205     normal3d n;
00206   triangle() : id0(-1), id1(-1), id2(-1) {}
00207   triangle(int id0, int id1, int id2) : id0(id0), id1(id1), id2(id2) {}
00208   triangle(const oriented_point3d& p0_, const oriented_point3d& p1_, const oriented_point3d& p2_, const normal3d& n_)
00209   : p0(p0_), p1(p1_), p2(p2_), n(n_) {}
00210   triangle(const oriented_point3d& p0_, const oriented_point3d& p1_, const oriented_point3d& p2_, const normal3d& n_, int id0_, int id1_, int id2_)
00211   : p0(p0_), p1(p1_), p2(p2_), id0(id0_), id1(id1_), id2(id2_), n(n_) {}
00212   triangle(const point3d& p0_, const point3d& p1_, const point3d& p2_, const normal3d& n_)
00213   : p0(p0_), p1(p1_), p2(p2_), n(n_) {}
00214     friend std::ostream& operator<<(std::ostream& o, const triangle& t)
00215     {
00216       o << t.p0 << " " << t.p1 << " " << t.p2;
00217       return o;
00218     }
00219   };
00220 
00221 
00222   class invalid_vector : public std::logic_error
00223   {
00224   public:
00225     explicit invalid_vector() : std::logic_error("Exception invalid_vector caught.") {}
00226   invalid_vector(const std::string& msg) : std::logic_error("Exception invalid_vector caught: "+msg) {}
00227   };
00228 
00229 
00230   // ==============================================================
00231   //                         Rotations
00232   // ==============================================================
00233 
00234   // NOTE: this is a std::vector derivation, thus a matrix<bool> will
00235   // take 1 bit per element.
00236 
00237   template<class T>
00238     class matrix : private std::vector<T> // row-major order
00239     {
00240     private:
00241       typedef std::vector<T> super;
00242       int width_;
00243       int height_;
00244 
00245     public:
00246 
00247       const int& width;
00248       const int& height;
00249 
00250       typedef typename super::iterator iterator;
00251       typedef typename super::const_iterator const_iterator;
00252 
00253       explicit matrix() : super(), width_(0), height_(0), width(width_), height(height_) {}
00254 
00255     matrix(int w, int h) : super(w*h), width_(w), height_(h), width(width_), height(height_) {}
00256 
00257     matrix(int w, int h, const T& v) : super(w*h, v), width_(w), height_(h), width(width_), height(height_) {}
00258 
00259     matrix(const matrix<T>& m) : super(), width(width_), height(height_)
00260       {
00261         resize(m.width_,m.height_);
00262         super::assign( m.begin(), m.end() );
00263       }
00264 
00265       typename super::reference operator() (size_t r, size_t c) { return super::operator[](r*width_+c); }
00266       typename super::const_reference operator() (size_t r, size_t c) const { return super::operator[](r*width_+c); }
00267 
00268       typename super::reference at(const size_t r, const size_t c) { return super::at(r*width_+c); }
00269       typename super::const_reference at(size_t r, size_t c) const { return super::at(r*width_+c); }
00270 
00271       const T* to_ptr() const {
00272         return &(super::operator[](0)); // ok since std::vector is guaranteed to be contiguous
00273       }
00274 
00275       T* to_ptr() {
00276         return &(super::operator[](0));
00277       }
00278 
00279       void resize(int w, int h)
00280       {
00281         super::resize(w*h);
00282         width_ = w;
00283         height_ = h;
00284       }
00285 
00286       size_t size() const { return super::size(); }
00287 
00288       iterator begin() { return super::begin(); }
00289       const_iterator begin() const { return super::begin(); }
00290       iterator end() { return super::end(); }
00291       const_iterator end() const { return super::end(); }
00292 
00293       bool operator==(const matrix<T>& m) const
00294       {
00295         if ((width_ != m.width_) || (height != m.height_ ))
00296           return false;
00297 
00298         const_iterator it1(begin()), it2(m.begin()), it1_end(end());
00299 
00300         for(; it1 != it1_end; ++it1, ++it2)
00301           if (*it1 != *it2) return false;
00302 
00303         return true;
00304       }
00305 
00306       bool operator!=(const matrix<T>& m) const { return !(*this == m); }
00307 
00308       matrix& operator=(const matrix<T>& m)
00309         {
00310           if (&m == this)
00311             return *this;
00312 
00313           if (width != m.width || height != m.height)
00314             throw invalid_vector("Cannot assign matrices with different sizes.");
00315 
00316           super::assign( m.begin(), m.end() );
00317           return *this;
00318         }
00319 
00320       template <typename S>
00321         matrix<T>& operator*=(const S& s)
00322         {
00323           for (size_t i=0; i<size(); ++i)
00324             super::operator[](i) *= T(s);
00325           return *this;
00326         }
00327 
00328       template <typename S>
00329         matrix<T>& operator/=(const S& s)
00330         {
00331           for (size_t i=0; i<size(); ++i)
00332             super::operator[](i) /= T(s);
00333           return *this;
00334         }
00335 
00336       friend std::ostream& operator<<(std::ostream& s, const matrix<T>& m)
00337       {
00338         for (int y=0; y<m.height_; ++y) {
00339           for (int x=0; x<m.width_; ++x) {
00340             s << m[y*m.width_+x] << " ";
00341           }
00342           s << std::endl;
00343         }
00344         return s;
00345       }
00346     };
00347 
00348 
00349   template<typename T>
00350     struct matrix3x3
00351     {
00352       T r00, r01, r02,
00353         r10, r11, r12,
00354         r20, r21, r22;
00355 
00356       int width, height;
00357 
00358       explicit matrix3x3()
00359         : r00(0), r01(0), r02(0)
00360         , r10(0), r11(0), r12(0)
00361         , r20(0), r21(0), r22(0)
00362         , width(3), height(3)
00363       {}
00364 
00365       template <typename S>
00366       explicit matrix3x3(const S* v)
00367       : r00(v[0]), r01(v[1]), r02(v[2])
00368         , r10(v[3]), r11(v[4]), r12(v[5])
00369         , r20(v[6]), r21(v[7]), r22(v[8])
00370         , width(3), height(3)
00371       {}
00372 
00373       void set_column(size_t c, const vec3d<T>& v)
00374       {
00375         T x = v.x;
00376         T y = v.y;
00377         T z = v.z;
00378 
00379         if (c==0) {
00380           r00 = x;
00381           r10 = y;
00382           r20 = z;
00383         }
00384         else if (c==1) {
00385           r01 = x;
00386           r11 = y;
00387           r21 = z;
00388         }
00389         else if (c==2) {
00390           r02 = x;
00391           r12 = y;
00392           r22 = z;
00393         }
00394         else
00395           throw std::logic_error("Cannot set column for 3x3 matrix.");
00396       }
00397 
00398       T& operator() (size_t row, size_t col)
00399       {
00400         switch (row) {
00401         case 0:
00402           if (col==0) return r00;
00403           if (col==1) return r01;
00404           if (col==2) return r02;
00405           else throw std::out_of_range("Cannot access element in 3x3 matrix");
00406         case 1:
00407           if (col==0) return r10;
00408           if (col==1) return r11;
00409           if (col==2) return r12;
00410           else throw std::out_of_range("Cannot access element in 3x3 matrix");
00411         case 2:
00412           if (col==0) return r20;
00413           if (col==1) return r21;
00414           if (col==2) return r22;
00415           else throw std::out_of_range("Cannot access element in 3x3 matrix");
00416         default:
00417           throw std::out_of_range("Cannot access element in 3x3 matrix");
00418         }
00419       }
00420 
00421       const T& operator() (size_t row, size_t col) const
00422       {
00423         switch (row) {
00424         case 0:
00425           if (col==0) return r00;
00426           if (col==1) return r01;
00427           if (col==2) return r02;
00428           else throw std::out_of_range("Cannot access element in 3x3 matrix");
00429         case 1:
00430           if (col==0) return r10;
00431           if (col==1) return r11;
00432           if (col==2) return r12;
00433           else throw std::out_of_range("Cannot access element in 3x3 matrix");
00434         case 2:
00435           if (col==0) return r20;
00436           if (col==1) return r21;
00437           if (col==2) return r22;
00438           else throw std::out_of_range("Cannot access element in 3x3 matrix");
00439         default:
00440           throw std::out_of_range("Cannot access element in 3x3 matrix");
00441         }
00442       }
00443 
00444       friend std::ostream& operator<<(std::ostream& s, const matrix3x3<T>& m) {
00445         s << m.r00 << " " << m.r01 << " " << m.r02 << std::endl;
00446         s << m.r10 << " " << m.r11 << " " << m.r12 << std::endl;
00447         s << m.r20 << " " << m.r21 << " " << m.r22 << std::endl;
00448         return s;
00449       }
00450     };   
00451 
00452 
00453   template <typename T>
00454     inline matrix3x3<T> identity3x3()
00455     {
00456       matrix3x3<T> m;
00457       set_identity(m);
00458       return m;
00459     }
00460 
00461 
00462   template <typename T>
00463     inline void mult_matrix_inplace(const matrix3x3<T>& m1, const matrix3x3<T>& m2, matrix3x3<T>& r)
00464     {
00465       const double r00 = m1.r00*m2.r00 + m1.r01*m2.r10 + m1.r02*m2.r20;
00466       const double r01 = m1.r00*m2.r01 + m1.r01*m2.r11 + m1.r02*m2.r21;
00467       const double r02 = m1.r00*m2.r02 + m1.r01*m2.r12 + m1.r02*m2.r22;
00468 
00469       const double r10 = m1.r10*m2.r00 + m1.r11*m2.r10 + m1.r12*m2.r20;
00470       const double r11 = m1.r10*m2.r01 + m1.r11*m2.r11 + m1.r12*m2.r21;
00471       const double r12 = m1.r10*m2.r02 + m1.r11*m2.r12 + m1.r12*m2.r22;
00472 
00473       const double r20 = m1.r20*m2.r00 + m1.r21*m2.r10 + m1.r22*m2.r20;
00474       const double r21 = m1.r20*m2.r01 + m1.r21*m2.r11 + m1.r22*m2.r21;
00475       const double r22 = m1.r20*m2.r02 + m1.r21*m2.r12 + m1.r22*m2.r22;
00476 
00477       r.r00 = r00; r.r01 = r01; r.r02 = r02;
00478       r.r10 = r10; r.r11 = r11; r.r12 = r12;
00479       r.r20 = r20; r.r21 = r21; r.r22 = r22;
00480     }
00481 
00482   template <typename T>
00483     inline void mult_matrix(const matrix3x3<T>& m1, const matrix3x3<T>& m2, matrix3x3<T>& r)
00484     {
00485       if (&r == &m1 || &r==&m2) throw std::logic_error("math3d::mult_matrix() argument alias");
00486       return mult_matrix_inplace<T>(m1,m2,r);
00487     }
00488 
00489   // NO in-place!
00490   template <typename Rot1, typename Rot2, typename Rot3>
00491     void mult_matrix(const Rot1& m1, const Rot2& m2, Rot3& r)
00492   {
00493     if ((char*)&r == (char*)&m1 || (char*)&r == (char*)&m2)
00494       throw std::logic_error("math3d::mult_matrix() argument alias");
00495 
00496     if (m1.width != m2.height || r.height != m1.height || r.width != m2.width)
00497       throw std::logic_error("Incompatible size matrices");
00498 
00499     double sum;
00500 
00501     for (int is=0; is<m1.height; ++is)
00502       {
00503         for (int jd=0; jd<m2.width; ++jd)
00504           {
00505             sum = 0.;
00506             for (int js=0; js<m1.width; ++js)
00507               {
00508                 sum += m1(is,js) * m2(js,jd);
00509               }
00510             r(is,jd) = sum;
00511           }
00512       }
00513   }
00514 
00515   // ==============================================================
00516   //                         Quaternions
00517   // ==============================================================
00518 
00519   template <typename T>
00520     struct quaternion
00521     {
00522       T w, i, j, k;
00523 
00524       explicit quaternion(T v=0) : w(v), i(0), j(0), k(0) {}
00525       //explicit quaternion(const T* p) : w(p[0]), i(p[1]), j(p[2]), k(p[3]) {}
00526     quaternion(T ww, T ii, T jj, T kk) : w(ww), i(ii), j(jj), k(kk) {}
00527 
00528       static quaternion<T> convert(const vec3d<T>& p) { return quaternion<T>(0, p.x, p.y, p.z); }
00529 
00530       static quaternion<T> convert(const T* p) { return quaternion<T>(p[0], p[1], p[2], p[3]); }
00531 
00532       quaternion<T>& operator+= (const quaternion<T>& a) {w+=a.w; i+=a.i; j+=a.j; k+=a.k; return *this;}
00533 
00534       quaternion<T>& operator*= (T a) {w*=a; i*=a; j*=a; k*=a; return *this;}
00535 
00536       void to_vector(T* p) const { p[0]=w; p[1]=i; p[2]=j; p[3]=k; }
00537 
00538       friend std::ostream& operator<<(std::ostream& os, const quaternion<T>& q)
00539       {
00540         return os << "[ " << q.w << " " << q.i << " " << q.j << " " << q.k << " ]";
00541       }
00542 
00543       friend std::istream& operator>>(std::istream& is, quaternion<T>& q)
00544       {
00545         std::string dump;
00546         return (is >> dump >> q.w >> q.i >> q.j >> q.k >> dump);
00547       }
00548     };
00549 
00550   template <typename T>
00551     quaternion<T> operator+ (const quaternion<T>& a, const quaternion<T>& b)
00552     {
00553       quaternion<T> result(a);
00554       result += b;
00555       return result;
00556     }
00557 
00558   template <typename T>
00559     T dot(const quaternion<T>& a, const quaternion<T>& b)
00560     {
00561       return a.w*b.w + a.i*b.i + a.j*b.j + a.k*b.k;
00562     }
00563 
00564   template <typename T>
00565     T norm(const quaternion<T>& a)
00566     {
00567       return std::sqrt(dot(a,a));
00568     }
00569 
00570   template <typename T>
00571     quaternion<T> operator* (const quaternion<T>& a, const quaternion<T>& b)
00572     {
00573       quaternion<T> result;
00574 
00575       result.w = a.w*b.w - a.i*b.i - a.j*b.j - a.k*b.k;
00576       result.i = a.i*b.w + a.w*b.i - a.k*b.j + a.j*b.k;
00577       result.j = a.j*b.w + a.k*b.i + a.w*b.j - a.i*b.k;
00578       result.k = a.k*b.w - a.j*b.i + a.i*b.j + a.w*b.k;
00579 
00580       return result;
00581     }
00582 
00583   template <typename T>
00584     quaternion<T> operator~ (const quaternion<T>& a)
00585     {
00586       return quaternion<T>(a.w, -a.i, -a.j, -a.k);
00587     }
00588 
00589   template <typename T>
00590     inline void conjugate(quaternion<T>& q)
00591     {
00592       q.i = -q.i;
00593       q.j = -q.j;
00594       q.k = -q.k;
00595     }
00596 
00597   template <typename T>
00598     inline void normalize(quaternion<T>& q)
00599     {
00600       T mag = q.w*q.w + q.i*q.i + q.j*q.j + q.k*q.k;
00601       if (!almost_zero(mag-T(1), 1e-10))
00602         {
00603           mag = std::sqrt(mag);
00604           q.w /= mag;
00605           q.i /= mag;
00606           q.j /= mag;
00607           q.k /= mag;
00608         }
00609     }
00610 
00611   template <typename T>
00612     inline void set_identity(quaternion<T>& q)
00613     {
00614       q.w = T(1);
00615       q.i = q.j = q.k = T(0);
00616     }
00617 
00618   // returns a normalized unit quaternion
00619   template<typename T>
00620     quaternion<T> rot_matrix_to_quaternion(const matrix3x3<T>& m)
00621     {
00622       const T m00 = m(0,0);
00623       const T m11 = m(1,1);
00624       const T m22 = m(2,2);
00625       const T m01 = m(0,1);
00626       const T m02 = m(0,2);
00627       const T m10 = m(1,0);
00628       const T m12 = m(1,2);
00629       const T m20 = m(2,0);
00630       const T m21 = m(2,1);
00631       const T tr = m00 + m11 + m22;
00632 
00633       quaternion<T> ret;
00634 
00635       if (tr > 0)
00636         {
00637           T s = std::sqrt(tr+T(1)) * 2; // S=4*qw
00638           ret.w = 0.25 * s;
00639           ret.i = (m21 - m12) / s;
00640           ret.j = (m02 - m20) / s;
00641           ret.k = (m10 - m01) / s;
00642         }
00643       else if ((m00 > m11)&(m00 > m22))
00644         {
00645           const T s = std::sqrt(T(1) + m00 - m11 - m22) * 2; // S=4*qx
00646           ret.w = (m21 - m12) / s;
00647           ret.i = 0.25 * s;
00648           ret.j = (m01 + m10) / s;
00649           ret.k = (m02 + m20) / s;
00650         }
00651       else if (m11 > m22)
00652         {
00653           const T s = std::sqrt(T(1) + m11 - m00 - m22) * 2; // S=4*qy
00654           ret.w = (m02 - m20) / s;
00655           ret.i = (m01 + m10) / s;
00656           ret.j = 0.25 * s;
00657           ret.k = (m12 + m21) / s;
00658         }
00659       else
00660         {
00661           const T s = std::sqrt(T(1) + m22 - m00 - m11) * 2; // S=4*qz
00662           ret.w = (m10 - m01) / s;
00663           ret.i = (m02 + m20) / s;
00664           ret.j = (m12 + m21) / s;
00665           ret.k = 0.25 * s;
00666         }
00667 
00668       return ret;
00669     }
00670 
00671   // assumes a normalized unit quaternion
00672   template <typename T>
00673     matrix3x3<T> quaternion_to_rot_matrix(const quaternion<T>& q)
00674     {
00675       matrix3x3<T> m;
00676       const T w = q.w, i = q.i, j = q.j, k = q.k;
00677 
00678       m(0,0) = 1 - 2*j*j - 2*k*k;
00679       m(0,1) = 2*i*j - 2*k*w;
00680       m(0,2) = 2*i*k + 2*j*w;
00681 
00682       m(1,0) = 2*i*j + 2*k*w;
00683       m(1,1) = 1 - 2*i*i - 2*k*k;
00684       m(1,2) = 2*j*k - 2*i*w;
00685 
00686       m(2,0) = 2*i*k - 2*j*w;
00687       m(2,1) = 2*j*k + 2*i*w;
00688       m(2,2) = 1 - 2*i*i - 2*j*j;
00689 
00690       return m;
00691     }
00692 
00693   template <typename T>
00694     inline void mult_quaternion(const quaternion<T>& a, const quaternion<T>& b, quaternion<T>& r)
00695     {
00696       r.w = a.w*b.w - (a.i*b.i + a.j*b.j + a.k*b.k);
00697       r.i = a.w*b.i + b.w*a.i + a.j*b.k - a.k*b.j;
00698       r.j = a.w*b.j + b.w*a.j + a.k*b.i - a.i*b.k;
00699       r.k = a.w*b.k + b.w*a.k + a.i*b.j - a.j*b.i;
00700     }
00701 
00702   // ==============================================================
00703   //
00704   // ==============================================================
00705 
00706   template <typename T>
00707     void transpose(matrix<T>& m)
00708     {
00709       matrix<T> old(m);
00710       const int w = m.width;
00711       const int h = m.height;
00712       m.resize(h,w);
00713 
00714       for (int row=0; row<h; ++row) {
00715         for (int col=0; col<w; ++col) {
00716           m(col,row) = old(row,col);
00717         }
00718       }
00719     }
00720 
00721   template <typename T>
00722     inline void transpose(matrix3x3<T>& m)
00723     {
00724       const T m01 = m.r01, m02 = m.r02, m12 = m.r12, m10 = m.r10, m21 = m.r21, m20 = m.r20;
00725       m.r01 = m10; m.r02 = m20;
00726       m.r10 = m01; m.r20 = m02;
00727       m.r12 = m21; m.r21 = m12;
00728     }
00729 
00730   template <typename T>
00731     inline matrix3x3<T> get_transpose(const matrix3x3<T>& m)
00732     {
00733       matrix3x3<T> ret;
00734       ret.r00 = m.r00; ret.r01 = m.r10; ret.r02 = m.r20;
00735       ret.r10 = m.r01; ret.r11 = m.r11; ret.r20 = m.r02;
00736       ret.r12 = m.r21; ret.r21 = m.r12; ret.r22 = m.r22;
00737       return ret;
00738     }
00739 
00740   // dest matrix must already be of the right size
00741   template <typename T>
00742     void transpose(const matrix<T>& src, matrix<T>& dest)
00743     {
00744       if (src.width != dest.height || src.height != dest.width)
00745         throw math3d::invalid_vector("math3d::transpose(): Destination matrix must be of the right size.");
00746 
00747       const int w = src.width;
00748       const int h = src.height;
00749 
00750       for (int row=0; row<h; ++row) {
00751         for (int col=0; col<w; ++col) {
00752           dest(col,row) = src(row,col);
00753         }
00754       }
00755     }
00756 
00757   template <typename T>
00758     inline void transpose(const matrix3x3<T>& src, matrix3x3<T>& dest)
00759     {
00760       dest.r00 = src.r00; dest.r11 = src.r11; dest.r22 = src.r22;
00761       dest.r01 = src.r10; dest.r02 = src.r20;
00762       dest.r10 = src.r01; dest.r12 = src.r21;
00763       dest.r21 = src.r12; dest.r20 = src.r02;
00764     }
00765 
00766   template <typename T>
00767     void set_identity(matrix<T>& m, T val=1)
00768     {
00769       if (m.width != m.height)
00770         throw invalid_vector("Cannot set identity on a rectangular matrix.");
00771 
00772       if (m.width == 0)
00773         return;
00774 
00775       const int n = m.width * m.height;
00776       const int w = m.width;
00777 
00778       int one = 0;
00779       for (int k=0; k<n; ++k)
00780         {
00781           if (k == one) {
00782             m(k / w, k % w) = val;
00783             one += w+1;
00784           }
00785           else
00786             m(k / w, k % w) = 0;
00787         }
00788     }
00789 
00790   template <typename T>
00791     void set_identity(matrix3x3<T>& m, T val=1)
00792     {
00793       m.r00 = val; m.r01 = 0; m.r02 = 0;
00794       m.r10 = 0; m.r11 = val; m.r12 = 0;
00795       m.r20 = 0; m.r21 = 0; m.r22 = val;
00796     }
00797 
00798 
00799   // ==============================================================
00800   //                         Rigid Motion
00801   // ==============================================================
00802 
00803   typedef std::pair<matrix3x3<double>, point3d> rigid_motion_t;
00804 
00805   template <typename T>
00806     void rotate(vec3d<T>& p, const matrix<T>& rot)
00807     {
00808       if (rot.height != 3 || rot.width != 3)
00809         throw std::logic_error("Rotation matrix must be 3x3");
00810 
00811       T oldx = p.x, oldy = p.y, oldz = p.z;
00812       p.x = oldx*rot(0,0) + oldy*rot(0,1) + oldz*rot(0,2);
00813       p.y = oldx*rot(1,0) + oldy*rot(1,1) + oldz*rot(1,2);
00814       p.z = oldx*rot(2,0) + oldy*rot(2,1) + oldz*rot(2,2);
00815     }
00816 
00817   template <typename T>
00818     void rotate(vec3d<T>& p, const matrix3x3<T>& rot)
00819     {
00820       T oldx = p.x, oldy = p.y, oldz = p.z;
00821       p.x = oldx*rot.r00 + oldy*rot.r01 + oldz*rot.r02;
00822       p.y = oldx*rot.r10 + oldy*rot.r11 + oldz*rot.r12;
00823       p.z = oldx*rot.r20 + oldy*rot.r21 + oldz*rot.r22;
00824     }
00825 
00826   template <typename T, typename S>
00827     void rotate(vec3d<T>& p, const matrix<S>& rot)
00828   {
00829     if (rot.height != 3 || rot.width != 3)
00830       throw std::logic_error("Rotation matrix must be 3x3");
00831 
00832     T oldx = p.x, oldy = p.y, oldz = p.z;
00833     p.x = T( oldx*rot(0,0) + oldy*rot(0,1) + oldz*rot(0,2) );
00834     p.y = T( oldx*rot(1,0) + oldy*rot(1,1) + oldz*rot(1,2) );
00835     p.z = T( oldx*rot(2,0) + oldy*rot(2,1) + oldz*rot(2,2) );
00836   }
00837 
00838   template <typename T, typename S>
00839     inline void rotate(vec3d<T>& p, const matrix3x3<S>& rot)
00840   {
00841     T oldx = p.x, oldy = p.y, oldz = p.z;
00842     p.x = T( oldx*rot.r00 + oldy*rot.r01 + oldz*rot.r02 );
00843     p.y = T( oldx*rot.r10 + oldy*rot.r11 + oldz*rot.r12 );
00844     p.z = T( oldx*rot.r20 + oldy*rot.r21 + oldz*rot.r22 );
00845   }
00846 
00847   template <typename T>
00848     inline void rotate(vec3d<T>& p, const quaternion<T>& rot)
00849     {
00850       rotate(p, quaternion_to_rot_matrix(rot));
00851     }
00852 
00853 
00854   template <typename T>
00855     inline vec3d<T> get_rotate(const vec3d<T>& v, const quaternion<T>& q)
00856     {
00857       return get_rotate(v, quaternion_to_rot_matrix(q));
00858       /*
00859         const T
00860         a = q.w, b = q.i, c = q.j, d = q.k,
00861         t2 = a*b, t3 = a*c, t4 = a*d, t5 = -b*b, t6 = b*c,
00862         t7 = b*d, t8 = -c*c, t9 = c*d, t10 = -d*d,
00863         v1 = v.x, v2 = v.y, v3 = v.z;
00864         return vec3d<T>(
00865         2*( (t8 + t10)*v1 + (t6 -  t4)*v2 + (t3 + t7)*v3 ) + v1,
00866         2*( (t4 +  t6)*v1 + (t5 + t10)*v2 + (t9 - t2)*v3 ) + v2,
00867         2*( (t7 -  t3)*v1 + (t2 +  t9)*v2 + (t5 + t8)*v3 ) + v3);
00868       */
00869     }
00870 
00871   template <typename T>
00872     inline vec3d<T> get_rotate(const vec3d<T>& p, const matrix3x3<T>& rot)
00873     {
00874       return vec3d<T>(p.x*rot.r00 + p.y*rot.r01 + p.z*rot.r02,
00875                       p.x*rot.r10 + p.y*rot.r11 + p.z*rot.r12,
00876                       p.x*rot.r20 + p.y*rot.r21 + p.z*rot.r22);
00877     }
00878 
00879 
00880   template <typename T, typename RotationType>
00881     inline void rotate_translate(vec3d<T>& v, const RotationType& rot, const point3d& trans)
00882   {
00883     rotate(v, rot);
00884     v += trans;
00885   }
00886 
00887   template <typename T>
00888     inline vec3d<T> get_rotate_translate(const vec3d<T>& p, const matrix3x3<T>& rot, const point3d& t)
00889     {
00890       return vec3d<T>(p.x*rot.r00 + p.y*rot.r01 + p.z*rot.r02 + t.x,
00891                       p.x*rot.r10 + p.y*rot.r11 + p.z*rot.r12 + t.y,
00892                       p.x*rot.r20 + p.y*rot.r21 + p.z*rot.r22 + t.z);
00893     }
00894 
00895   template <typename T>
00896     inline vec3d<T> get_rotate_translate(const vec3d<T>& p, const matrix<T>& rot, const point3d& t)
00897     {
00898       if (rot.height != 3 || rot.width != 3)
00899         throw std::logic_error("Rotation matrix must be 3x3");
00900 
00901       return vec3d<T>(p.x*rot(0,0) + p.y*rot(0,1) + p.z*rot(0,2) + t.x,
00902                       p.x*rot(1,0) + p.y*rot(1,1) + p.z*rot(1,2) + t.y,
00903                       p.x*rot(2,0) + p.y*rot(2,1) + p.z*rot(2,2) + t.z);
00904     }
00905 
00906   template <typename T>
00907     inline vec3d<T> get_rotate_translate(const vec3d<T>& p, const T* rot, const T* t)
00908     {
00909       return get_rotate_translate(p, matrix3x3<T>(rot), vec3d<T>(t[0],t[1],t[2]));
00910     }
00911 
00912   template <typename T>
00913     inline vec3d<T> get_rotate_translate(const vec3d<T>& v, const quaternion<T>& rot, const point3d& t)
00914     {
00915       return (get_rotate(v, rot) + t);
00916     }
00917 
00918 
00922   template <typename R, typename T>
00923     inline void invert(R& r, T& t)
00924   {
00925     transpose(r);
00926     rotate(t, r);
00927     t.x = -t.x; t.y = -t.y; t.z = -t.z;
00928   }
00929 
00930 
00935   template <typename T>
00936     void relative_motion(
00937 
00938                          const matrix3x3<T>& Ri, const point3d& Ti,
00939                          const matrix3x3<T>& Rj, const point3d& Tj,
00940                          matrix3x3<T>& Rij, point3d& Tij
00941 
00942                          ){
00943     matrix3x3<T> Ri_inv = Ri;
00944     point3d Ti_inv = Ti;
00945     invert(Ri_inv, Ti_inv);
00946 
00947     mult_matrix(Ri_inv, Rj, Rij);
00948     Tij = get_rotate_translate(Tj, Ri_inv, Ti_inv);
00949   }
00950 
00951 
00952   // ==============================================================
00953   //                      Vector Operations
00954   // ==============================================================
00955 
00956   template <typename T>
00957     inline double normalize(vec3d<T>& p)
00958     {
00959       const double n = magnitude(p);
00960       if (n==0.) {
00961         p.x = 0;
00962         p.y = 0;
00963         p.z = 0;
00964       }
00965       else {
00966         p.x /= n;
00967         p.y /= n;
00968         p.z /= n;
00969       }
00970       return n;
00971     }
00972 
00973   template <typename T>
00974     inline vec3d<T> get_normalize(const vec3d<T>& p)
00975     {
00976       vec3d<T> q(p);
00977       normalize(q);
00978       return q;
00979     }
00980 
00981   template <typename T>
00982     inline double dist(const T& p1, const T& p2)
00983     {
00984       const double sqdist = squared_dist(p1,p2);
00985       return (sqdist == 0. ? 0. : std::sqrt(sqdist));
00986     }
00987 
00988   // ||p1 - p2||^2
00989   template <typename T>
00990     inline double squared_dist(const vec3d<T>& p1, const vec3d<T>& p2)
00991     {
00992       T x = p1.x - p2.x;
00993       T y = p1.y - p2.y;
00994       T z = p1.z - p2.z;
00995       return ((x*x) + (y*y) + (z*z));
00996     }
00997 
00998   template <typename T>
00999     inline T dot_product(const vec3d<T>& v1, const vec3d<T>& v2) {
01000     return (v1.x*v2.x) + (v1.y*v2.y) + (v1.z*v2.z);
01001   }
01002 
01003   template <typename T, typename S>
01004     inline double dot_product(const vec3d<T>& v1, const vec3d<S>& v2) {
01005     return (v1.x*v2.x) + (v1.y*v2.y) + (v1.z*v2.z);
01006   }
01007 
01008   template <typename T>
01009     inline T dot_product(const quaternion<T>& p, const quaternion<T>& q) {
01010     return (p.w*q.w + p.i*q.i + p.j*q.j + p.k*q.k);
01011   }
01012 
01013   template <typename T>
01014     inline double norm2(const T& v)
01015     {
01016       return dot_product(v,v);
01017     }
01018 
01019   template <typename T>
01020     inline double magnitude(const T& p)
01021     {
01022       return std::sqrt(dot_product(p,p));
01023     }
01024 
01025   template <typename T>
01026     inline vec3d<T> cross_product(const vec3d<T>& v1, const vec3d<T>& v2)
01027     {
01028       return vec3d<T>(
01029                       (v1.y*v2.z) - (v1.z*v2.y),
01030                       (v1.z*v2.x) - (v1.x*v2.z),
01031                       (v1.x*v2.y) - (v1.y*v2.x)
01032                       );
01033     }
01034 
01035 
01036   template <typename Iterator>
01037     inline double median(Iterator start, Iterator end)
01038     {
01039       const typename Iterator::difference_type n = end - start;
01040       if (n <= 0) return 0.;
01041 
01042       if (n % 2 == 0)
01043         return (*(start+(n/2)) + *(start+(n/2-1))) / 2.;
01044       else
01045         return *(start + ( (n-1) / 2 ));
01046     }
01047 
01048 }
01049 
01050 #endif


trac_ik_lib
Author(s): Patrick Beeson, Barrett Ames
autogenerated on Thu Sep 21 2017 02:53:02