RDCode: point.h Source File

# 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