Tekkotsu Homepage
Demos
Overview
Downloads
Dev. Resources
Reference
Credits

PlannerObstacles.h

Go to the documentation of this file.
00001 //-*-c++-*-
00002 #ifndef INCLUDED_PlannerObstacles_H
00003 #define INCLUDED_PlannerObstacles_H
00004 
00005 #include <ostream>
00006 
00007 #include "Shared/fmat.h"
00008 #include "Shared/plist.h"
00009 #include "Shared/FamilyFactory.h"
00010 #include "Shared/BoundingBox.h"
00011 #include <vector>
00012 
00013 template<size_t N>
00014 class PlannerObstacle;
00015 typedef PlannerObstacle<2> PlannerObstacle2D;
00016 typedef PlannerObstacle<3> PlannerObstacle3D;
00017 
00018 class RectangularObstacle;
00019 class CircularObstacle;
00020 class EllipticalObstacle;
00021 class ConvexPolyObstacle;
00022 class HierarchicalObstacle;
00023 class BoxObstacle;
00024 class CylindricalObstacle;
00025 class SphericalObstacle;
00026 class EllipsoidObstacle;
00027 
00028 namespace plist {
00029   //! supports use of plist::ArrayOf<PlannerObstacle> for polymorphic load/save
00030   template<> PlannerObstacle2D* loadXML(xmlNode* node);
00031   template<> PlannerObstacle3D* loadXML(xmlNode* node);
00032   //! not supported
00033   template<> inline PlannerObstacle2D* allocate() {
00034     throw std::runtime_error("cannot plist::allocate generic instances (PlannerObstacle2D)");
00035   }
00036   template<> inline PlannerObstacle3D* allocate() {
00037     throw std::runtime_error("cannot plist::allocate generic instances (PlannerObstacle3D)");
00038   }
00039   template<> void inline assign<PlannerObstacle2D>(PlannerObstacle2D&, PlannerObstacle2D const&) { throw std::runtime_error("cannot assign"); }
00040   template<> void inline assign<PlannerObstacle3D>(PlannerObstacle3D&, PlannerObstacle3D const&) { throw std::runtime_error("cannot assign"); }
00041 }
00042 
00043 namespace DualCoding {
00044   class ShapeRoot;
00045 }
00046 
00047 //! Base class for all obstacles
00048 /*! Subclasses should remember to override operator= to avoid using the plist::Dictionary version
00049  *  (plist::Dictionary::operator= will only copy dictionary entries, skips other state */
00050 template <size_t N>
00051 class PlannerObstacle : public plist::Dictionary {
00052 public:
00053   //! each collision shape is assigned a prime number, these provide fast dispatch in collides()
00054   enum ObstacleGeometry {
00055     RECTANGULAR_OBS=2,
00056     CIRCULAR_OBS=3,
00057     ELLIPTICAL_OBS=5,
00058     CONVEX_POLY_OBS=7,
00059     HIERARCHICAL_OBS=11,
00060     BOX_OBS=13,
00061     CYLINDRICAL_OBS=17,
00062     SPHERICAL_OBS=19,
00063     ELLIPSOID_OBS=23
00064   };
00065   
00066   //! Default constructor
00067   explicit PlannerObstacle(ObstacleGeometry geom, const std::string& t) : plist::Dictionary(), name(), type(t), geometry(geom), shapeId(-1) { init(); }
00068   
00069   //! Destructor
00070   virtual ~PlannerObstacle() {}
00071   
00072   //! sgn(x): returns sign of input
00073   template <typename T>
00074   static int sgn(T x) { return x < 0 ? -1 : 1; }
00075   
00076   //! Sub-components of an obstacle
00077   plist::Primitive<std::string> name;
00078   
00079   static void convertShapeToPlannerObstacle(const DualCoding::ShapeRoot& shape, 
00080                         float inflation,
00081                         std::vector<PlannerObstacle*> &obstacles);
00082   
00083   //! Increases the size of the obstacle in all directions by at least @a amount
00084   //virtual void bloat(float amount) = 0;
00085   
00086   //! Decreases the size of the obstacle in all directions by at least @a amount
00087   //virtual void contract(float amount) = 0;
00088   
00089   //! moves the obstacle
00090   virtual void updatePosition(const fmat::SubVector<N,const fmat::fmatReal>& newPos) = 0;
00091   
00092   //! rotate the obstacle about a specified origin and a 2d rotation matrix
00093   virtual void rotate(const fmat::SubVector<N,const fmat::fmatReal>& origin,
00094             const fmat::SubMatrix<N,N,const fmat::fmatReal>& rot) = 0;
00095   
00096   //! rotate the obstacle about its center by a 2d rotation matrix
00097   void rotate(const fmat::SubMatrix<N,N,const fmat::fmatReal>& rot) { rotate(getCenter(), rot); }
00098   
00099   //! get center point of obstacle
00100   virtual fmat::Column<N> getCenter() const = 0;
00101   
00102   //! get boundaries of the current obstacle
00103   virtual BoundingBox<N> getBoundingBox() const = 0;
00104   
00105   //! checks for collision with other PlannerObstacles
00106   bool collides(const PlannerObstacle<N>& other) const;
00107   
00108   //! All collision tests that need to be handled by subclasses for specific points
00109   virtual bool collides(const fmat::SubVector<N,const fmat::fmatReal>& point) const = 0;
00110   
00111   //! Support function for GJK collision detection algorithm.
00112   /*! Gets the point on the convex polygon farthest along the specified direction. */
00113   virtual fmat::Column<N> getSupport(const fmat::SubVector<N,const fmat::fmatReal>& direction) const = 0;
00114   
00115   //! Calculate the vector to closest point on the obstacle boundary from @a pt
00116   virtual fmat::Column<N> gradient(const fmat::SubVector<N,const fmat::fmatReal>& pt) const = 0;
00117   
00118   virtual std::string toString() const;
00119   friend std::ostream& operator<<(std::ostream& os, const PlannerObstacle& po) { return os << po.toString(); }
00120   
00121   ObstacleGeometry getObstacleGeometry() const { return geometry; }
00122   
00123   int getShapeId() const { return shapeId; }
00124   void setShapeId(int id) { shapeId = id; }
00125   
00126   const std::string& getTypeName() const { return type; }
00127   
00128   typedef FamilyFactory<PlannerObstacle,std::string> registry_t;
00129   static registry_t& getRegistry() { static registry_t registry; return registry; }
00130   
00131   PLIST_CLONE_FWD(PlannerObstacle);
00132   
00133 protected:
00134   //! Copy constructor, be careful not to cross-copy different types
00135   PlannerObstacle(const PlannerObstacle& o) : plist::Dictionary(), name(o.name), 
00136   type(o.type), geometry(o.geometry), shapeId(o.shapeId) { init(); }
00137   //! Don't use this assignment...
00138   PlannerObstacle& operator=(const PlannerObstacle& o) {
00139     name = o.name;
00140     type = o.type;
00141     geometry = o.geometry;
00142     init();
00143     return *this;
00144   }
00145   
00146   void init() {
00147     addEntry("Name",name,"Human readable name for debugging, display");
00148     addEntry(".type",type,"Allows polymorphic load/save, must match known class name");
00149     setLoadSavePolicy(FIXED,SYNC);
00150   }
00151   
00152   plist::Primitive<std::string> type;
00153   ObstacleGeometry geometry;
00154   int shapeId; //!< For obstacles defined by DualCoding shapes
00155 };
00156 
00157 template<size_t N>
00158 std::string PlannerObstacle<N>::toString() const {
00159   std::ostringstream os;
00160   os << "PlannerObstacle[type=" << type << ",name=" << name << "]";
00161   return os.str();
00162 }
00163 
00164 //! Rectangular defined obstacle designated by 4 corners and its rotation matrix from axis alignment
00165 class RectangularObstacle: public PlannerObstacle2D {
00166 protected:
00167   friend class ConvexPolyObstacle;
00168   
00169   //! stores the class name used for polymorphic load/save
00170   static const std::string autoRegisterName;
00171   
00172   //! Center of rectangle
00173   fmat::Column<2> center;
00174   
00175   //! minimum extents (along rectangle axes)
00176   fmat::Column<2> minEx;
00177   //! maximum extents (along rectangle axes)
00178   fmat::Column<2> maxEx;
00179   
00180   //! axis aligned bounding box
00181   BoundingBox2D bBox;
00182   
00183   //! The rotation matrix to rotate from 'normal' coordinates to the obstacle orientation
00184   fmat::Matrix<2,2> unrot;
00185   //! corner points for fast collision checking
00186   /*! points are stored in clockwise order from upper right:
00187    *  - top right
00188    *  - bottom right
00189    *  - bottom left
00190    *  - top left */
00191   fmat::Matrix<4,2> points;
00192   
00193 public:
00194   //! Default constructor
00195   RectangularObstacle(): PlannerObstacle2D(RECTANGULAR_OBS,autoRegisterName), center(), minEx(), maxEx(), bBox(), unrot(fmat::Matrix<2,2>::identity()), points() {}
00196   
00197   //! Pass the center, the extents from center (half-width and half-height), and an angular (radian) rotation
00198   RectangularObstacle(const fmat::SubVector<2,const fmat::fmatReal>& centerPoint,
00199             const fmat::SubVector<2,const fmat::fmatReal>& extents,
00200             fmat::fmatReal orient)
00201   : PlannerObstacle2D(RECTANGULAR_OBS,autoRegisterName), center(), minEx(), maxEx(), bBox(), unrot(), points()
00202   {
00203     reset(centerPoint,extents,orient); 
00204   }
00205   
00206   //! Pass a bounding box and a transform... the transformation is applied relative to origin, e.g. the @a bb center will rotate about the origin
00207   RectangularObstacle(const BoundingBox2D& bb, const fmat::SubMatrix<2,2,const fmat::fmatReal>& rot, const fmat::SubVector<2,const fmat::fmatReal>& off)
00208   : PlannerObstacle2D(RECTANGULAR_OBS,autoRegisterName), center(), minEx(), maxEx(), bBox(), unrot(), points()
00209   {
00210     fmat::Column<2> c(bb.getCenter()), d(bb.getDimensions());
00211     reset(rot*c+off, d/2, rot);
00212   }
00213   
00214   //! Assignment, should not use plist::Dictionary version
00215   RectangularObstacle& operator=(const RectangularObstacle& o) {
00216     PlannerObstacle2D::operator=(o);
00217     center=o.center;
00218     minEx=o.minEx;
00219     maxEx=o.maxEx;
00220     bBox=o.bBox;
00221     unrot=o.unrot;
00222     points=o.points;
00223     return *this;
00224   }
00225   
00226   using PlannerObstacle2D::collides;
00227   
00228   //! Test if the rectangle includes a specific point
00229   virtual bool collides(const fmat::SubVector<2,const fmat::fmatReal>& point) const;
00230   
00231   bool collides(const RectangularObstacle& other) const;
00232   bool collides(const CircularObstacle& other) const;
00233   bool collides(const EllipticalObstacle& other) const;
00234   
00235   virtual fmat::Column<2> getSupport(const fmat::SubVector<2,const fmat::fmatReal>& direction) const;
00236   
00237   //! do a complete reset of parameters
00238   virtual void reset(const fmat::Column<2>& centerPoint, const fmat::Column<2>& extents, fmat::fmatReal orient) {
00239     reset(centerPoint,extents,fmat::rotation2D(orient));
00240   }
00241   
00242   //! do a complete reset of parameters (so if you already have the rotation matrix, avoids regeneration from the angular value)
00243   virtual void reset(fmat::Column<2> centerPoint,
00244              const fmat::SubVector<2,const fmat::fmatReal>& extents,
00245              const fmat::SubMatrix<2,2,const fmat::fmatReal>& rot);
00246   
00247   virtual void updatePosition(const fmat::SubVector<2, const fmat::fmatReal>& newPos);
00248   
00249   using PlannerObstacle2D::rotate;
00250   virtual void rotate(const fmat::SubVector<2,const fmat::fmatReal>& origin,
00251             const fmat::SubMatrix<2,2,const fmat::fmatReal>& rot);
00252   
00253   //! Minimum and maximum X and Y extents (axis aligned bounding box)
00254   virtual BoundingBox2D getBoundingBox() const { return bBox; }
00255   
00256   virtual fmat::Column<2> gradient(const fmat::SubVector<2,const fmat::fmatReal>& pt) const;
00257   
00258   virtual std::string toString() const;
00259   
00260   //! Gets the center (X,Y)
00261   virtual fmat::Column<2> getCenter() const { return center; }
00262   
00263   //! returns the width along 'local' axes
00264   float getWidth() const { return maxEx[0] - minEx[0]; }
00265   //! returns the height along 'local' axes
00266   float getHeight() const { return maxEx[1] - minEx[1]; }
00267   //! returns the half-width and half-height, suitable for easy use with reset()
00268   fmat::Column<2> getExtents() const { return (maxEx-minEx)/2; }
00269   //! returns the orienation of the rectangle in radians
00270   float getOrientation() const;
00271   
00272   enum CornerOrder {
00273     TOP_RIGHT,
00274     TOP_LEFT,
00275     BOTTOM_LEFT,
00276     BOTTOM_RIGHT,
00277     NUM_CORNERS // for looping
00278   };
00279   
00280   //! returns the specified corner point
00281   fmat::Column<2> getCorner(size_t i) const { return fmat::pack(points(i,0),points(i,1)); }
00282   
00283   //! Increases the size of the obstacle in all directions by at least @a amount
00284   virtual void bloat(float amount);
00285   
00286   //! Decreases the size of the obstacle in all directions by at least @a amount
00287   virtual void contract(float amount);
00288   
00289   virtual void loadXML(xmlNode* node);
00290   virtual void saveXML(xmlNode * node) const;
00291   using plist::DictionaryBase::saveXML;
00292   
00293   //! clone definition for RectangularObstacle
00294   PLIST_CLONE_DEF(RectangularObstacle,new RectangularObstacle(*this));
00295 };
00296 
00297 //! Circle/Sphere defined obstacle designated by a center point and a radius
00298 class CircularObstacle : public PlannerObstacle2D {
00299 protected:
00300   //! stores the class name used for polymorphic load/save
00301   static const std::string autoRegisterName;
00302   
00303   //! Center of the obstacle
00304   fmat::Column<2> center;
00305   
00306   //! Radius of the obstacle
00307   fmat::fmatReal radius;
00308   
00309 public:
00310   //! Default constructor
00311   CircularObstacle() : PlannerObstacle2D(CIRCULAR_OBS,autoRegisterName),
00312   center(), radius(0) {}
00313   
00314   //! point and radius
00315   CircularObstacle(fmat::fmatReal x, fmat::fmatReal y, fmat::fmatReal r) : PlannerObstacle2D(CIRCULAR_OBS,autoRegisterName),
00316   center(fmat::pack(x,y)), radius(r) {}
00317   
00318   //! point and radius
00319   CircularObstacle(const fmat::Column<2>& c, fmat::fmatReal r) : PlannerObstacle2D(CIRCULAR_OBS,autoRegisterName),
00320   center(c), radius(r) {}
00321   
00322   //! Assignment, should not use plist::Dictionary version
00323   CircularObstacle& operator=(const CircularObstacle& o) {
00324     PlannerObstacle2D::operator=(o);
00325     center=o.center;
00326     radius=o.radius;
00327     return *this;
00328   }
00329   
00330   using PlannerObstacle2D::collides;
00331   
00332   //! Test if the circle includes a specific point
00333   virtual bool collides(const fmat::SubVector<2,const fmat::fmatReal>& point) const {
00334     return (point - center).sumSq() < radius*radius;
00335   }
00336   
00337   bool collides(const CircularObstacle& other) const;
00338   
00339   virtual fmat::Column<2> getSupport(const fmat::SubVector<2,const fmat::fmatReal>& direction) const;
00340   
00341   virtual fmat::Column<2> getCenter() const { return center; }
00342   virtual fmat::fmatReal getRadius() const { return radius; }
00343   virtual void setRadius(fmat::fmatReal r) { radius = r; }
00344   
00345   virtual void updatePosition(const fmat::SubVector<2, const fmat::fmatReal>& newPos) { center = newPos; }
00346   
00347   using PlannerObstacle2D::rotate;
00348   virtual void rotate(const fmat::SubVector<2,const fmat::fmatReal>& origin,
00349             const fmat::SubMatrix<2,2,const fmat::fmatReal>& rot) {
00350     updatePosition(rot * (getCenter()-origin) + origin);
00351   }
00352   
00353   virtual BoundingBox2D getBoundingBox() const {
00354     return BoundingBox2D(center - radius, center + radius);
00355   }
00356   
00357   virtual fmat::Column<2> gradient(const fmat::SubVector<2,const fmat::fmatReal>& pt) const;
00358   
00359   virtual std::string toString() const;
00360   
00361   //! Increases the size of the obstacle in all directions by at least @a amount
00362   virtual void bloat(float amount) { radius += amount; }
00363   //! Decreases the size of the obstacle in all directions by at least @a amount
00364   virtual void contract(float amount) { radius += amount; }
00365   
00366   virtual void loadXML(xmlNode* node);
00367   virtual void saveXML(xmlNode * node) const;
00368   using plist::DictionaryBase::saveXML;
00369   
00370   //! clone definition for CircularObstacle
00371   PLIST_CLONE_DEF(CircularObstacle,new CircularObstacle(*this));
00372 };
00373 
00374 //! Elliptically defined obstacle
00375 class EllipticalObstacle : public PlannerObstacle2D {
00376 protected:
00377   //! stores the class name used for polymorphic load/save
00378   static const std::string autoRegisterName;
00379   
00380 public:
00381   //! Focus of the ellipse
00382   fmat::Column<2> focus1;
00383   
00384   //! Focus of the ellipse  
00385   fmat::Column<2> focus2;
00386   
00387   //! Center of the ellipse
00388   fmat::Column<2> center;
00389   
00390   //! Half-length of the major axis
00391   fmat::fmatReal semimajor;
00392   
00393   //! Half-length of the minor axis
00394   fmat::fmatReal semiminor;
00395   
00396   //! Default constructor
00397   EllipticalObstacle() : PlannerObstacle2D(ELLIPTICAL_OBS,autoRegisterName),
00398   focus1(), focus2(), center(), semimajor(), semiminor() {}
00399   
00400   //! Location, semimajor, semiminor, orientation
00401   /*! Swaps the major/minor and adds 90° to the orientation if major<minor */
00402   EllipticalObstacle(const fmat::Column<2>& c, fmat::fmatReal _semimajor, fmat::fmatReal _semiminor, fmat::fmatReal orientation) : PlannerObstacle2D(ELLIPTICAL_OBS,autoRegisterName),
00403   focus1(), focus2(), center(c), semimajor(_semimajor), semiminor(_semiminor) { reset(c, _semimajor, _semiminor, orientation); }
00404   
00405   //! Circle with point and radius
00406   EllipticalObstacle(const fmat::Column<2>& c, fmat::fmatReal r) : PlannerObstacle2D(ELLIPTICAL_OBS,autoRegisterName),
00407   focus1(c), focus2(c), center(c), semimajor(r), semiminor(r) {}
00408   
00409   //! Assignment, should not use plist::Dictionary version
00410   EllipticalObstacle& operator=(const EllipticalObstacle& o) {
00411     PlannerObstacle2D::operator=(o);
00412     focus1=o.focus1;
00413     focus2=o.focus2;
00414     center=o.center;
00415     semimajor=o.semimajor;
00416     semiminor=o.semiminor;
00417     return *this;
00418   }
00419   
00420   //! Initialize from two foci and semimajor @a s
00421   /*! Will throw an exception if @a s is too short (must be at least half the distance between the foci) */
00422   void reset(const fmat::Column<2>& f1, const fmat::Column<2>& f2, fmat::fmatReal s);
00423   
00424   //! Initialize from center, extents, and orientation
00425   /*! Swaps the major/minor and adds 90° to the orientation if major<minor */
00426   void reset(const fmat::Column<2>& c, fmat::fmatReal smajor, fmat::fmatReal sminor, fmat::fmatReal ori);
00427   
00428   //! Initialize from circle: center and radius
00429   void reset(const fmat::Column<2>& c, fmat::fmatReal radius) {
00430     focus1 = focus2 = center = c;
00431     semimajor = semiminor = std::abs(radius);
00432   }
00433   
00434   using PlannerObstacle2D::collides;
00435   
00436   //! Test if the circle includes a specific point
00437   virtual bool collides(const fmat::SubVector<2,const fmat::fmatReal>& point) const {
00438     return (point - focus1).norm() + (point - focus2).norm() < 2*semimajor;
00439   }
00440   
00441   virtual fmat::Column<2> getSupport(const fmat::SubVector<2,const fmat::fmatReal>& direction) const;
00442   
00443   virtual fmat::Column<2> getCenter() const { return center; }
00444   
00445   virtual void updatePosition(const fmat::SubVector<2, const fmat::fmatReal>& newPos);
00446   
00447   using PlannerObstacle2D::rotate;
00448   virtual void rotate(const fmat::SubVector<2,const fmat::fmatReal>& origin,
00449             const fmat::SubMatrix<2,2,const fmat::fmatReal>& rot);
00450   
00451   //! Returns the angle of the major axis
00452   float getOrientation() const { return std::atan2(focus1[1] - focus2[1], focus1[0] - focus2[0]); }
00453   
00454   //! If rotating into the ellipse's frame, construct rotation matrix directly
00455   fmat::Matrix<2,2> getRotation() const;
00456   
00457   //! Returns the point on the edge of the ellipse at the specified angle
00458   /*! @a theta should be relative to the reference frame of the space that the ellipse resides in
00459    *  (and returns results in the external frame as well) */
00460   fmat::Column<2> getPointOnEdge(fmat::fmatReal theta) const {
00461     return getPointOnEdge(fmat::pack(std::cos(theta),std::sin(theta)));
00462   }
00463   
00464   //! Returns the point on the edge of the ellipse which intersects vector @a v through the center.
00465   /*! @a v does not need to be normalized */
00466   fmat::Column<2> getPointOnEdge(const fmat::Column<2>& direction) const;
00467   
00468   virtual BoundingBox2D getBoundingBox() const;
00469   
00470   //! Approximates the closest point on the ellipse to @a pt
00471   /*! Basically scales the vector from the center to @a pt */
00472   virtual fmat::Column<2> gradient(const fmat::SubVector<2,const fmat::fmatReal>& pt) const;
00473   
00474   virtual std::string toString() const;
00475   
00476   //! Increases the size of the obstacle in all directions by at least @a amount
00477   virtual void bloat(float amount) { reset(center, semimajor+amount, semiminor+amount, getOrientation()); }
00478   //! Decreases the size of the obstacle in all directions by at least @a amount
00479   virtual void contract(float amount) { reset(center, semimajor-amount, semiminor-amount, getOrientation()); }
00480   
00481   virtual void loadXML(xmlNode* node);
00482   virtual void saveXML(xmlNode* node) const;
00483   using plist::DictionaryBase::saveXML;
00484   
00485   //! clone definition for EllipticalObstacle
00486   PLIST_CLONE_DEF(EllipticalObstacle,new EllipticalObstacle(*this));
00487 };
00488 
00489 //! Manages collision detection with convex polygons
00490 /*! Basically the same algorithm used for rectangles, just generalized for more sides */
00491 class ConvexPolyObstacle : public PlannerObstacle2D {
00492 protected:
00493   //! stores the class name used for polymorphic load/save
00494   static const std::string autoRegisterName;
00495   
00496   std::vector<fmat::Column<2> > points; //! the points of the polygon, in counter-clockwise order
00497   std::vector<fmat::Column<2> > normals; //! the 'outside' normal of segment following corresponding entry in #points
00498   
00499 public:
00500   //! default constructor
00501   ConvexPolyObstacle() : PlannerObstacle2D(CONVEX_POLY_OBS,autoRegisterName), points(), normals() {}
00502   
00503   //! Assignment, should not use plist::Dictionary version
00504   ConvexPolyObstacle& operator=(const ConvexPolyObstacle& o) {
00505     PlannerObstacle2D::operator=(o);
00506     points = o.points;
00507     normals = o.normals;
00508     return *this;
00509   }
00510   
00511   //! returns the points, in counter-clockwise order
00512   const std::vector<fmat::Column<2> >& getPoints() const { return points; }
00513   
00514   //! returns the normals, in counter-clockwise order
00515   const std::vector<fmat::Column<2> >& getNormals() const { return normals; }
00516   
00517   //! Selects points which form a convex hull, clears current points
00518   /*! Passing a set because the hulling algorithm (Andrew's Monotone Chain)
00519    *  begins with sorting the list of points anyway.  If you have a different STL container 'c'
00520    *  just pass std::set<fmat::Column<2>(c.begin(),c.end()) to convert to a set.
00521    *  This implementation adapted from:
00522    *  http://en.wikibooks.org/wiki/Algorithm_Implementation/Geometry/Convex_hull/Monotone_chain */
00523   void hull(const std::set<fmat::Column<2> >& p);
00524   
00525   //! remove all points and normals
00526   void clear() { points.clear(); normals.clear(); }
00527   
00528   //! Add a point to the polygon, must maintain convexity and in counter-clockwise order, call close() when done
00529   void addPoint(const fmat::Column<2>& p);
00530   
00531   //! Calculates values for final segment of polygon, call after a series of addPoint()
00532   void close();
00533   
00534   using PlannerObstacle2D::collides;
00535   //! Test if the polygon includes a specific point
00536   virtual bool collides(const fmat::SubVector<2,const fmat::fmatReal>& point) const;
00537   //! For polygon on rectangle collision
00538   bool collides(const RectangularObstacle& other) const;
00539   //! For polygon on circle collision
00540   bool collides(const CircularObstacle& other) const;
00541   //! For polygon on polygon collision
00542   bool collides(const ConvexPolyObstacle& other) const;
00543   
00544   virtual fmat::Column<2> getSupport(const fmat::SubVector<2,const fmat::fmatReal>& direction) const;
00545   
00546   virtual fmat::Column<2> getCenter() const;
00547   virtual void updatePosition(const fmat::SubVector<2, const fmat::fmatReal>& newPos) { offset(newPos-getCenter()); }
00548   
00549   using PlannerObstacle2D::rotate;
00550   virtual void rotate(const fmat::SubVector<2,const fmat::fmatReal>& origin,
00551             const fmat::SubMatrix<2,2,const fmat::fmatReal>& rot);
00552   virtual BoundingBox2D getBoundingBox() const;
00553   
00554   virtual void offset(const fmat::Column<2>& off);
00555   virtual fmat::Column<2> gradient(const fmat::SubVector<2,const fmat::fmatReal>& pt) const;
00556   
00557   virtual std::string toString() const;
00558   
00559   virtual void loadXML(xmlNode* node);
00560   virtual void saveXML(xmlNode * node) const;
00561   using plist::DictionaryBase::saveXML;
00562   
00563   //! clone definition for ConvexPolyObstacle
00564   PLIST_CLONE_DEF(ConvexPolyObstacle,new ConvexPolyObstacle(*this));
00565 };
00566 
00567 //! Hierarchically defined obstacle containing multiple obstacles
00568 class HierarchicalObstacle : public PlannerObstacle2D {
00569 protected:
00570   //! stores the class name used for polymorphic load/save
00571   static const std::string autoRegisterName;
00572   
00573   //! recalculate rectangular bounding box based on contained obstacles
00574   void recalculateBoundingBox();
00575   
00576   //! grow the bounding box to include that of @a other
00577   void expandBoundingBox(PlannerObstacle2D& other);
00578   
00579   std::vector<PlannerObstacle2D*> obstacles; //!< the obstacles contained in the hierarchy
00580   
00581   BoundingBox2D aabb; //!< axis-aligned bounding box of all obstacles
00582   
00583   fmat::Column<2> center; //!< origin of the obstacle, all sub-obstacles will be relative to this point
00584   fmat::Matrix<2,2> rotation; //!< rotation about the origin
00585   
00586 public:
00587   //! default constructor
00588   HierarchicalObstacle()
00589   : PlannerObstacle2D(HIERARCHICAL_OBS,autoRegisterName), obstacles(), aabb(), center(), rotation(fmat::Matrix<2,2>::identity()) {}
00590   
00591   //! copy constructor (deep copy #obstacles)
00592   HierarchicalObstacle(const HierarchicalObstacle& ho)
00593   : PlannerObstacle2D(ho), obstacles(), aabb(ho.aabb), center(ho.center), rotation(ho.rotation)
00594   {
00595     obstacles.reserve(ho.obstacles.size());
00596     for(std::vector<PlannerObstacle2D*>::const_iterator it=ho.obstacles.begin(); it!=ho.obstacles.end(); ++it) {
00597       obstacles.push_back(dynamic_cast<PlannerObstacle2D*>((*it)->clone())); // need explicit cast for old compilers, should be no-op
00598     }
00599   }
00600   
00601   //! Assignment, should not use plist::Dictionary version
00602   HierarchicalObstacle& operator=(const HierarchicalObstacle& o) {
00603     PlannerObstacle2D::operator=(o);
00604     clear();
00605     obstacles.reserve(o.obstacles.size());
00606     for(std::vector<PlannerObstacle2D*>::const_iterator it=o.obstacles.begin(); it!=o.obstacles.end(); ++it) {
00607       obstacles.push_back(dynamic_cast<PlannerObstacle2D*>((*it)->clone())); // need explicit cast for old compilers, should be no-op
00608     }
00609     aabb=o.aabb;
00610     center=o.center;
00611     rotation=o.rotation;
00612     return *this;
00613   }
00614   
00615   //! destructor
00616   virtual ~HierarchicalObstacle() { clear(); }
00617   
00618   //! returns obstacles of specified type
00619   template <class T>
00620   void getObstacles(std::vector<T> &obs) const;
00621   
00622   const std::vector<PlannerObstacle2D*>& getObstacles() const { return obstacles; }
00623   
00624   using PlannerObstacle2D::collides;
00625   //! For obstacle on point
00626   virtual bool collides(const fmat::SubVector<2,const fmat::fmatReal>& point) const;
00627   
00628   virtual fmat::Column<2> getSupport(const fmat::SubVector<2,const fmat::fmatReal>& direction) const;
00629   
00630   virtual BoundingBox2D getBoundingBox() const { return aabb; }
00631   
00632   virtual fmat::Column<2> getCenter() const { return center; }
00633   virtual fmat::Matrix<2,2> getRotation() const { return rotation; }
00634   
00635   virtual void updatePosition(const fmat::SubVector<2, const fmat::fmatReal>& newPos);
00636   
00637   //! update to specified orientation about the center
00638   virtual void updateRotation(const fmat::Matrix<2,2>& rot) { rotation = rot; }
00639   
00640   using PlannerObstacle2D::rotate;
00641   virtual void rotate(const fmat::SubVector<2,const fmat::fmatReal>& origin,
00642             const fmat::SubMatrix<2,2,const fmat::fmatReal>& rot);
00643   
00644   virtual fmat::Column<2> gradient(const fmat::SubVector<2,const fmat::fmatReal>& pt) const;
00645   
00646   virtual std::string toString() const;
00647   
00648   //! clear all obstacles
00649   void clear() {
00650     for (unsigned int i = 0; i < obstacles.size(); i++)
00651       delete obstacles[i];
00652     obstacles.clear(); recalculateBoundingBox();
00653   }
00654   
00655   //! add obstacle to end of obstacle list; obstacles should be transformed in terms of Hierarchical Obstacle
00656   /*! Memory allocation of @a o will be claimed by the hierarchical obstacle. */
00657   void add(PlannerObstacle2D* o) { obstacles.push_back(o); expandBoundingBox(*o); }
00658   
00659   //! clone definition for HierarchicalObstacle
00660   PLIST_CLONE_DEF(HierarchicalObstacle,new HierarchicalObstacle(*this));
00661 };
00662 
00663 template <class T>
00664 void HierarchicalObstacle::getObstacles(std::vector<T> &obs) const {
00665   for (unsigned int i = 0; i < obstacles.size(); i++) {
00666     T t = dynamic_cast<T>(obstacles[i]);
00667     if (t)
00668       obs.push_back(t);
00669   }
00670 }
00671 
00672 class BoxObstacle : public PlannerObstacle3D {
00673 protected:
00674   //! stores the class name used for polymorphic load/save
00675   static const std::string autoRegisterName;
00676   
00677   //! Center of box
00678   fmat::Column<3> center;
00679   
00680   //! minimum extents (along box axes)
00681   fmat::Column<3> minEx;
00682   //! maximum extents (along box axes)
00683   fmat::Column<3> maxEx;
00684   
00685   //! axis aligned bounding box
00686   BoundingBox3D bBox;
00687   
00688   //! The rotation matrix to rotate from 'normal' coordinates to the obstacle orientation
00689   fmat::Matrix<3,3> unrot;
00690   
00691   //! corner points for fast collision checking
00692   /*! points are stored first top then bottom,
00693    both in clockwise order from upper right:
00694    *  - top upper right
00695    *  - top lower right
00696    *  - top lower left
00697    *  - top upper left
00698    *  - bottom upper right
00699    *  - bottom lower right
00700    *  - bottom lower left
00701    *  - bottom upper left */
00702   fmat::Matrix<8,3> points;
00703   
00704 public:
00705   //! Default constructor
00706   BoxObstacle() : PlannerObstacle3D(BOX_OBS,autoRegisterName),
00707   center(), minEx(), maxEx(), bBox(), unrot(fmat::Matrix<3,3>::identity()), points() {}
00708   
00709   //! Pass the center, the extents from center (half-length, half-width and half-height), and a rotation
00710   BoxObstacle(const fmat::SubVector<3,const fmat::fmatReal>& centerPoint,
00711         const fmat::SubVector<3,const fmat::fmatReal>& extents,
00712         const fmat::SubMatrix<3,3,const fmat::fmatReal>& orient)
00713   : PlannerObstacle3D(BOX_OBS,autoRegisterName), center(), minEx(), maxEx(), bBox(), unrot(), points()
00714   {
00715     reset(centerPoint,extents,orient); 
00716   }
00717   
00718   //! Pass a bounding box and a transform... the transformation is applied relative to origin, e.g. the @a bb center will rotate about the origin
00719   BoxObstacle(const BoundingBox3D& bb,
00720         const fmat::SubMatrix<3,3,const fmat::fmatReal>& rot,
00721         const fmat::SubVector<3,const fmat::fmatReal>& off)
00722   : PlannerObstacle3D(BOX_OBS,autoRegisterName), center(), minEx(), maxEx(), bBox(), unrot(), points()
00723   {
00724     fmat::Column<3> c(bb.getCenter()), d(bb.getDimensions());
00725     reset(rot*c+off, d/2, rot);
00726   }
00727   
00728   //! Assignment, should not use plist::Dictionary version
00729   BoxObstacle& operator=(const BoxObstacle& o) {
00730     PlannerObstacle3D::operator=(o);
00731     center=o.center;
00732     minEx=o.minEx;
00733     maxEx=o.maxEx;
00734     bBox=o.bBox;
00735     unrot=o.unrot;
00736     points=o.points;
00737     return *this;
00738   }
00739   
00740   //! do a complete reset of parameters
00741   virtual void reset(fmat::Column<3> centerPoint,
00742              const fmat::SubVector<3,const fmat::fmatReal>& extents,
00743              const fmat::SubMatrix<3,3,const fmat::fmatReal>& rot);
00744   
00745   virtual void updatePosition(const fmat::SubVector<3, const fmat::fmatReal>& newPos);
00746   
00747   using PlannerObstacle3D::rotate;
00748   virtual void rotate(const fmat::SubVector<3,const fmat::fmatReal>& origin,
00749             const fmat::SubMatrix<3,3,const fmat::fmatReal>& rot);
00750   
00751   virtual std::string toString() const;
00752   
00753   virtual fmat::Column<3> getCenter() const { return center; }
00754   virtual BoundingBox3D getBoundingBox() const { return bBox; }
00755   
00756   using PlannerObstacle3D::collides;
00757   virtual bool collides(const fmat::SubVector<3,const fmat::fmatReal>& point) const;
00758   
00759   virtual fmat::Column<3> getSupport(const fmat::SubVector<3,const fmat::fmatReal>& direction) const;
00760   
00761   virtual fmat::Column<3> gradient(const fmat::SubVector<3,const fmat::fmatReal>& pt) const;
00762   
00763   //! returns the length along 'local' axes
00764   float getLength() const { return maxEx[0] - minEx[0]; }
00765   //! returns the width along 'local' axes
00766   float getWidth() const { return maxEx[1] - minEx[1]; }
00767   //! returns the height along 'local' axes
00768   float getHeight() const { return maxEx[2] - minEx[2]; }
00769   //! returns the half-width and half-height, suitable for easy use with reset()
00770   fmat::Column<3> getExtents() const { return (maxEx-minEx)/2; }
00771   
00772   enum CornerOrder {
00773     TOP_UPPER_RIGHT,
00774     TOP_LOWER_RIGHT,
00775     TOP_LOWER_LEFT,
00776     TOP_UPPER_LEFT,
00777     BOTTOM_UPPER_RIGHT,
00778     BOTTOM_LOWER_RIGHT,
00779     BOTTOM_LOWER_LEFT,
00780     BOTTOM_UPPER_LEFT,
00781     NUM_CORNERS // for looping
00782   };
00783   
00784   //! returns the specified corner point
00785   fmat::Column<3> getCorner(size_t i) const { return fmat::pack(points(i,0),points(i,1),points(i,2)); }
00786   
00787   //! Increases the size of the obstacle in all directions by at least @a amount
00788   virtual void bloat(float amount);
00789   
00790   //! Decreases the size of the obstacle in all directions by at least @a amount
00791   virtual void contract(float amount);
00792   
00793   virtual void loadXML(xmlNode* node);
00794   virtual void saveXML(xmlNode * node) const;
00795   using plist::DictionaryBase::saveXML;
00796   
00797   //! clone definition for BoxObstacle
00798   PLIST_CLONE_DEF(BoxObstacle,new BoxObstacle(*this));
00799 };
00800 
00801 //! Cylinder with central axis in alignment with z-axis by default.
00802 class CylindricalObstacle : public PlannerObstacle3D {
00803 protected:
00804   //! stores the class name used for polymorphic load/save
00805   static const std::string autoRegisterName;
00806   
00807   //! center of the cylinder
00808   fmat::Column<3> center;
00809   
00810   //! 3D orientation of cylinder
00811   fmat::Matrix<3,3> orientation;
00812   
00813   //! radius of cylinder
00814   fmat::fmatReal radius;
00815   
00816   //! half-height
00817   fmat::fmatReal halfHeight;
00818   
00819 public:
00820   //! Default constructor
00821   CylindricalObstacle() : PlannerObstacle3D(CYLINDRICAL_OBS,autoRegisterName),
00822   center(), orientation(), radius(0), halfHeight(0) {}
00823   
00824   CylindricalObstacle(const fmat::SubVector<3,const fmat::fmatReal>& c,
00825             const fmat::SubMatrix<3,3,const fmat::fmatReal>& o,
00826             fmat::fmatReal r,
00827             fmat::fmatReal hh) :
00828   PlannerObstacle3D(CYLINDRICAL_OBS,autoRegisterName), center(c), orientation(o), radius(r), halfHeight(hh) {}
00829   
00830   //! Assignment, should not use plist::Dictionary version
00831   CylindricalObstacle& operator=(const CylindricalObstacle& o) {
00832     PlannerObstacle3D::operator=(o);
00833     center=o.center;
00834     orientation=o.orientation;
00835     radius=o.radius;
00836     halfHeight=o.halfHeight;
00837     return *this;
00838   }
00839   
00840   virtual void updatePosition(const fmat::SubVector<3, const fmat::fmatReal>& newPos) { center = newPos; }
00841   virtual void rotate(const fmat::SubVector<3,const fmat::fmatReal>& origin,
00842             const fmat::SubMatrix<3,3,const fmat::fmatReal>& rot) {
00843     center = rot * (center - origin) + origin;
00844     orientation = rot * orientation;
00845   }
00846   virtual fmat::Column<3> getCenter() const { return center; }
00847   virtual BoundingBox3D getBoundingBox() const;
00848   
00849   using PlannerObstacle3D::collides;
00850   virtual bool collides(const fmat::SubVector<3,const fmat::fmatReal>& point) const;
00851   
00852   virtual fmat::Column<3> getSupport(const fmat::SubVector<3,const fmat::fmatReal>& direction) const;
00853   
00854   virtual fmat::Column<3> gradient(const fmat::SubVector<3,const fmat::fmatReal>& pt) const;
00855   
00856   virtual void loadXML(xmlNode* node);
00857   virtual void saveXML(xmlNode* node) const;
00858   using plist::DictionaryBase::saveXML;
00859   
00860   //! clone definition for CylindricalObstacle
00861   PLIST_CLONE_DEF(CylindricalObstacle,new CylindricalObstacle(*this));
00862 };
00863 
00864 //! Spherically defined obstacle
00865 class SphericalObstacle : public PlannerObstacle3D {
00866 protected:
00867   //! stores the class name used for polymorphic load/save
00868   static const std::string autoRegisterName;
00869   
00870   //! center of the sphere
00871   fmat::Column<3> center;
00872   
00873   //! radius of the sphere
00874   fmat::fmatReal radius;
00875   
00876 public:
00877   //! Default constructor
00878   SphericalObstacle() : PlannerObstacle3D(SPHERICAL_OBS,autoRegisterName),
00879   center(), radius(0) {}
00880   
00881   //! point and radius
00882   SphericalObstacle(fmat::fmatReal x, fmat::fmatReal y, fmat::fmatReal z, fmat::fmatReal r) : PlannerObstacle3D(CIRCULAR_OBS,autoRegisterName),
00883   center(fmat::pack(x,y,z)), radius(r) {}
00884   
00885   //! point and radius
00886   SphericalObstacle(const fmat::Column<3>& c, fmat::fmatReal r) : PlannerObstacle3D(CIRCULAR_OBS,autoRegisterName),
00887   center(c), radius(r) {}
00888   
00889   //! Assignment, should not use plist::Dictionary version
00890   SphericalObstacle& operator=(const SphericalObstacle& o) {
00891     PlannerObstacle3D::operator=(o);
00892     center=o.center;
00893     radius=o.radius;
00894     return *this;
00895   }
00896   
00897   virtual void updatePosition(const fmat::SubVector<3, const fmat::fmatReal>& newPos) { center = newPos; }
00898   
00899   virtual void rotate(const fmat::SubVector<3,const fmat::fmatReal>& origin,
00900             const fmat::SubMatrix<3,3,const fmat::fmatReal>& rot) { center = rot * (center - origin) + origin; }
00901   
00902   virtual fmat::Column<3> getCenter() const { return center; }
00903   virtual fmat::fmatReal getRadius() const { return radius; }
00904   virtual BoundingBox3D getBoundingBox() const {
00905     return BoundingBox3D(center - radius, center + radius);
00906   }
00907   
00908   using PlannerObstacle3D::collides;
00909   //! For obstacle on point
00910   virtual bool collides(const fmat::SubVector<3,const fmat::fmatReal>& point) const;
00911   
00912   bool collides(const SphericalObstacle& other) const;
00913   
00914   virtual fmat::Column<3> getSupport(const fmat::SubVector<3,const fmat::fmatReal>& direction) const;
00915   
00916   virtual fmat::Column<3> gradient(const fmat::SubVector<3,const fmat::fmatReal>& pt) const;
00917   
00918   virtual void loadXML(xmlNode* node);
00919   virtual void saveXML(xmlNode* node) const;
00920   using plist::DictionaryBase::saveXML;
00921   
00922   //! clone definition for SphericalObstacle
00923   PLIST_CLONE_DEF(SphericalObstacle,new SphericalObstacle(*this));
00924 };
00925 
00926 class EllipsoidObstacle : public PlannerObstacle3D {
00927 protected:
00928   //! stores the class name used for polymorphic load/save
00929   static const std::string autoRegisterName;
00930   
00931   //! center of the ellipsoid
00932   fmat::Column<3> center;
00933   
00934   //! 3D orientation of the ellipse
00935   fmat::Matrix<3,3> orientation;
00936   
00937   //! positive half-width extents along each axis
00938   fmat::Column<3> extents;
00939   
00940 public:
00941   //! Default constructor
00942   EllipsoidObstacle() :
00943   PlannerObstacle3D(ELLIPSOID_OBS,autoRegisterName), center(), orientation(), extents() {}
00944   
00945   EllipsoidObstacle(const fmat::SubVector<3, const fmat::fmatReal>& c,
00946             const fmat::SubMatrix<3,3, const fmat::fmatReal>& o,
00947             const fmat::SubVector<3, const fmat::fmatReal>& e) :
00948   PlannerObstacle3D(ELLIPSOID_OBS,autoRegisterName), center(c), orientation(o), extents(e) {}
00949   
00950   //! Assignment, should not use plist::Dictionary version
00951   EllipsoidObstacle& operator=(const EllipsoidObstacle& o) {
00952     PlannerObstacle3D::operator=(o);
00953     center=o.center;
00954     orientation=o.orientation;
00955     extents=o.extents;
00956     return *this;
00957   }
00958   
00959   virtual void updatePosition(const fmat::SubVector<3, const fmat::fmatReal>& newPos) { center = newPos; }
00960   virtual void rotate(const fmat::SubVector<3,const fmat::fmatReal>& origin,
00961             const fmat::SubMatrix<3,3,const fmat::fmatReal>& rot) {
00962     center = rot * (center - origin) + origin;
00963     orientation = rot * orientation;
00964   }
00965   virtual fmat::Column<3> getCenter() const { return center; }
00966   virtual BoundingBox3D getBoundingBox() const;
00967   
00968   using PlannerObstacle3D::collides;
00969   virtual bool collides(const fmat::SubVector<3,const fmat::fmatReal>& point) const;
00970   
00971   virtual fmat::Column<3> getSupport(const fmat::SubVector<3,const fmat::fmatReal>& direction) const;
00972   
00973   //! helper function, in the case of any of the components being zero.
00974   virtual fmat::Column<2> get2Support(const fmat::SubVector<2,const fmat::fmatReal>& direction) const;
00975   
00976   virtual fmat::Column<3> gradient(const fmat::SubVector<3,const fmat::fmatReal>& pt) const;
00977   
00978   virtual void loadXML(xmlNode* node);
00979   virtual void saveXML(xmlNode* node) const;
00980   using plist::DictionaryBase::saveXML;
00981   
00982   //! clone definition for EllipsoidObstacle
00983   PLIST_CLONE_DEF(EllipsoidObstacle,new EllipsoidObstacle(*this));
00984 };
00985 
00986 #endif

Tekkotsu v5.1CVS
Generated Fri Mar 16 05:26:47 2012 by Doxygen 1.6.3