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