00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
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
00104
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;
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
00232
00233
00234
00235
00236
00237 template<class T>
00238 class matrix : private std::vector<T>
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));
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
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
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
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
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;
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;
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;
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;
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
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
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
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
00860
00861
00862
00863
00864
00865
00866
00867
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
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
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