enki/Geometry.h

Go to the documentation of this file.
00001 /*
00002     Enki - a fast 2D robot simulator
00003     Copyright (C) 1999-2008 Stephane Magnenat <stephane at magnenat dot net>
00004     Copyright (C) 2004-2005 Markus Waibel <markus dot waibel at epfl dot ch>
00005     Copyright (c) 2004-2005 Antoine Beyeler <abeyeler at ab-ware dot com>
00006     Copyright (C) 2005-2006 Laboratory of Intelligent Systems, EPFL, Lausanne
00007     Copyright (C) 2006-2008 Laboratory of Robotics Systems, EPFL, Lausanne
00008     See AUTHORS for details
00009 
00010     This program is free software; the authors of any publication 
00011     arising from research using this software are asked to add the 
00012     following reference:
00013     Enki - a fast 2D robot simulator
00014     http://lis.epfl.ch/enki
00015     Stephane Magnenat <stephane at magnenat dot net>,
00016     Markus Waibel <markus dot waibel at epfl dot ch>
00017     Laboratory of Intelligent Systems, EPFL, Lausanne.
00018 
00019     You can redistribute this program and/or modify
00020     it under the terms of the GNU General Public License as published by
00021     the Free Software Foundation; either version 2 of the License, or
00022     (at your option) any later version.
00023 
00024     This program is distributed in the hope that it will be useful,
00025     but WITHOUT ANY WARRANTY; without even the implied warranty of
00026     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00027     GNU General Public License for more details.
00028 
00029     You should have received a copy of the GNU General Public License
00030     along with this program; if not, write to the Free Software
00031     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00032 */
00033 
00034 #ifndef __ENKI_GEOMETRY_H
00035 #define __ENKI_GEOMETRY_H
00036 
00037 #ifdef WIN32
00038 #define _USE_MATH_DEFINES
00039 #define NOMINMAX
00040 #endif
00041 #include <cmath>
00042 #include <vector>
00043 #include <limits>
00044 #include <ostream>
00045 #include <algorithm>
00046 
00047 #ifdef _MSC_VER
00048 #define round(x) floor((x) + 0.5)
00049 #endif
00050 
00055 namespace Enki
00056 {
00058 
00065     struct Vector
00066     {
00068         double x;
00070         double y;
00071     
00073         Vector() { x = y = 0; }
00075         Vector(double v) { this->x = v; this->y = v; }
00077         Vector(double x, double y) { this->x = x; this->y = y; }
00079         Vector(double array[2]) { x = array[0]; y = array[1]; }
00080     
00082         void operator +=(const Vector &v) { x += v.x; y += v.y; }
00084         void operator -=(const Vector &v) { x -= v.x; y -= v.y; }
00086         void operator *=(double f) { x *= f; y *= f; }
00088         void operator /=(double f) { x /= f; y /= f; }
00090         Vector operator +(const Vector &v) const { Vector n; n.x = x + v.x; n.y = y + v.y; return n; }
00092         Vector operator -(const Vector &v) const { Vector n; n.x = x - v.x; n.y = y - v.y; return n; }
00094         Vector operator /(double f) const { Vector n; n.x = x/f; n.y = y/f; return n; }
00096         Vector operator *(double f) const { Vector n; n.x = x*f; n.y = y*f; return n; }
00098         Vector operator -() const { return Vector(-x, -y); }
00099     
00101         double operator *(const Vector &v) const { return x*v.x + y*v.y; }
00103         double norm(void) const { return sqrt(x*x + y*y); }
00105         double norm2(void) const { return x*x+y*y; }
00107         double cross(const Vector &v) const { return x * v.y - y * v.x; }
00109         Vector unitary(void) const { if (norm() < std::numeric_limits<double>::epsilon()) return Vector(); return *this / norm(); }
00111         double angle(void) const { return atan2(y, x); }
00113         Vector perp(void) const { return Vector(-y, x); }
00114         
00116         Vector crossWithZVector(double l) const { return Vector(y * l, -x * l); }
00118         Vector crossFromZVector(double l) const { return Vector(-y * l, x * l); }
00119         
00121         bool operator <(const Vector& that) const { if (this->x == that.x) return (this->y < that.y); else return (this->x < that.x); }
00122     };
00123     
00125     std::ostream & operator << (std::ostream & outs, const Vector &vector);
00126     
00128 
00129     typedef Vector Point;
00130     
00132 
00139     struct Matrix22
00140     {
00141         // line-column component
00143         double _11;
00145         double _21;
00147         double _12;
00149         double _22;
00150     
00152         Matrix22() { _11 = _21 = _12 = _22 = 0; }
00154         Matrix22(double _11, double _21, double _12, double _22) { this->_11 = _11; this->_21 = _21; this->_12 = _12; this->_22 = _22; }
00156         Matrix22(double alpha) { _11 = cos(alpha); _21 = sin(alpha); _12 = -_21; _22 = _11; }
00158         Matrix22(double array[4]) { _11=array[0]; _21=array[1]; _12=array[2]; _22=array[3]; }
00159         
00161         void zeros() { _11 = _21 = _12 = _22 = 0; }
00162         
00164         void operator +=(const Matrix22 &v) { _11 += v._11; _21 += v._21; _12 += v._12; _22 += v._22; }
00166         void operator -=(const Matrix22 &v) { _11 -= v._11; _21 -= v._21; _12 -= v._12; _22 -= v._22; }
00168         void operator *=(double f) { _11 *= f; _21 *= f; _12 *= f; _22 *= f; }
00170         void operator /=(double f) { _11 /= f; _21 /= f; _12 /= f; _22 /= f; }
00172         Matrix22 operator +(const Matrix22 &v) const { Matrix22 n; n._11 = _11 + v._11; n._21 = _21 + v._21; n._12 = _12 + v._12; n._22 = _22 + v._22; return n; }
00174         Matrix22 operator -(const Matrix22 &v) const { Matrix22 n; n._11 = _11 - v._11; n._21 = _21 - v._21; n._12 = _12 - v._12; n._22 = _22 - v._22; return n; }
00176         Matrix22 operator *(double f) const { Matrix22 n; n._11 = _11 * f; n._21 = _21 * f; n._12 = _12 * f; n._22 = _22 * f; return n; }
00178         Matrix22 operator /(double f) const { Matrix22 n; n._11 = _11 / f; n._21 = _21 / f; n._12 = _12 / f; n._22 = _22 / f; return n; }
00179         
00181         Point operator*(const Point &v) const { Point n; n.x = v.x*_11 + v.y*_12; n.y = v.x*_21 + v.y*_22; return n; }
00182         
00184         static Matrix22 fromDiag(double _1, double _2 ) { return Matrix22(_1, 0, 0, _2); }
00185     };
00186     
00188 
00189     struct Segment
00190     {
00192         Segment(double ax, double ay, double bx, double by) { this->a.x = ax; this->a.y = ay; this->b.x = bx; this->b.y = by; }
00194         Segment(double array[4]) { a.x = array[0]; a.y = array[1]; b.x = array[2]; b.y = array[3]; }
00196         Segment(const Point &p1, const Point &p2) { a = p1; b = p2; }
00197         
00199         Point a;
00201         Point b;
00202     
00204         double dist(const Point &p) const
00205         {
00206             const Vector n(a.y-b.y, b.x-a.x);
00207             const Vector u = n.unitary();
00208             const Vector ap = p-a;
00209             return ap * u;
00210         }
00211     
00213         bool doesIntersect(const Segment &o) const
00214         {
00215             const double s2da = dist (o.a);
00216             const double s2db = dist (o.b);
00217             const double s1da = o.dist (a);
00218             const double s1db = o.dist (b);
00219             return (s2da*s2db<0) && (s1da*s1db<0);
00220         }
00221     };
00222     
00224 
00225     struct Polygone: public std::vector<Point>
00226     {
00228         bool isPointInside(const Point& p) const
00229         {
00230             for (size_t i = 0; i < size(); i++)
00231             {
00232                 Segment s((*this)[i], (*this)[(i + 1) % size()]);
00233                 if (s.dist(p) < 0)
00234                     return false;
00235             }
00236             return true;
00237         }
00238         
00240         bool getAxisAlignedBoundingBox(Point& bottomLeft, Point& topRight) const
00241         {
00242             if (empty())
00243                 return false;
00244             
00245             bottomLeft = (*this)[0];
00246             topRight = (*this)[0];
00247             
00248             extendAxisAlignedBoundingBox(bottomLeft, topRight);
00249             
00250             return true;
00251         }
00252         
00254         void extendAxisAlignedBoundingBox(Point& bottomLeft, Point& topRight) const
00255         {
00256             for (const_iterator it = begin(); it != end(); ++it)
00257             {
00258                 const Point& p = *it;
00259                 
00260                 if (p.x < bottomLeft.x)
00261                     bottomLeft.x = p.x;
00262                 else if (p.x > topRight.x)
00263                     topRight.x = p.x;
00264                 
00265                 if (p.y < bottomLeft.y)
00266                     bottomLeft.y = p.y;
00267                 else if (p.y > topRight.y)
00268                     topRight.y = p.y;
00269             }
00270         }
00271         
00273         double getBoundingRadius() const
00274         {
00275             double radius = 0;
00276             for (size_t i = 0; i < size(); i++)
00277                 radius = std::max<double>(radius, (*this)[i].norm());
00278             return radius;
00279         }
00280         
00282         void translate(const Vector& delta)
00283         {
00284             for (iterator it = begin(); it != end(); ++it)
00285                 *it += delta;
00286         }
00287         
00289         void translate(const double& x, const double& y)
00290         {
00291             translate(Vector(x,y));
00292         }
00293         
00295         void rotate(double angle)
00296         {
00297             Matrix22 rot(angle);
00298             for (iterator it = begin(); it != end(); ++it)
00299                 *it = rot * (*it);
00300         }
00301         
00303         void flipX()
00304         {
00305             for (size_t i = 0; i < size(); i++)
00306                 (*this)[i].x = -(*this)[i].x;
00307             for (size_t i = 0; i < size() / 2; i++)
00308             {
00309                 Point p = (*this)[i];
00310                 (*this)[i] = (*this)[size() - i - 1];
00311                 (*this)[size() - i - 1] = p;
00312             }
00313         }
00314         
00316         void flipY()
00317         {
00318             for (size_t i = 0; i < size(); i++)
00319                 (*this)[i].y = -(*this)[i].y;
00320             for (size_t i = 0; i < size() / 2; i++)
00321             {
00322                 Point p = (*this)[i];
00323                 (*this)[i] = (*this)[size() - i - 1];
00324                 (*this)[size() - i - 1] = p;
00325             }
00326         }
00327         
00329         Polygone& operator << (const Point& p) { push_back(p); return *this; }
00330     };
00331     
00333     std::ostream & operator << (std::ostream & outs, const Polygone &polygone);
00334     
00336 
00337     inline double normalizeAngle(double angle)
00338     {
00339         while (angle > M_PI)
00340             angle -= 2*M_PI;
00341         while (angle < -M_PI)
00342             angle += 2*M_PI;
00343         return angle;
00344     }
00345   
00349 
00350     inline Point getIntersection(const Segment &s1, const Segment &s2)
00351     {
00352         // compute first segment's equation
00353         const double c1 = s1.a.y + (-s1.a.x / (s1.b.x - s1.a.x)) * (s1.b.y - s1.a.y);
00354         const double m1 = (s1.b.y - s1.a.y) / (s1.b.x - s1.a.x);
00355  
00356         // compute second segment's equation
00357         const double c2 = s2.a.y + (-s2.a.x / (s2.b.x - s2.a.x)) * (s2.b.y - s2.a.y);
00358         const double m2 = (s2.b.y - s2.a.y) / (s2.b.x - s2.a.x);
00359 
00360         // are the lines parallel ?
00361         if (m1 == m2)
00362             return Point(HUGE_VAL, HUGE_VAL);
00363 
00364         double x1 = s1.a.x;
00365         double x2 = s1.b.x;
00366         double x3 = s2.a.x;
00367         double x4 = s2.b.x;
00368         double y1 = s1.a.y;
00369         double y2 = s1.b.y;
00370         double y3 = s2.a.y;
00371         double y4 = s2.b.y;
00372 
00373         // make sure x1 < x2
00374         if (x1 > x2)
00375         {
00376             double temp = x1;
00377             x1 = x2;
00378             x2 = temp;
00379         }
00380 
00381         // make sure x3 < x4
00382         if (x3 > x4)
00383         {
00384             double temp = x3;
00385             x3 = x4;
00386             x4 = temp;
00387         }
00388 
00389         // make sure y1 < y2
00390         if (y1 > y2)
00391         {
00392             double temp = y1;
00393             y1 = y2;
00394             y2 = temp;
00395         }
00396 
00397         // make sure y3 < y4
00398         if (y3 > y4)
00399         {
00400             double temp = y3;
00401             y3 = y4;
00402             y4 = temp;
00403         }
00404 
00405         // intersection point in case of infinite slopes
00406         double x;
00407         double y;
00408 
00409         // infinite slope m1
00410         if (x1 == x2)
00411         {
00412             x = x1;
00413             y = m2 * x1 + c2;
00414             if (x > x3 && x < x4 && y > y1 && y <y2)
00415                 return Point(x, y);
00416             else
00417                 return Point(HUGE_VAL, HUGE_VAL);
00418         }
00419 
00420         // infinite slope m2
00421         if (x3 == x4)
00422         {
00423             x = x3;
00424             y = m1 * x3 + c1;
00425             if (x > x1 && x < x2 && y > y3 && y < y4)
00426                 return Point(x, y);
00427             else
00428                 return Point(HUGE_VAL, HUGE_VAL);
00429         }
00430         
00431         // compute lines intersection point
00432         x = (c2 - c1) / (m1 - m2);
00433 
00434         // see whether x in in both ranges [x1, x2] and [x3, x4]
00435         if (x > x1 && x < x2 && x > x3 && x < x4)
00436             return Point(x, m1 * x + c1);
00437   
00438         return Point(HUGE_VAL, HUGE_VAL);
00439     }
00440 }
00441 
00442 #endif

Generated on Sun Mar 1 03:10:09 2009 for Enki by  doxygen 1.5.1