vector3.cpp

00001 #include <math.h>
00002 #include <assert.h>
00003 #include "vector3.h"
00004 
00005 
00006 using namespace Geometry;
00007 using namespace std;
00008 
00009 
00010 
00011 // Aux. function that translates a value to a valid interval
00012 double normalize(double min, double max, double value)
00013 {
00014   double distance = max - min;
00015   if (distance <= 0)
00016     {
00017       cerr << __FILE__ << ": min > max in \"normalize\" function" << endl;
00018       return value;
00019     }
00020 
00021   while (value > max)
00022     value -= distance;
00023 
00024   while (value < min)
00025     value += distance;
00026 
00027   return value;
00028 }
00029 
00030 
00031 
00032 // Default constructor
00033 template <class T> Vector3D<T>::Vector3D()
00034 {
00035         for (unsigned i=0 ; i<DIM ; i++)
00036                 _data[i] = (T) 0.0;
00037 }
00038 
00039 // Constructor
00040 template <class T> Vector3D<T>::Vector3D(const T& x, const T& y, const T& z)
00041 {
00042   _data[0] = x;
00043   _data[1] = y;
00044   _data[2] = z;
00045 }
00046 
00047 // Constructor
00048 template <class T> Vector3D<T>::Vector3D(const T data[3])
00049 {
00050         for (unsigned i=0 ; i<DIM ; i++)
00051                 _data[i] = data[i];
00052 }
00053 
00054 // Copy constructor
00055 template <class T> Vector3D<T>::Vector3D(const Vector3D<T>& v)
00056 {
00057         for (unsigned i=0 ; i<DIM ; i++)
00058                 _data[i] = v._data[i];
00059 }
00060 
00061 // Copy constructor
00062 template <class T> Vector3D<T>::Vector3D(const vector<T>& v)
00063 {
00064         assert(v.size() >= DIM);
00065         for (unsigned i=0 ; i<DIM ; i++)
00066                 _data[i] = v[i];
00067 }
00068 
00069 // Constructor
00070 template <class T> Vector3D<T>::Vector3D(const Vector3D<T>* v)
00071 {
00072         for (unsigned i=0 ; i<DIM ; i++)
00073                 _data[i] = v->_data[i];
00074 }
00075 
00076 
00077 // Simple global "set" method
00078 template <class T> void Vector3D<T>::set(const T&x, const T& y, const T& z)
00079 {
00080   _data[0] = x;
00081   _data[1] = y;
00082   _data[2] = z;
00083 }
00084 
00085 
00086 // Simple global "set" method
00087 template <class T> void Vector3D<T>::set(const T data[3])
00088 {
00089         for (unsigned i=0 ; i<DIM ; i++)
00090                 _data[i] = data[i];
00091 }
00092 
00093 
00094 // Copy operator
00095 template <class T> Vector3D<T>& Vector3D<T>::operator=(const Vector3D<T>& src)
00096 {
00097         for (unsigned i=0 ; i<DIM ; i++)
00098                 _data[i] = src._data[i];
00099 
00100   return *this;
00101 }
00102 
00103 // Comparison operator
00104 template <class T> bool Vector3D<T>::operator==(const Vector3D<T>& src) const
00105 {
00106         for (unsigned i=0 ; i<DIM ; i++)
00107                 if (ABS(_data[i] - src._data[i]) > ALMOST_ZERO)
00108                         return false;
00109 
00110         return true;
00111 }
00112 
00113 // Comparison operator, admittedly arbitrary, yet necessary for
00114 // using the class in many STL algorithms and containers.
00115 template <class T> bool Vector3D<T>::operator<(const Vector3D<T>& src) const
00116 {
00117         for (unsigned i=0 ; i<DIM ; i++)
00118                 {
00119                         if (_data[i] < src._data[i])
00120                                 return true;
00121                         if (_data[i] > src._data[i])
00122                                 return false;
00123                 }
00124 
00125         return false;
00126 }
00127 
00128 // Normalizes a vector (sets the module to 1)
00129 template <class T> void Vector3D<T>::normalize()
00130 {
00131   double mod = module();
00132         *this /= mod;
00133 }
00134 
00135 // Sets the length of a vector 
00136 template <class T> void Vector3D<T>::setLength(T len)
00137 {
00138   double mod = module();
00139         *this *= len/mod;
00140 }
00141 
00142 
00143 // Returns the square of the module of the vector.
00144 // Equivalent to module(), faster when only relative comparisons are needed.
00145 template <class T> double Vector3D<T>::squaredModule() const
00146 {
00147         T sum(0);
00148         for (unsigned i=0 ; i<DIM ; i++)
00149                 sum += _data[i]*_data[i];
00150 
00151   return sum;
00152 }
00153 
00154 
00155 // Accesses an element of the vector
00156 template <class T> T& Vector3D<T>::operator[](int index)
00157 {
00158   return _data[index];
00159 }
00160 
00161 // Accesses an element of the vector
00162 template <class T> const T& Vector3D<T>::operator[](int index) const
00163 {
00164   return _data[index];
00165 }
00166 
00167 // Calculates the angle between 2 vectors
00168 template <class T> double Vector3D<T>::angle(const Vector3D<T>& v) const
00169 {
00170   Vector3D<T> local(*this);
00171   Vector3D<T> param(v);
00172 
00173   double m = module();
00174   assert(!isnan(m));
00175 
00176   double mv = v.module();
00177   assert(!isnan(mv));
00178 
00179   double mod = m*mv;
00180   assert(!isnan(mod));
00181 
00182   if ( mod < ALMOST_ZERO )
00183     return 0.0;
00184 
00185   local /= m;
00186   param /= mv;
00187 
00188   double dp = local*param;
00189   assert(!isnan(dp));
00190 
00191         // Clamp the value to [-1,1], for sanity
00192   if (dp > 1.0)
00193     dp = 1.0;
00194   else if (dp < -1.0)
00195     dp = -1.0;
00196 
00197   assert(!isnan(acos(dp)));
00198   return acos( dp );
00199 }
00200 
00201 
00202 // Calculates the square of the distance between 2 vectors.
00203 // Faster than ::distance, for when only comparisons are needed.
00204 template <class T> double Vector3D<T>::squaredDistance(const Vector3D<T>& v) const
00205 {
00206         T sum(0);
00207         for (unsigned i=0 ; i<DIM ; i++)
00208                 {
00209                         T diff = _data[i] - v._data[i];
00210                         sum += diff * diff;
00211                 }
00212 
00213   return sum;
00214 }
00215 
00216 // Computes the infinite-degree distance to 'v'
00217 template <class T> double Vector3D<T>::infDistance(const Vector3D<T>& v) const
00218 {
00219         T soFar(0);
00220         for (unsigned i=0 ; i<DIM ; i++)
00221                 {
00222                         T diff = ABS(_data[i] - v._data[i]);
00223                         if (diff > soFar)
00224                                 soFar = diff;
00225                 }
00226 
00227   return soFar;
00228 }
00229 
00230 // Computes the degree-1 (Manhattan) distance to 'v'
00231 template <class T> double Vector3D<T>::manhattanDistance(const Vector3D<T>& v) const
00232 {
00233         T sum(0);
00234         for (unsigned i=0 ; i<DIM ; i++)
00235                 sum += ABS(_data[i] - v._data[i]);
00236 
00237   return sum;
00238 }
00239 
00240 // Calculates the distance between a point in space and a plane represented
00241 // as a point on that plane and the plane normal.
00242 // This distance is signed, as it considers the positive and negative sides of the plane.
00243 template <class T> double Vector3D<T>::distanceToPlane(const Vector3D<T>& P, const Vector3D<T>& N) const
00244 {
00245   assert( fabs(N.squaredModule() - 1) < ALMOST_ZERO );
00246 
00247   return (P-*this) * N;
00248 }
00249 
00250 
00251 
00252 // Rotates a vector around the X axis
00253 template <class T> void Vector3D<T>::rotateX(double angle)
00254 {
00255         double y = _data[1];
00256         double z = _data[2];
00257         double cosine = cos(angle);
00258         double sine = sin(angle);
00259 
00260         _data[1] = (T) (y*cosine - z*sine);
00261         _data[2] = (T) (y*sine + z*cosine);
00262 }
00263 
00264 
00265 // Rotates a vector around the Y axis
00266 template <class T> void Vector3D<T>::rotateY(double angle)
00267 {
00268   double x = _data[0];
00269   double z = _data[2];
00270   double cosine = cos(angle);
00271   double sine = sin(angle);
00272 
00273   _data[2] = (T) (z*cosine - x*sine);
00274   _data[0] = (T) (z*sine + x*cosine);
00275 }
00276 
00277 // Rotates a vector around the Z axis
00278 template <class T> void Vector3D<T>::rotateZ(double angle)
00279 {
00280   double x = _data[0];
00281   double y = _data[1];
00282   double cosine = cos(angle);
00283   double sine = sin(angle);
00284 
00285   _data[0] = (T) (x*cosine - y*sine);
00286   _data[1] = (T) (x*sine + y*cosine);
00287 }
00288 
00289 
00290 // Produces the rotation of the vector around an axis.
00291 // Precondition: *this and axis are unit vectors
00292 template <class T> Vector3D<T> Vector3D<T>::rotation(const Vector3D<T>& axis, double angle) const
00293 {
00294         Vector3D<T> Y = axis ^ (*this);
00295         assert(fabs(Y.squaredModule() - 1) < 0.0001);
00296         
00297         double cosine = cos(angle);
00298         double sine = sin(angle);
00299 
00300         return Y*sine + (*this)*cosine;
00301 }
00302 
00303 // Calculates the dot product of 2 vectors
00304 template <class T> T Vector3D<T>::operator*(const Vector3D<T>& v) const
00305 {
00306         T sum(0);
00307         for (unsigned i=0 ; i<DIM ; i++)
00308                 sum += _data[i] * v._data[i];
00309 
00310   return sum;
00311 }
00312 
00313 // Calculates the dot product of 2 vectors, the second being an STD vector
00314 template <class T> T Vector3D<T>::operator*(const std::vector<T>& v) const
00315 {
00316         assert(v.size() >= (unsigned) dim());
00317         T sum(0);
00318         for (unsigned i=0 ; i<DIM ; i++)
00319                 sum += _data[i] * v[i];
00320 
00321   return sum;
00322 }
00323 
00324 // Divides a vector by a scalar factor
00325 template <class T> Vector3D<T> Vector3D<T>::operator/(T factor) const
00326 {
00327   return Vector3D<T>(_data[0]/factor, _data[1]/factor, _data[2]/factor);
00328 }
00329 
00330 // Multiplies a vector by a scalar factor and assigns the result to itself
00331 template <class T> const Vector3D<T>& Vector3D<T>::operator/=(T factor)
00332 {
00333         for (unsigned i=0 ; i<DIM ; i++)
00334                 _data[i] /= factor;
00335 
00336   return *this;
00337 }
00338 
00339 // Multiplies a vector by a scalar factor
00340 template <class T> Vector3D<T> Vector3D<T>::operator*(T factor) const
00341 {
00342   return Vector3D<T>(_data[0]*factor, _data[1]*factor, _data[2]*factor);
00343 }
00344 
00345 #if 0
00346 // Multiplies a vector by a scalar factor
00347 template <class T> Vector3D<T> operator*(T factor, const Vector3D<T>& v)
00348 {
00349   return v*factor;
00350 }
00351 #endif
00352 
00353 // Multiplies a vector by a scalar factor and assigns the result to itself
00354 template <class T> const Vector3D<T>& Vector3D<T>::operator*=(T factor)
00355 {
00356         for (unsigned i=0 ; i<DIM ; i++)
00357                 _data[i] *= factor;
00358 
00359   return *this;
00360 }
00361 
00362 // Returns the cross product of 2 vectors
00363 template <class T> Vector3D<T> Vector3D<T>::operator^(const Vector3D<T>& v) const
00364 {
00365   return Vector3D<T>( (_data[1] * v._data[2]) - (v._data[1] * _data[2]),
00366                       (_data[2] * v._data[0]) - (v._data[2] * _data[0]),
00367                       (_data[0] * v._data[1]) - (v._data[0] * _data[1]) );
00368 }
00369 
00370 
00371 // Returns the difference vector between 2 vectors
00372 template <class T> Vector3D<T> Vector3D<T>::operator-(const Vector3D<T>& v) const
00373 {
00374   return Vector3D<T>( _data[0] - v._data[0],
00375                       _data[1] - v._data[1],
00376                       _data[2] - v._data[2] );
00377 }
00378 
00379 
00380 // Substracts one vector to another
00381 template <class T> const Vector3D<T>& Vector3D<T>::operator-=(const Vector3D<T>& v)
00382 {
00383         for (unsigned i=0 ; i<DIM ; i++)
00384                 _data[i] -= v._data[i];
00385 
00386   return *this;
00387 }
00388 
00389 
00390 // Returns a vector summation
00391 template <class T> Vector3D<T> Vector3D<T>::operator+(const Vector3D<T>& v) const
00392 {
00393   return Vector3D<T>( _data[0] + v._data[0],
00394                       _data[1] + v._data[1],
00395                       _data[2] + v._data[2] );
00396 }
00397 
00398 
00399 // Adds a vector to another one
00400 template <class T> const Vector3D<T>& Vector3D<T>::operator+=(const Vector3D<T>& v)
00401 {
00402         for (unsigned i=0 ; i<DIM ; i++)
00403                 _data[i] += v._data[i];
00404 
00405   return *this;
00406 }
00407 
00408 // Calculates the spherical coordinates for the vector, except the distance
00409 template <class T> void Vector3D<T>::getSpheric(double& theta, double& phi) const
00410 {
00411   double distance = sqrt( x()*x() + y()*y() + z()*z() );
00412   assert(distance != 0.0);
00413 
00414   theta = atan2(y(), x());
00415   phi = acos(z() / distance);
00416 
00417   //    theta = ::normalize(-M_PI, M_PI, theta);
00418   //    phi = ::normalize(0, M_PI, phi);
00419 }
00420 
00421 // Calculates the spherical coordinates for the vector
00422 template <class T> void Vector3D<T>::getSpheric(double& distance, double& theta, double& phi) const
00423 {
00424   distance = sqrt( x()*x() + y()*y() + z()*z() );
00425   theta = atan2(y(), x());
00426   phi = acos(z() / distance);
00427 
00428   assert( (theta >= -M_PI) && (theta <= M_PI) );
00429   assert( (phi >= 0) && (phi <= M_PI) );
00430 }
00431 
00432 // Sets the values of the vector given its spheric coordinates
00433 template <class T> void Vector3D<T>::setSpheric(double distance, double theta, double phi)
00434 {
00435   //    theta = ::normalize(-M_PI, M_PI, theta);
00436   //    phi = ::normalize(0, M_PI, phi);
00437   //assert( (theta >= -M_PI) && (theta <= M_PI) );
00438   //assert( (phi >= 0) && (phi <= M_PI) );
00439 
00440   double sinPhi = sin(phi);
00441 
00442   x( (T) (distance * cos(theta) * sinPhi) );
00443   y( (T) (distance * sin(theta) * sinPhi) );
00444   z( (T) (distance * cos(phi)) );
00445 }
00446 
00447 
00448 // Projects the vector onto plane X
00449 template <class T> Vector3D<T> Vector3D<T>::projectX() const
00450 {
00451   return Vector3D<T>(0, _data[1], _data[2]);
00452 }
00453 
00454 // Projects the vector onto plane Y
00455 template <class T> Vector3D<T> Vector3D<T>::projectY() const
00456 {
00457   return Vector3D<T>(_data[0], 0, _data[2]);
00458 }
00459 
00460 // Projects the vector onto plane Z
00461 template <class T> Vector3D<T> Vector3D<T>::projectZ() const
00462 {
00463   return Vector3D<T>(_data[0], _data[1], 0);
00464 }
00465 
00466 // Projects the vector onto a plane crossing the origin, with normal v.
00467 // Precondition: n is assumed to be a unit vector.
00468 template <class T> Vector3D<T> Vector3D<T>::project(const Vector3D<T>& n) const
00469 {
00470         return (*this) - n * dotProduct(n);
00471 }
00472 
00473 
00474 // Project the Vector3D<T> onto a plane defined by a center and normal
00475 // The vector is supposed to be origined at (0,0,0)
00476 // Check <http://members.tripod.com/~Paul_Kirby/vector/Vplanelineint.html>
00477 // for details (a=0, b=*this, c=center, n=normal).
00478 template <class T> Vector3D<T>
00479                 Vector3D<T>::intersect(const Vector3D<T>& center, const Vector3D<T>& normal) const
00480 {
00481         return (*this) * ((center*normal) / ((*this)*normal));
00482 }
00483 
00484 
00485 // Returns a unit vector which is perpendicular to *this
00486 template <class T> Vector3D<T>
00487                 Vector3D<T>::perpendicular() const
00488 {
00489         static const Vector3D<T> X(1, 0, 0);
00490         static const Vector3D<T> Y(0, 1, 0);
00491         
00492         const Vector3D<T>& base = (fabs((*this) * X) <  fabs((*this) * Y) ? X : Y);
00493         Vector3D<T> result = base ^ (*this);
00494         result.normalize();
00495         
00496         return result;
00497 }
00498 
00499 
00500 // Instantiation of templates, needed by gcc
00501 // The fewer of these we compile, the faster the compilation
00502 //template class Vector3D<double>;
00503 template class Vector3D<float>;
00504 //template class Vector3D<int>;
00505 //template class Vector3D<short>;
00506 //template class Vector3D<char>;

Generated on Wed Apr 9 19:22:38 2008 for HalfEdge library by  doxygen 1.5.3