point.h

Go to the documentation of this file.
00001 //
00002 // Copyright (C) 2003-2008 Greg Landrum and Rational Discovery LLC
00003 //
00004 //   @@ All Rights Reserved  @@
00005 //
00006 
00007 
00008 #ifndef __RD_POINT_H__
00009 #define __RD_POINT_H__
00010 #include <iostream>
00011 #include <cmath>
00012 #include <vector>
00013 #include <map>
00014 
00015 #ifndef M_PI
00016 #define M_PI 3.14159265358979323846
00017 #endif
00018 
00019 
00020 #include <RDGeneral/Invariant.h>
00021 #include <Numerics/Vector.h>
00022 #include <boost/smart_ptr.hpp>
00023 
00024 
00025 namespace RDGeom {
00026 
00027   class Point {
00028     // this is the virtual base class, mandating certain functions
00029   public:
00030     virtual ~Point() {};
00031     
00032     virtual double operator[](unsigned int i) const = 0;
00033     virtual double& operator[](unsigned int i) = 0;
00034 
00035     virtual void normalize() = 0;
00036     virtual double length() const = 0;
00037     virtual double lengthSq() const = 0;
00038     virtual unsigned int dimension() const = 0;
00039   };
00040    
00041   //typedef class Point3D Point;
00042   class Point3D : public Point {
00043 
00044   public:
00045     double x,
00046       y,
00047       z;
00048 
00049     Point3D() : x(0.0), y(0.0), z(0.0) {};
00050     Point3D(double xv,double yv,double zv): x(xv),y(yv),z(zv) {};
00051 
00052     ~Point3D() {};
00053 
00054     Point3D(const Point3D &other) :
00055       x(other.x), y(other.y), z(other.z) {
00056     }
00057 
00058     inline unsigned int dimension() const {return 3;}
00059 
00060     inline double operator[](unsigned int i) const {
00061       PRECONDITION(i < 3, "Invalid index on Point3D");
00062       if (i == 0) {
00063         return x;
00064       } else if (i == 1) {
00065         return y;
00066       } else {
00067         return z;
00068       }
00069     }
00070         
00071     inline double& operator[](unsigned int i) {
00072       PRECONDITION(i < 3, "Invalid index on Point3D");
00073       if (i == 0) {
00074         return x;
00075       } else if (i == 1) {
00076         return y;
00077       } else {
00078         return z;
00079       }
00080     }
00081 
00082     Point3D&
00083       operator=(const Point3D &other)
00084     {
00085       x = other.x;y=other.y;z=other.z;
00086       return *this;
00087     };
00088 
00089     Point3D& operator+=(const Point3D &other) {
00090       x += other.x;
00091       y += other.y;
00092       z += other.z;
00093       return *this;
00094     };
00095  
00096     Point3D& operator-=(const Point3D &other) {
00097       x -= other.x;
00098       y -= other.y;
00099       z -= other.z;
00100       return *this;
00101     };
00102     
00103     Point3D& operator*=(double scale) {
00104       x *= scale;
00105       y *= scale;
00106       z *= scale;
00107       return *this;
00108     };  
00109 
00110     Point3D& operator/=(double scale) {
00111       x /= scale;
00112       y /= scale;
00113       z /= scale;
00114       return *this;
00115     };  
00116 
00117     Point3D operator-() const {
00118       Point3D res(x, y, z);
00119       res.x *= -1.0;
00120       res.y *= -1.0;
00121       res.z *= -1.0;
00122       return res;
00123     }
00124 
00125     void normalize() {
00126       double l = this->length();
00127       x /= l;
00128       y /= l;
00129       z /= l;
00130     };
00131 
00132     double length() const {
00133       double res = x*x+y*y+z*z;
00134       return sqrt(res);
00135     };
00136 
00137     double lengthSq() const {
00138       double res = pow(x,2) + pow(y,2) + pow(z,2);
00139       return res;
00140     };
00141 
00142     double dotProduct(const Point3D &other) const {
00143       double res = x*(other.x) + y*(other.y) + z*(other.z);
00144       return res;
00145     };
00146 
00147     /*! \brief determines the angle between a vector to this point
00148      *   from the origin and a vector to the other point.
00149      * 
00150      *  The angle is unsigned: the results of this call will always
00151      *   be between 0 and M_PI
00152      */
00153     double angleTo(const Point3D &other) const {
00154       Point3D t1,t2;
00155       t1 = *this;
00156       t2 = other;
00157       t1.normalize();
00158       t2.normalize();
00159       double dotProd = t1.dotProduct(t2);
00160       // watch for roundoff error:
00161       if(dotProd<-1.0) dotProd = -1.0;
00162       else if(dotProd>1.0) dotProd = 1.0;
00163       return acos(dotProd);
00164     }
00165 
00166     /*! \brief determines the signed angle between a vector to this point
00167      *   from the origin and a vector to the other point.
00168      * 
00169      *  The results of this call will be between 0 and M_2_PI
00170      */
00171     double signedAngleTo(const Point3D &other) const {
00172       double res=this->angleTo(other);
00173       // check the sign of the z component of the cross product:
00174       if((this->x*other.y-this->y*other.x)<-1e-6) res = 2.0*M_PI-res;
00175       return res;
00176     }
00177 
00178     /*! \brief Returns a normalized direction vector from this
00179      *   point to another.
00180      * 
00181      */
00182     Point3D directionVector(const Point3D &other) const {
00183       Point3D res;
00184       res.x = other.x - x;
00185       res.y = other.y - y;
00186       res.z = other.z - z;
00187       res.normalize();
00188       return res;
00189         
00190     }
00191 
00192     
00193     /*! \brief Cross product of this point with the another point
00194      * 
00195      * The order is important here
00196      *  The result is "this" cross with "other" not (other x this)
00197      */
00198     Point3D crossProduct(const Point3D &other) const {
00199       Point3D res;
00200       res.x = y*(other.z) - z*(other.y);
00201       res.y = -x*(other.z) + z*(other.x);
00202       res.z = x*(other.y) - y*(other.x);
00203       return res;
00204     };
00205 
00206     /*! \brief Get a unit perpendicular from this point (treating it as a vector):
00207      *
00208      */
00209     Point3D getPerpendicular() const {
00210       Point3D res(0.0,0.0,0.0);
00211       if(x){
00212         if(y){
00213           res.y = -1*x;
00214           res.x = y;
00215         } else if(z) {
00216           res.z = -1*x;
00217           res.x = z;
00218         } else {
00219           res.y = 1;
00220         }
00221       } else if(y){
00222         if(z){
00223           res.z = -1*y;
00224           res.y = z;
00225         } else {
00226           res.x = 1;
00227         }
00228       } else if(z){
00229         res.x = 1;
00230       }
00231       double l=res.length();
00232       POSTCONDITION(l>0.0,"zero perpendicular");
00233       res /= l;
00234       return res;
00235     }
00236   };
00237   
00238   // given a  set of four pts in 3D compute the dihedral angle between the
00239   // plane of the first three points (pt1, pt2, pt3) and the plane of the 
00240   // last three points (pt2, pt3, pt4)
00241   // the computed angle is between 0 and PI
00242   double computeDihedralAngle(const Point3D &pt1, const Point3D &pt2,
00243                               const Point3D &pt3, const Point3D &pt4);
00244 
00245   class Point2D : public Point {
00246   public:
00247     double x,
00248       y;
00249 
00250     Point2D() : x(0.0), y(0.0) {};
00251     Point2D(double xv,double yv): x(xv),y(yv) {};
00252     
00253     ~Point2D() {}; 
00254 
00255     Point2D(const Point2D &other) : x(other.x), y(other.y) {
00256     }
00257 
00258     inline unsigned int dimension() const {return 2;}
00259 
00260     inline double operator[](unsigned int i) const {
00261       PRECONDITION(i < 2, "Invalid index on Point2D");
00262       if (i == 0) {
00263         return x;
00264       } else { 
00265         return y;
00266       } 
00267     }
00268 
00269     inline double& operator[](unsigned int i) {
00270       PRECONDITION(i < 2, "Invalid index on Point2D");
00271       if (i == 0) {
00272         return x;
00273       } else { 
00274         return y;
00275       } 
00276     }
00277 
00278     Point2D&
00279       operator=(const Point2D &other)
00280     {
00281       x = other.x;y=other.y;
00282       return *this;
00283     };
00284 
00285     Point2D& operator+=(const Point2D &other) {
00286       x += other.x;
00287       y += other.y;
00288       return *this;
00289     };
00290 
00291     Point2D& operator-=(const Point2D &other) {
00292       x -= other.x;
00293       y -= other.y;
00294       return *this;
00295     };
00296     
00297     Point2D& operator*=(double scale){
00298       x *= scale;
00299       y *= scale;
00300       return *this;
00301     };
00302 
00303     Point2D& operator/=(double scale){
00304       x /= scale;
00305       y /= scale;
00306       return *this;
00307     };
00308 
00309     Point2D operator-() const {
00310       Point2D res(x, y);
00311       res.x *= -1.0;
00312       res.y *= -1.0;
00313       return res;
00314     }
00315       
00316     void normalize() {
00317       double ln = this->length();
00318       x /= ln;
00319       y /= ln;
00320     };
00321 
00322     void rotate90() {
00323       double temp = x;
00324       x = -y;
00325       y = temp;
00326     }
00327 
00328     double length() const {
00329       double res = pow(x,2) + pow(y,2);
00330       return sqrt(res);
00331     };
00332 
00333     double lengthSq() const {
00334       double res = x*x+y*y;
00335       return res;
00336     };
00337 
00338     double dotProduct(const Point2D &other) const {
00339       double res = x*(other.x) + y*(other.y);
00340       return res;
00341     };
00342 
00343     double angleTo(const Point2D &other) const {
00344       Point2D t1,t2;
00345       t1 = *this;
00346       t2 = other;
00347       t1.normalize();
00348       t2.normalize();
00349       double dotProd = t1.dotProduct(t2);
00350       // watch for roundoff error:
00351       if(dotProd<-1.0) dotProd = -1.0;
00352       else if(dotProd>1.0) dotProd = 1.0;
00353       return acos(dotProd);
00354     }
00355 
00356     double signedAngleTo(const Point2D &other) const {
00357       double res=this->angleTo(other);
00358       if((this->x*other.y-this->y*other.x)<-1e-6) res = 2.0*M_PI-res;
00359       return res;
00360     }
00361 
00362     Point2D directionVector(const Point2D &other) const {
00363       Point2D res;
00364       res.x = other.x - x;
00365       res.y = other.y - y;
00366       res.normalize();
00367       return res;
00368         
00369     }
00370     
00371   };
00372   
00373   class PointND : public Point {
00374   public:
00375 
00376     typedef boost::shared_ptr<RDNumeric::Vector<double> > VECT_SH_PTR;
00377 
00378     PointND(unsigned int dim){
00379       RDNumeric::Vector<double> *nvec = new RDNumeric::Vector<double>(dim, 0.0);
00380       dp_storage.reset(nvec);
00381     };
00382 
00383     PointND(const PointND &other) {
00384       RDNumeric::Vector<double> *nvec = new RDNumeric::Vector<double>(*other.getStorage());
00385       dp_storage.reset(nvec);
00386     }
00387 
00388 #if 0
00389         template <typename T>
00390     PointND(const T &vals){
00391       RDNumeric::Vector<double> *nvec = new RDNumeric::Vector<double>(vals.size(), 0.0);
00392       dp_storage.reset(nvec);
00393       unsigned int idx=0;
00394       typename T::const_iterator it;
00395       for(it=vals.begin();
00396           it!=vals.end();
00397           ++it){
00398         nvec->setVal(idx,*it);
00399         ++idx;
00400       };
00401     };
00402 #endif
00403 
00404     ~PointND() {}
00405 
00406     inline double operator[](unsigned int i) const {
00407       return dp_storage.get()->getVal(i);
00408     }
00409 
00410     inline double& operator[](unsigned int i) {
00411       return (*dp_storage.get())[i];
00412     }
00413 
00414     inline void normalize() {
00415       dp_storage.get()->normalize();
00416     }
00417 
00418     inline double length() const {
00419       return dp_storage.get()->normL2();
00420     }
00421 
00422     inline double lengthSq() const {
00423       return dp_storage.get()->normL2Sq();
00424     }
00425     
00426     unsigned int dimension() const {
00427       return dp_storage.get()->size();
00428     }
00429     
00430     PointND& operator=(const PointND &other) {
00431       RDNumeric::Vector<double> *nvec = new RDNumeric::Vector<double>(*other.getStorage());
00432       dp_storage.reset(nvec);
00433       return *this;
00434     }
00435 
00436     PointND& operator+=(const PointND &other) {
00437       (*dp_storage.get()) += (*other.getStorage());
00438       return *this;
00439     }
00440     
00441     PointND& operator-=(const PointND &other) {
00442       (*dp_storage.get()) -= (*other.getStorage());
00443       return *this;
00444     }
00445 
00446     PointND& operator*=(double scale) {
00447       (*dp_storage.get()) *= scale;
00448       return *this;
00449     }
00450 
00451     PointND& operator/=(double scale) {
00452       (*dp_storage.get()) /= scale;
00453       return *this;
00454     }
00455     
00456     PointND directionVector(const PointND &other) {
00457       PRECONDITION(this->dimension() == other.dimension(), "Point dimensions do not match");
00458       PointND np(other);
00459       np -= (*this);
00460       np.normalize();
00461       return np;
00462     }
00463 
00464     double dotProduct(const PointND &other) const {
00465       return dp_storage.get()->dotProduct(*other.getStorage());
00466     }
00467     
00468     double angleTo(const PointND &other) const {
00469       double dp = this->dotProduct(other);
00470       double n1 = this->length();
00471       double n2 = other.length();
00472       if ((n1 > 1.e-8) && (n2 > 1.e-8)) {
00473         dp /= (n1*n2);
00474       }
00475       if (dp < -1.0) dp = -1.0;
00476       else if (dp > 1.0) dp = 1.0;
00477       return acos(dp);
00478     }
00479 
00480   private:
00481     VECT_SH_PTR dp_storage;
00482     inline const RDNumeric::Vector<double> * getStorage() const {
00483       return dp_storage.get();
00484     }
00485   };
00486 
00487   typedef std::vector<RDGeom::Point *> PointPtrVect;
00488   typedef PointPtrVect::iterator PointPtrVect_I;
00489   typedef PointPtrVect::const_iterator PointPtrVect_CI;
00490 
00491   typedef std::vector<RDGeom::Point3D *> Point3DPtrVect;
00492   typedef std::vector<RDGeom::Point2D *> Point2DPtrVect;
00493   typedef Point3DPtrVect::iterator Point3DPtrVect_I;
00494   typedef Point3DPtrVect::const_iterator Point3DPtrVect_CI;
00495   typedef Point2DPtrVect::iterator Point2DPtrVect_I;
00496   typedef Point2DPtrVect::const_iterator Point2DPtrVect_CI;
00497 
00498   typedef std::vector<const RDGeom::Point3D *> Point3DConstPtrVect;
00499   typedef Point3DConstPtrVect::iterator Point3DConstPtrVect_I;
00500   typedef Point3DConstPtrVect::const_iterator Point3DConstPtrVect_CI;
00501 
00502   typedef std::vector<Point3D>                 POINT3D_VECT;
00503   typedef std::vector<Point3D>::iterator       POINT3D_VECT_I;
00504   typedef std::vector<Point3D>::const_iterator POINT3D_VECT_CI;
00505 
00506   typedef std::map<int, Point2D> INT_POINT2D_MAP;
00507   typedef INT_POINT2D_MAP::iterator INT_POINT2D_MAP_I;
00508   typedef INT_POINT2D_MAP::const_iterator INT_POINT2D_MAP_CI;
00509 
00510   std::ostream & operator<<(std::ostream& target, const RDGeom::Point &pt);
00511 
00512   RDGeom::Point3D operator+ (const RDGeom::Point3D& p1, const RDGeom::Point3D& p2);
00513   RDGeom::Point3D operator- (const RDGeom::Point3D& p1, const RDGeom::Point3D& p2);
00514   RDGeom::Point3D operator* (const RDGeom::Point3D& p1, double v);
00515   RDGeom::Point3D operator/ (const RDGeom::Point3D& p1, double v);
00516 
00517   RDGeom::Point2D operator+ (const RDGeom::Point2D& p1, const RDGeom::Point2D& p2);
00518   RDGeom::Point2D operator- (const RDGeom::Point2D& p1, const RDGeom::Point2D& p2);
00519   RDGeom::Point2D operator* (const RDGeom::Point2D& p1, double v);
00520   RDGeom::Point2D operator/ (const RDGeom::Point2D& p1, double v);
00521 
00522   RDGeom::PointND operator+ (const RDGeom::PointND& p1, const RDGeom::PointND& p2);
00523   RDGeom::PointND operator- (const RDGeom::PointND& p1, const RDGeom::PointND& p2);
00524   RDGeom::PointND operator* (const RDGeom::PointND& p1, double v);
00525   RDGeom::PointND operator/ (const RDGeom::PointND& p1, double v);
00526 }
00527 
00528 #endif

Generated on Tue Oct 7 06:10:11 2008 for RDCode by  doxygen 1.5.5