00001 #include "PlannerObstacles.h"
00002 #include "GJK.h"
00003 #include "Shared/FamilyFactory.h"
00004 #include "Shared/debuget.h"
00005 #include "Shared/plistSpecialty.h"
00006 #include "Shared/mathutils.h"
00007
00008 #include <iostream>
00009 #include <typeinfo>
00010
00011 using namespace std;
00012 using namespace fmat;
00013
00014 const float INF = 10e10f;
00015
00016 const std::string RectangularObstacle::autoRegisterName = PlannerObstacle2D::getRegistry().registerType<RectangularObstacle>("Rectangle");
00017 const std::string CircularObstacle::autoRegisterName = PlannerObstacle2D::getRegistry().registerType<CircularObstacle>("Circle");
00018 const std::string EllipticalObstacle::autoRegisterName = PlannerObstacle2D::getRegistry().registerType<EllipticalObstacle>("Ellipse");
00019 const std::string ConvexPolyObstacle::autoRegisterName = PlannerObstacle2D::getRegistry().registerType<ConvexPolyObstacle>("ConvexPoly");
00020 const std::string HierarchicalObstacle::autoRegisterName = PlannerObstacle2D::getRegistry().registerType<HierarchicalObstacle>("Hierarchy");
00021 const std::string BoxObstacle::autoRegisterName = PlannerObstacle3D::getRegistry().registerType<BoxObstacle>("Box");
00022 const std::string CylindricalObstacle::autoRegisterName = PlannerObstacle3D::getRegistry().registerType<CylindricalObstacle>("Cylinder");
00023 const std::string SphericalObstacle::autoRegisterName = PlannerObstacle3D::getRegistry().registerType<SphericalObstacle>("Sphere");
00024 const std::string EllipsoidObstacle::autoRegisterName = PlannerObstacle3D::getRegistry().registerType<EllipsoidObstacle>("Ellipsoid");
00025
00026 PLIST_CLONE_IMP(RectangularObstacle,new RectangularObstacle(*this));
00027 PLIST_CLONE_IMP(CircularObstacle,new CircularObstacle(*this));
00028 PLIST_CLONE_IMP(EllipticalObstacle,new EllipticalObstacle(*this));
00029 PLIST_CLONE_IMP(ConvexPolyObstacle,new ConvexPolyObstacle(*this));
00030 PLIST_CLONE_IMP(HierarchicalObstacle,new HierarchicalObstacle(*this));
00031 PLIST_CLONE_IMP(BoxObstacle,new BoxObstacle(*this));
00032 PLIST_CLONE_IMP(CylindricalObstacle,new CylindricalObstacle(*this));
00033 PLIST_CLONE_IMP(SphericalObstacle,new SphericalObstacle(*this));
00034 PLIST_CLONE_IMP(EllipsoidObstacle,new EllipsoidObstacle(*this));
00035
00036 namespace plist {
00037 template<> PlannerObstacle2D* loadXML(xmlNode* node) {
00038 plist::Primitive<std::string> type;
00039 Dictionary td(false);
00040 td.setUnusedWarning(false);
00041 td.addEntry(".type",type);
00042 td.loadXML(node);
00043 PlannerObstacle2D* po = PlannerObstacle2D::getRegistry().create(type);
00044 if(po==NULL)
00045 throw XMLLoadSave::bad_format(node,"Unknown PlannerObstacle type "+type);
00046 try {
00047 po->loadXML(node);
00048 } catch(...) {
00049 delete po;
00050 throw;
00051 }
00052 return po;
00053 }
00054 template<> PlannerObstacle3D* loadXML(xmlNode* node) {
00055 plist::Primitive<std::string> type;
00056 Dictionary td(false);
00057 td.setUnusedWarning(false);
00058 td.addEntry(".type",type);
00059 td.loadXML(node);
00060 PlannerObstacle3D* po = PlannerObstacle3D::getRegistry().create(type);
00061 if(po==NULL)
00062 throw XMLLoadSave::bad_format(node,"Unknown PlannerObstacle type "+type);
00063 try {
00064 po->loadXML(node);
00065 } catch(...) {
00066 delete po;
00067 throw;
00068 }
00069 return po;
00070 }
00071 }
00072
00073
00074 template <>
00075 bool PlannerObstacle2D::collides(const PlannerObstacle2D& other) const {
00076
00077
00078 switch(geometry * geometry * other.geometry) {
00079
00080 case RECTANGULAR_OBS * RECTANGULAR_OBS * RECTANGULAR_OBS:
00081 return static_cast<const RectangularObstacle*>(this)->collides(static_cast<const RectangularObstacle&>(other));
00082 case RECTANGULAR_OBS * RECTANGULAR_OBS * CIRCULAR_OBS:
00083 return static_cast<const RectangularObstacle*>(this)->collides(static_cast<const CircularObstacle&>(other));
00084 case RECTANGULAR_OBS * CIRCULAR_OBS * CIRCULAR_OBS:
00085 return static_cast<const RectangularObstacle*>(&other)->collides(static_cast<const CircularObstacle&>(*this));
00086
00087
00088 case CIRCULAR_OBS * CIRCULAR_OBS * CIRCULAR_OBS:
00089 return static_cast<const CircularObstacle*>(this)->collides(static_cast<const CircularObstacle&>(other));
00090
00091
00092 case CONVEX_POLY_OBS * CONVEX_POLY_OBS * RECTANGULAR_OBS:
00093 return static_cast<const ConvexPolyObstacle*>(this)->collides(static_cast<const RectangularObstacle&>(other));
00094 case CONVEX_POLY_OBS * RECTANGULAR_OBS * RECTANGULAR_OBS:
00095 return static_cast<const ConvexPolyObstacle*>(&other)->collides(static_cast<const RectangularObstacle&>(*this));
00096 case CONVEX_POLY_OBS * CONVEX_POLY_OBS * CIRCULAR_OBS:
00097 return static_cast<const ConvexPolyObstacle*>(this)->collides(static_cast<const CircularObstacle&>(other));
00098 case CONVEX_POLY_OBS * CIRCULAR_OBS * CIRCULAR_OBS:
00099 return static_cast<const ConvexPolyObstacle*>(&other)->collides(static_cast<const CircularObstacle&>(*this));
00100 case CONVEX_POLY_OBS * CONVEX_POLY_OBS * CONVEX_POLY_OBS:
00101 return static_cast<const ConvexPolyObstacle*>(this)->collides(static_cast<const ConvexPolyObstacle&>(other));
00102 }
00103
00104
00105
00106 return GJK::collides(this, &other);
00107 }
00108
00109 template <>
00110 bool PlannerObstacle3D::collides(const PlannerObstacle3D& other) const {
00111 return GJK::collides(this, &other);
00112 }
00113
00114 void RectangularObstacle::reset(fmat::Column<2> centerPoint,
00115 const fmat::SubVector<2,const fmat::fmatReal>& extents,
00116 const fmat::SubMatrix<2,2,const fmat::fmatReal>& rot) {
00117 center = centerPoint;
00118
00119 fmat::Column<2> off = rot * extents;
00120 points.row(TOP_RIGHT) = &(center + off)[0];
00121 points.row(BOTTOM_LEFT) = &(center - off)[0];
00122 off = rot * fmat::pack(-extents[0],extents[1]);
00123 points.row(TOP_LEFT) = &(center + off)[0];
00124 points.row(BOTTOM_RIGHT) = &(center - off)[0];
00125
00126 bBox.min = &points.minR()[0];
00127 bBox.max = &points.maxR()[0];
00128
00129 unrot = rot.transpose();
00130 centerPoint = unrot * centerPoint;
00131 maxEx = centerPoint + extents;
00132 minEx = centerPoint - extents;
00133 }
00134
00135 void RectangularObstacle::updatePosition(const fmat::SubVector<2,const fmat::fmatReal>& newPos) {
00136 fmat::Column<2> diff = newPos - getCenter();
00137 center = newPos;
00138 bBox.min += diff;
00139 bBox.max += diff;
00140 points.column(0)+=diff[0];
00141 points.column(1)+=diff[1];
00142
00143 diff = unrot * diff;
00144 minEx += diff;
00145 maxEx += diff;
00146 }
00147
00148 bool RectangularObstacle::collides(const RectangularObstacle& other) const {
00149 if( !bBox.collides(other.bBox) )
00150 return false;
00151 if(unrot(0,0)==1 && other.unrot(0,0)==1)
00152 return true;
00153
00154
00155 fmat::Matrix<4,2> p2 = other.points * unrot.transpose();
00156 float minX,maxX,minY,maxY;
00157 minX=p2.column(0).min();
00158 maxX=p2.column(0).max();
00159 minY=p2.column(1).min();
00160 maxY=p2.column(1).max();
00161 if(maxX <= minEx[0] || maxEx[0] <= minX
00162 || maxY <= minEx[1] || maxEx[1] <= minY)
00163 return false;
00164
00165 if(unrot(0,0)!=other.unrot(0,0)) {
00166
00167 p2 = points * other.unrot.transpose();
00168 minX=p2.column(0).min();
00169 maxX=p2.column(0).max();
00170 minY=p2.column(1).min();
00171 maxY=p2.column(1).max();
00172 if(maxX <= other.minEx[0] || other.maxEx[0] <= minX
00173 || maxY <= other.minEx[1] || other.maxEx[1] <= minY)
00174 return false;
00175 }
00176
00177 return true;
00178 }
00179
00180 bool RectangularObstacle::collides(const CircularObstacle& other) const {
00181 const fmat::Column<2> p = unrot * other.getCenter();
00182 const fmat::Column<2> pmin = p-other.getRadius(), pmax = p+other.getRadius();
00183
00184 if(pmax[0]<=minEx[0] || maxEx[0]<=pmin[0] || pmax[1]<=minEx[1] || maxEx[1]<=pmin[1]) {
00185 return false;
00186 } else if(p[0]<minEx[0]) {
00187 if(p[1]<minEx[1]) {
00188 return ((minEx - p).norm() < other.getRadius());
00189 } else if(maxEx[1]<p[1]) {
00190 return ((fmat::pack(minEx[0],maxEx[1]) - p).norm() < other.getRadius());
00191 }
00192 return true;
00193 } else if(maxEx[0] < p[0]) {
00194 if(p[1]<minEx[1]) {
00195 return ((fmat::pack(maxEx[0],minEx[1]) - p).norm() < other.getRadius());
00196 } else if(maxEx[1]<p[1]) {
00197 return ((maxEx - p).norm() < other.getRadius());
00198 }
00199 return true;
00200 } else {
00201 return true;
00202 }
00203 }
00204
00205 void RectangularObstacle::rotate(const fmat::SubVector<2,const fmat::fmatReal>& origin,
00206 const fmat::SubMatrix<2,2,const fmat::fmatReal>& rot) {
00207 fmat::Column<2> newCenter = rot * (getCenter() - origin) + origin;
00208 reset(newCenter, getExtents(), unrot.transpose() * rot);
00209 }
00210
00211 fmat::Column<2> RectangularObstacle::gradient(const fmat::SubVector<2,const fmat::fmatReal>& pt) const {
00212 const fmat::Column<2> p = unrot * pt;
00213
00214 if(p[0]<minEx[0]) {
00215 if(p[1]<minEx[1]) {
00216 return fmat::Column<2>(points.row(BOTTOM_LEFT).transpose()) - pt;
00217 } else if(maxEx[1]<p[1]) {
00218 return fmat::Column<2>(points.row(TOP_LEFT).transpose()) - pt;
00219 }
00220 return unrot.row(0).transpose() * (minEx[0]-p[0]);
00221 } else if(maxEx[0] < p[0]) {
00222 if(p[1]<minEx[1]) {
00223 return fmat::Column<2>(points.row(BOTTOM_RIGHT).transpose()) - pt;
00224 } else if(maxEx[1]<p[1]) {
00225 return fmat::Column<2>(points.row(TOP_RIGHT).transpose()) - pt;
00226 }
00227 return unrot.row(0).transpose() * (maxEx[0]-p[0]);
00228 } else if(p[1]<minEx[1]) {
00229 return unrot.row(1).transpose() * (minEx[1]-p[1]);
00230 } else if(maxEx[1]<p[1]) {
00231 return unrot.row(1).transpose() * (maxEx[1]-p[1]);
00232 } else {
00233
00234 fmatReal dist[4];
00235 dist[0] = p[0]-minEx[0];
00236 dist[1] = p[1]-minEx[1];
00237 dist[2] = maxEx[0]-p[0];
00238 dist[3] = maxEx[1]-p[1];
00239 if(dist[0] < dist[1]) {
00240 if(dist[0] < dist[2]) {
00241 if(dist[0] < dist[3]) {
00242 return unrot.row(0).transpose() * (minEx[0]-p[0]);
00243 }
00244 } else {
00245 if(dist[2] < dist[3]) {
00246 return unrot.row(0).transpose() * (maxEx[0]-p[0]);
00247 }
00248 }
00249 } else {
00250 if(dist[1] < dist[2]) {
00251 if(dist[1] < dist[3]) {
00252 return unrot.row(1).transpose() * (minEx[1]-p[1]);
00253 }
00254 } else {
00255 if(dist[2] < dist[3]) {
00256 return unrot.row(0).transpose() * (maxEx[0]-p[0]);
00257 }
00258 }
00259 }
00260 return unrot.row(1).transpose() * (maxEx[1]-p[1]);
00261 }
00262 }
00263
00264 std::string RectangularObstacle::toString() const {
00265 ostringstream os;
00266 os << "RectangularObstacle[" << name << ",points=" << points.fmt() << ",unrot=" << unrot.fmt() << "]";
00267 return os.str();
00268 }
00269
00270 bool RectangularObstacle::collides(const fmat::SubVector<2,const fmat::fmatReal>& point) const {
00271 const fmat::Column<2> p2 = unrot * point;
00272 return (minEx[0]<p2[0] && p2[0]<maxEx[0] &&
00273 minEx[1]<p2[1] && p2[1]<maxEx[1]);
00274 }
00275
00276 fmat::Column<2> RectangularObstacle::getSupport(const fmat::SubVector<2,const fmat::fmatReal>& direction) const {
00277 const fmat::Column<2> dir = unrot * direction;
00278
00279 if (dir[0]>0) {
00280 if (dir[1]>0)
00281 return points.row(TOP_RIGHT).transpose();
00282 else
00283 return points.row(BOTTOM_RIGHT).transpose();
00284 }
00285 else {
00286 if (dir[1]>0)
00287 return points.row(TOP_LEFT).transpose();
00288 else
00289 return points.row(BOTTOM_LEFT).transpose();
00290 }
00291 }
00292
00293 void RectangularObstacle::bloat(float amount) {
00294 reset(getCenter(),maxEx+amount,unrot.transpose());
00295 }
00296
00297
00298 void RectangularObstacle::contract(float amount) {
00299 bloat(-amount);
00300 }
00301
00302 void RectangularObstacle::loadXML(xmlNode* node) {
00303
00304 plist::ArrayOf< plist::Primitive<fmat::fmatReal> > c(2,0,false);
00305 plist::ArrayOf< plist::Primitive<fmat::fmatReal> > d(2,0,false);
00306 plist::Angle ang;
00307 addEntry("Center",c);
00308 addEntry("Dimensions",d);
00309 addEntry("Orientation",ang);
00310 PlannerObstacle2D::loadXML(node);
00311 removeEntry("Center");
00312 removeEntry("Dimensions");
00313 removeEntry("Orientation");
00314 reset(fmat::pack(c[0],c[1]), fmat::pack(d[0]/2,d[1]/2), ang);
00315 }
00316 void RectangularObstacle::saveXML(xmlNode * node) const {
00317
00318 plist::ArrayOf< plist::Primitive<fmat::fmatReal> > c(2,0,false);
00319 getCenter().exportTo(c);
00320 c.setSaveInlineStyle(true);
00321 plist::ArrayOf< plist::Primitive<fmat::fmatReal> > d(2,0,false);
00322 d[0] = getWidth();
00323 d[1] = getHeight();
00324 d.setSaveInlineStyle(true);
00325 plist::Angle ang = getOrientation();
00326 plist::Dictionary tmp(*this);
00327 tmp.addEntry("Center",c,"Center point");
00328 tmp.addEntry("Dimensions",d,"Width and height");
00329 tmp.addEntry("Orientation",ang,"Rotation (radians unless you specify ° suffix)");
00330 tmp.saveXML(node);
00331 }
00332
00333 float RectangularObstacle::getOrientation() const {
00334 return std::atan2(unrot(0,1),unrot(0,0));
00335 }
00336
00337 fmat::Column<2> CircularObstacle::gradient(const fmat::SubVector<2,const fmat::fmatReal>& pt) const {
00338 fmat::Column<2> v = pt - center;
00339 fmat::fmatReal n = v.norm();
00340 if(n == 0)
00341 return fmat::pack(radius,0);
00342 return v * ((radius - n)/n);
00343 }
00344
00345 std::string CircularObstacle::toString() const {
00346 ostringstream os;
00347 os << "CircularObstacle[" << name << ",center=" << center << ",radius=" << radius << "]";
00348 return os.str();
00349 }
00350
00351 bool CircularObstacle::collides(const CircularObstacle& other) const {
00352 const fmat::Column<2> diff = center - other.center;
00353 const float r = radius + other.radius;
00354 return diff.sumSq() < r*r;
00355 }
00356
00357 fmat::Column<2> CircularObstacle::getSupport(const fmat::SubVector<2,const fmat::fmatReal>& direction) const {
00358 return center + (direction / direction.norm() * radius);
00359 }
00360
00361 void CircularObstacle::loadXML(xmlNode* node) {
00362
00363 plist::ArrayOf< plist::Primitive<fmat::fmatReal> > c(2,0,false);
00364 plist::Primitive<fmat::fmatReal> r;
00365 addEntry("Center",c);
00366 addEntry("Radius",r);
00367 PlannerObstacle2D::loadXML(node);
00368 removeEntry("Center");
00369 removeEntry("Radius");
00370 center.importFrom(c);
00371 radius = r;
00372 }
00373 void CircularObstacle::saveXML(xmlNode * node) const {
00374
00375 plist::ArrayOf< plist::Primitive<fmat::fmatReal> > c(2,0,false);
00376 c.setSaveInlineStyle(true);
00377 center.exportTo(c);
00378 plist::Primitive<fmat::fmatReal> r = radius;
00379 plist::Dictionary tmp(*this);
00380 tmp.addEntry("Center",c);
00381 tmp.addEntry("Radius",r);
00382 tmp.saveXML(node);
00383 }
00384
00385 void EllipticalObstacle::reset(const fmat::Column<2>& f1, const fmat::Column<2>& f2, fmat::fmatReal s) {
00386 center = ( (focus1 = f1) + (focus2 = f2) ) / 2;
00387 semimajor = std::abs(s);
00388 fmat::fmatReal d = s*s - (f1-center).sumSq();
00389 if(d<0)
00390 throw std::invalid_argument("EllipticalObstacle::reset with two foci and too-short semimajor");
00391 semiminor = std::sqrt(d);
00392 }
00393
00394 void EllipticalObstacle::reset(const fmat::Column<2>& c, fmat::fmatReal _semimajor, fmat::fmatReal _semiminor, fmat::fmatReal orientation) {
00395 center = c;
00396 semimajor = _semimajor;
00397 semiminor = _semiminor;
00398 if(semimajor < semiminor) {
00399 std::swap(semimajor, semiminor);
00400 orientation+=static_cast<fmat::fmatReal>(M_PI_2);
00401 }
00402 fmat::fmatReal focusDist = std::sqrt(semimajor*semimajor - semiminor*semiminor);
00403 fmat::Column<2> ax = fmat::pack(focusDist*std::cos(orientation),focusDist*std::sin(orientation));
00404 focus1 = center + ax;
00405 focus2 = center - ax;
00406 }
00407
00408 fmat::Column<2> EllipticalObstacle::getSupport(const fmat::SubVector<2,const fmat::fmatReal>& direction) const {
00409
00410 if (semimajor == semiminor)
00411 return center + (direction / direction.norm() * semimajor);
00412
00413
00414 fmat::Column<2> dir = getRotation().transpose() * direction;
00415
00416
00417 if (dir[0] == 0) {
00418 return getRotation() * fmat::pack(0, sgn(dir[1]) * semiminor) + center;
00419 }
00420 else if (dir[1] == 0) {
00421 return getRotation() * fmat::pack(sgn(dir[0]) * semimajor, 0) + center;
00422 }
00423
00424
00425 fmat::fmatReal a2 = semimajor*semimajor, b2 = semiminor*semiminor;
00426
00427
00428 fmat::fmatReal k = (dir[1]*b2)/(dir[0]*a2);
00429 fmat::fmatReal x = sgn(dir[0]) * std::sqrt(1/((1/(a2)) + (k*k/(b2))));
00430
00431 return getRotation() * fmat::pack(x, k*x) + center;
00432 }
00433
00434 void EllipticalObstacle::updatePosition(const fmat::SubVector<2,const fmat::fmatReal>& newPos) {
00435 fmat::Column<2> diff = newPos - center;
00436 center = newPos;
00437 focus1 += diff;
00438 focus2 += diff;
00439 }
00440
00441 void EllipticalObstacle::rotate(const fmat::SubVector<2,const fmat::fmatReal>& origin,
00442 const fmat::SubMatrix<2,2,const fmat::fmatReal>& rot) {
00443 focus1 = rot * (focus1 - origin) + origin;
00444 focus2 = rot * (focus2 - origin) + origin;
00445 center = (focus1+focus2)/2;
00446 }
00447
00448 fmat::Matrix<2,2> EllipticalObstacle::getRotation() const {
00449 if(semimajor==semiminor)
00450 return fmat::Matrix<2,2>::identity();
00451 fmat::fmatReal x[4] = { focus1[0]-center[0], focus1[1]-center[1] };
00452 fmat::fmatReal n = fmat::SubVector<2>(x).norm();
00453 x[0]/=n; x[1]/=n; x[2]=-x[1]; x[3]=x[0];
00454 return fmat::Matrix<2,2>(x);
00455 }
00456
00457 fmat::Column<2> EllipticalObstacle::getPointOnEdge(const fmat::Column<2>& direction) const {
00458 fmat::Matrix<2,2> rot = getRotation();
00459 fmat::Column<2> x = rot.transpose() * direction;
00460 fmat::fmatReal ratio = semimajor/semiminor;
00461 x[1]*=ratio;
00462 x *= semimajor/x.norm();
00463 x[1]/=ratio;
00464 return rot * x + center;
00465 }
00466
00467 BoundingBox2D EllipticalObstacle::getBoundingBox() const {
00468 float orientation = getOrientation();
00469 float t_x = std::atan(-semiminor * tan(orientation) / semimajor);
00470 float t_y = std::atan( semiminor / tan(orientation) / semimajor);
00471 BoundingBox2D b;
00472
00473 float o_sin = std::sin(orientation), t_x_sin = std::sin(t_x), t_y_sin = std::sin(t_y);
00474 float o_cos = std::cos(orientation), t_x_cos = std::cos(t_x), t_y_cos = std::cos(t_y);
00475 b.expand(fmat::pack(center[0] + semimajor*t_x_cos*o_cos - semiminor*t_x_sin*o_sin,
00476 center[1] + semiminor*t_y_sin*o_cos + semimajor*t_y_cos*o_sin));
00477
00478 b.expand(fmat::pack(center[0] - semimajor*t_x_cos*o_cos + semiminor*t_x_sin*o_sin,
00479 center[1] - semiminor*t_y_sin*o_cos - semimajor*t_y_cos*o_sin));
00480 return b;
00481 }
00482
00483 fmat::Column<2> EllipticalObstacle::gradient(const fmat::SubVector<2,const fmat::fmatReal>& pt) const {
00484
00485 if (semimajor == semiminor)
00486 return getPointOnEdge(pt - center) - pt;
00487
00488 fmat::Column<2> newPt = getRotation().transpose() * (pt - center);
00489
00490 float a = (semimajor*semimajor - semiminor*semiminor);
00491 float b = semimajor * newPt[0];
00492 float c = semiminor * newPt[1];
00493
00494
00495
00496 float aa = a*a, bb = b*b;
00497
00498 float a3 = -2*b/a;
00499 float a2 = (bb-aa+c*c)/aa;
00500 float a1 = -a3;
00501 float a0 = -bb/aa;
00502
00503 float a2a2 = a2*a2, a3a3 = a3*a3;
00504
00505 float t1 = -a3/4;
00506 float t2 = a2a2 - 3*a3*a1 + 12*a0;
00507 float t3 = (2*a2a2*a2 - 9*a3*a2*a1 + 27*a1*a1 + 27*a3a3*a0 - 72*a2*a0)/2;
00508 float t4 = (-a3a3*a3 + 4*a3*a2 - 8*a1)/32;
00509 float t5 = (3*a3a3 - 8*a2)/48;
00510
00511 float s1 = std::sqrt(t3*t3 - std::pow(t2,3));
00512 float s2 = std::pow(t3 + s1, 1.0f/3.0f);
00513 float s3 = (1.0f/12.0f)*(t2/s2 + s2);
00514 float s4 = std::sqrt(t5 + s3);
00515 float s5 = 2*t5 - s3;
00516 float s6 = t4/s4;
00517
00518 float sq1 = std::sqrt(s5 - s6);
00519 float sq2 = std::sqrt(s5 + s6);
00520
00521 float sols[8];
00522
00523 sols[0] = std::acos(t1 - s4 - sq1);
00524 sols[1] = std::acos(t1 - s4 + sq1);
00525 sols[2] = std::acos(t1 + s4 - sq2);
00526 sols[3] = std::acos(t1 + s4 + sq2);
00527
00528 if (std::isnan(sols[0]) && std::isnan(sols[1]) && std::isnan(sols[2]) && std::isnan(sols[3])) {
00529
00530 return fmat::pack(0,0);
00531 }
00532
00533
00534 if (newPt[1] < 0) {
00535 for (int i = 0; i < 4; i++)
00536 sols[i] = -sols[i];
00537 }
00538
00539 float ori = getOrientation(), so = std::sin(ori), co = std::cos(ori);
00540
00541 fmat::Column<2> grads[4];
00542 float minMag = std::numeric_limits<float>::infinity();
00543 int minMagIndex = 0;
00544 for (int i = 0; i < 4; i++) {
00545 if (std::isnan(sols[i])) continue;
00546 float st = std::sin(sols[i]), ct = std::cos(sols[i]);
00547 grads[i] = fmat::pack(semimajor*ct*co - semiminor*st*so,
00548 semimajor*ct*so + semiminor*st*co) + center - pt;
00549 float sumSq = grads[i].sumSq();
00550 if (sumSq < minMag) {
00551 minMag = sumSq;
00552 minMagIndex = i;
00553 }
00554 }
00555
00556 return grads[minMagIndex];
00557 }
00558
00559 std::string EllipticalObstacle::toString() const {
00560 ostringstream os;
00561 os << "EllipticalObstacle[" << name << ",focus1=" << focus1 << ",focus2=" << focus2 << "," << std::endl
00562 << " center=" << center << ",semimajor=" << semimajor << ",semiminor=" << semiminor << std::endl
00563 << " orientation=" << getOrientation() << "]";
00564 return os.str();
00565 }
00566
00567 void EllipticalObstacle::loadXML(xmlNode* node) {
00568
00569 plist::ArrayOf< plist::Primitive<fmat::fmatReal> > c(2,0,false);
00570 plist::Primitive<fmat::fmatReal> smajor;
00571 plist::Primitive<fmat::fmatReal> sminor;
00572 plist::Angle ori;
00573 addEntry("Center",c);
00574 addEntry("Orientation",ori);
00575 addEntry("Semimajor",smajor);
00576 addEntry("Semiminor",sminor);
00577 PlannerObstacle2D::loadXML(node);
00578 removeEntry("Center");
00579 removeEntry("Orientation");
00580 removeEntry("Semimajor");
00581 removeEntry("Semiminor");
00582 center.importFrom(c);
00583 reset(center,smajor,sminor,ori);
00584 }
00585
00586 void EllipticalObstacle::saveXML(xmlNode * node) const {
00587
00588 plist::ArrayOf< plist::Primitive<fmat::fmatReal> > c(2,0,false);
00589 c.setSaveInlineStyle(true);
00590 center.exportTo(c);
00591 plist::Primitive<fmat::fmatReal> smajor = semimajor;
00592 plist::Primitive<fmat::fmatReal> sminor = semiminor;
00593 plist::Angle ori = getOrientation();
00594 plist::Dictionary tmp(*this);
00595 tmp.addEntry("Center",c);
00596 tmp.addEntry("Orientation",ori);
00597 tmp.addEntry("Semimajor",smajor);
00598 tmp.addEntry("Semiminor",sminor);
00599 tmp.saveXML(node);
00600 }
00601
00602 void ConvexPolyObstacle::hull(const std::set<fmat::Column<2> >& p) {
00603 size_t k = 0;
00604 points.resize(p.size()+1);
00605
00606
00607 for(std::set<fmat::Column<2> >::const_iterator it=p.begin(); it!=p.end(); ++it) {
00608 while(k>=2 && fmat::crossProduct(points[k-1]-points[k-2], *it-points[k-2])[2] <= 0)
00609 --k;
00610 points[k++] = *it;
00611 }
00612
00613
00614 const size_t t = k+1;
00615 std::set<fmat::Column<2> >::const_reverse_iterator it=p.rbegin();
00616 for(++it; it!=p.rend(); ++it) {
00617 while(k >= t && fmat::crossProduct(points[k-1]-points[k-2], *it-points[k-2])[2] <= 0)
00618 --k;
00619 points[k++] = *it;
00620 }
00621
00622
00623 normals.resize(k-1);
00624 for(size_t i=0; i<k-1; ++i) {
00625 fmat::Column<2> d = points[i+1] - points[i];
00626
00627 normals[i] = (fmat::pack(d[1],-d[0]) / d.norm());
00628 }
00629 points.resize(k-1);
00630 }
00631
00632 void ConvexPolyObstacle::addPoint(const fmat::Column<2>& p) {
00633 if(points.size()>0) {
00634 fmat::Column<2> d = p - points.back();
00635
00636 d = fmat::pack(d[1],-d[0]) / d.norm();
00637 if(normals.size()==points.size())
00638 normals.back() = d;
00639 else
00640 normals.push_back(d);
00641 }
00642 points.push_back(p);
00643 }
00644
00645 void ConvexPolyObstacle::close() {
00646 ASSERTRET(points.size()==normals.size()+1,"ConvexPolyObstacle already closed: " << points.size() << " points " << normals.size() << " normals");
00647 fmat::Column<2> d = points.front() - points.back();
00648
00649 d = fmat::pack(d[1],-d[0]) / d.norm();
00650 normals.push_back(d);
00651 }
00652
00653 bool ConvexPolyObstacle::collides(const fmat::SubVector<2,const fmat::fmatReal>& point) const {
00654 ASSERTRETVAL(points.size()>=3,"ConvexPolyObstacle: not enough points (" << points.size() << ", need at least 3)",false);
00655 ASSERTRETVAL(points.size()==normals.size(),"ConvexPolyObstacle not closed",false);
00656 for(size_t i=0; i<points.size(); ++i) {
00657 if(fmat::dotProduct(point-points[i],normals[i]) >= 0)
00658 return false;
00659 }
00660 return true;
00661 }
00662
00663 bool ConvexPolyObstacle::collides(const RectangularObstacle& other) const {
00664 ASSERTRETVAL(points.size()>=3,"ConvexPolyObstacle: not enough points (" << points.size() << ", need at least 3)",false);
00665 ASSERTRETVAL(points.size()==normals.size(),"ConvexPolyObstacle not closed",false);
00666 for(size_t i=0; i<points.size(); ++i) {
00667 fmat::Matrix<4,2> c(other.points);
00668 c.column(0)-=points[i][0];
00669 c.column(1)-=points[i][1];
00670 fmat::Column<4> d = c * normals[i];
00671 if(d.min() >= 0)
00672 return false;
00673 }
00674 fmat::Column<2> p = other.unrot * points[0];
00675 fmat::fmatReal minX=p[0],maxX=p[0],minY=p[1],maxY=p[1];
00676 for(size_t i=1; i<points.size(); ++i) {
00677 p = other.unrot * points[i];
00678 if(p[0]<minX)
00679 minX=p[0];
00680 else if(maxX<p[0])
00681 maxX=p[0];
00682 if(p[1]<minY)
00683 minY=p[1];
00684 else if(maxY<p[1])
00685 maxY=p[1];
00686 }
00687 return (other.minEx[0]<maxX && minX<other.maxEx[0] && other.minEx[1]<maxY && minY<other.maxEx[1]);
00688 }
00689
00690 bool ConvexPolyObstacle::collides(const CircularObstacle& other) const {
00691 ASSERTRETVAL(points.size()>=3,"ConvexPolyObstacle: not enough points (" << points.size() << ", need at least 3)",false);
00692 ASSERTRETVAL(points.size()==normals.size(),"ConvexPolyObstacle not closed",false);
00693 const fmat::fmatReal r2 = other.getRadius() * other.getRadius();
00694 bool outside = false;
00695 bool testedLast = false;
00696 for(size_t i=0; i<points.size(); ++i) {
00697 fmat::Column<2> v = other.getCenter()-points[i];
00698 fmat::fmatReal d = fmat::dotProduct(v,normals[i]);
00699 if(d >= other.getRadius())
00700 return false;
00701 if(d >= 0) {
00702 outside = true;
00703
00704 d = v[0]*-normals[i][1] + v[1]*normals[i][0];
00705
00706 if(d >= 0) {
00707 const fmat::Column<2>& next = (i+1==points.size() ? points[0] : points[i+1]);
00708 fmat::fmatReal len = (points[i] - next).norm();
00709 if(d <= len)
00710 return true;
00711 if(testedLast) {
00712 testedLast=false;
00713 } else if(d < len+other.getRadius()) {
00714
00715 if((other.getCenter() - next).sumSq() < r2)
00716 return true;
00717 testedLast=true;
00718 }
00719 } else {
00720 if(d > -other.getRadius()) {
00721
00722 if(v.sumSq() < r2)
00723 return true;
00724 }
00725 testedLast=false;
00726 }
00727 }
00728 }
00729 return !outside;
00730 }
00731
00732 bool ConvexPolyObstacle::collides(const ConvexPolyObstacle& other) const {
00733 ASSERTRETVAL(points.size()>=3,"ConvexPolyObstacle: not enough points (" << points.size() << ", need at least 3)",false);
00734 ASSERTRETVAL(points.size()==normals.size(),"ConvexPolyObstacle not closed",false);
00735 ASSERTRETVAL(other.points.size()==other.normals.size(),"ConvexPolyObstacle not closed",false);
00736 for(size_t i=0; i<points.size(); ++i) {
00737 bool inter=false;
00738 for(size_t j=0; j<other.points.size(); ++j) {
00739 if(fmat::dotProduct(other.points[j]-points[i],normals[i]) < 0) {
00740 inter=true;
00741 break;
00742 }
00743 }
00744 if(!inter)
00745 return false;
00746 }
00747 for(size_t i=0; i<other.points.size(); ++i) {
00748 bool inter=false;
00749 for(size_t j=0; j<points.size(); ++j) {
00750 if(fmat::dotProduct(points[j]-other.points[i],other.normals[i]) < 0) {
00751 inter=true;
00752 break;
00753 }
00754 }
00755 if(!inter)
00756 return false;
00757 }
00758 return true;
00759 }
00760
00761 fmat::Column<2> ConvexPolyObstacle::getSupport(const fmat::SubVector<2,const fmat::fmatReal>& direction) const {
00762 ASSERTRETVAL(points.size()>0,"ConvexPolyObstacle: no points",fmat::pack(0,0));
00763 fmat::fmatReal max = fmat::dotProduct(direction, points[0]);
00764 int maxIndex = 0;
00765 for (unsigned int i = 1; i < points.size(); i++) {
00766 fmat::fmatReal newMax = fmat::dotProduct(direction, points[i]);
00767 if (newMax > max) {
00768 max = newMax;
00769 maxIndex = i;
00770 }
00771 }
00772 return points[maxIndex];
00773 }
00774
00775 fmat::Column<2> ConvexPolyObstacle::getCenter() const {
00776 ASSERTRETVAL(points.size()>0,"ConvexPolyObstacle empty (" << points.size() << ", need at least 1 for getCenter())",fmat::Column<2>());
00777 fmat::Column<2> ans=points.front();
00778 for(size_t i=1; i<points.size(); ++i) {
00779 ans+=points[i];
00780 }
00781 return ans/points.size();
00782 }
00783
00784 void ConvexPolyObstacle::rotate(const fmat::SubVector<2,const fmat::fmatReal>& origin,
00785 const fmat::SubMatrix<2,2,const fmat::fmatReal>& rot) {
00786 std::vector<fmat::Column<2> > tmpPoints = points;
00787 clear();
00788 for(size_t i=0; i<tmpPoints.size(); ++i) {
00789 addPoint(rot*(tmpPoints[i] - origin) + origin);
00790 }
00791 close();
00792 }
00793
00794 BoundingBox2D ConvexPolyObstacle::getBoundingBox() const {
00795 BoundingBox2D bb;
00796 for(size_t i=0; i<points.size(); ++i)
00797 bb.expand(points[i]);
00798 return bb;
00799 }
00800
00801 void ConvexPolyObstacle::offset(const fmat::Column<2>& off) {
00802 for(size_t i=0; i<points.size(); ++i) {
00803 points[i]+=off;
00804 }
00805 }
00806
00807 fmat::Column<2> ConvexPolyObstacle::gradient(const fmat::SubVector<2,const fmat::fmatReal>& pt) const {
00808 ASSERTRETVAL(points.size()>=3,"ConvexPolyObstacle: not enough points (" << points.size() << ", need at least 3)",fmat::Column<2>());
00809 ASSERTRETVAL(points.size()==normals.size(),"ConvexPolyObstacle not closed",fmat::Column<2>());
00810 fmat::fmatReal closest2=std::numeric_limits<fmat::fmatReal>::infinity();
00811 fmat::Column<2> ans;
00812 bool testedLast = false;
00813 for(size_t i=0; i<points.size(); ++i) {
00814 fmat::Column<2> v = pt-points[i];
00815
00816 const fmat::fmatReal d = v[0]*-normals[i][1] + v[1]*normals[i][0];
00817
00818 if(d >= 0) {
00819 const fmat::Column<2>& next = (i+1==points.size() ? points[0] : points[i+1]);
00820 fmat::fmatReal len = (points[i] - next).norm();
00821 if(d <= len) {
00822 fmat::fmatReal n = fmat::dotProduct(v,normals[i]);
00823 fmat::fmatReal n2 = n*n;
00824 if(n2<closest2) {
00825 closest2 = n2;
00826 ans = normals[i]*-n;
00827 }
00828 }
00829 if(testedLast) {
00830 testedLast=false;
00831 } else if(d < len) {
00832
00833 fmat::fmatReal n2 = (next - pt).sumSq();
00834 if(n2 < closest2) {
00835 closest2 = n2;
00836 ans = next - pt;
00837 }
00838 testedLast=true;
00839 }
00840 } else {
00841
00842 fmat::fmatReal n2 = v.sumSq();
00843 if(n2 < closest2) {
00844 closest2 = n2;
00845 ans = -v;
00846 }
00847 testedLast=false;
00848 }
00849 }
00850 return ans;
00851 }
00852
00853 std::string ConvexPolyObstacle::toString() const {
00854 ostringstream os;
00855 os << "ConvexPolyObstacle[" << name << ",#points=" << points.size() << ",#normals=" << normals.size() << "]";
00856 return os.str();
00857 }
00858
00859
00860 void ConvexPolyObstacle::loadXML(xmlNode* node) {
00861
00862 plist::ArrayOf< plist::Point > ps;
00863 addEntry("Points",ps);
00864 PlannerObstacle2D::loadXML(node);
00865 removeEntry("Points");
00866 points.resize(ps.size());
00867 for(size_t i=0; i<ps.size(); ++i)
00868 points[i].importFrom(ps[i]);
00869 }
00870
00871 void ConvexPolyObstacle::saveXML(xmlNode * node) const {
00872
00873 plist::ArrayOf< plist::Point > ps;
00874 for(size_t i=0; i<ps.size(); ++i) {
00875 points[i].exportTo(ps[i]);
00876 ps.removeEntry(2);
00877 }
00878 plist::Dictionary tmp(*this);
00879 tmp.addEntry("Points",ps);
00880 tmp.saveXML(node);
00881 }
00882
00883 void HierarchicalObstacle::recalculateBoundingBox() {
00884 aabb = BoundingBox2D();
00885
00886 if (obstacles.empty())
00887 return;
00888
00889 for (std::vector<PlannerObstacle2D*>::iterator it = obstacles.begin(); it != obstacles.end(); ++it)
00890 expandBoundingBox(**it);
00891 }
00892
00893 void HierarchicalObstacle::expandBoundingBox(PlannerObstacle2D& other) {
00894 other.rotate(fmat::pack(0,0), rotation);
00895 fmat::Column<2> oldCenter = other.getCenter();
00896 other.updatePosition(oldCenter+getCenter());
00897
00898 aabb.expand(other.getBoundingBox());
00899
00900 other.updatePosition(oldCenter);
00901 other.rotate(fmat::pack(0,0), rotation.transpose());
00902 }
00903
00904 bool HierarchicalObstacle::collides(const fmat::SubVector<2,const fmat::fmatReal>& point) const {
00905
00906 if( !aabb.collides(point) )
00907 return false;
00908
00909
00910 const fmat::Column<2> newPt = rotation.transpose() * (point - center);
00911
00912
00913 for (unsigned int i = 0; i < obstacles.size(); i++) {
00914 if (obstacles[i]->collides(newPt))
00915 return true;
00916 }
00917 return false;
00918 }
00919
00920 fmat::Column<2> HierarchicalObstacle::getSupport(const fmat::SubVector<2,const fmat::fmatReal>& direction) const {
00921 fmat::Column<2> dir = rotation.transpose() * direction;
00922 fmat::Column<2> maxSupport = obstacles[0]->getSupport(dir);
00923 fmat::fmatReal max = fmat::dotProduct(maxSupport, dir);
00924 for (unsigned int i = 1; i < obstacles.size(); i++) {
00925 fmat::Column<2> newSupport = obstacles[i]->getSupport(dir);
00926 fmat::fmatReal newMax = fmat::dotProduct(newSupport, dir);
00927 if (newMax > max) {
00928 maxSupport = newSupport;
00929 max = newMax;
00930 }
00931 }
00932 return rotation * maxSupport + center;
00933 }
00934
00935 void HierarchicalObstacle::updatePosition(const fmat::SubVector<2,const fmat::fmatReal>& newPos) {
00936 fmat::Column<2> diff = newPos - getCenter();
00937 aabb.min += diff;
00938 aabb.max += diff;
00939 center = newPos;
00940 }
00941
00942 void HierarchicalObstacle::rotate(const fmat::SubVector<2,const fmat::fmatReal>& origin,
00943 const fmat::SubMatrix<2,2,const fmat::fmatReal>& rot) {
00944 rotation = rotation * rot;
00945 center = rot * (getCenter() - origin) + origin;
00946 recalculateBoundingBox();
00947 }
00948
00949 fmat::Column<2> HierarchicalObstacle::gradient(const fmat::SubVector<2,const fmat::fmatReal>& pt) const {
00950 fmat::Column<2> transformedPt = rotation.transpose() * (pt - getCenter());
00951 ASSERTRETVAL(obstacles.size()>0,"HierarchicalObstacle: no obstacles, can't determine gradient",fmat::Column<2>());
00952 fmat::Column<2> minGradient;
00953 bool minSet = false;
00954 for (unsigned int i = 0; i < obstacles.size(); ++i) {
00955 fmat::Column<2> newGradient = obstacles[i]->gradient(transformedPt);
00956 bool collision = false;
00957 for (unsigned int j = 0; j < obstacles.size(); ++j) {
00958 if (i == j) continue;
00959 if (obstacles[j]->collides(transformedPt+newGradient)) {
00960 collision = true;
00961 break;
00962 }
00963 }
00964
00965 if (collision)
00966 continue;
00967
00968 if (!minSet) {
00969 minGradient = newGradient;
00970 minSet = true;
00971 }
00972 else if (newGradient.sumSq() < minGradient.sumSq())
00973 minGradient = newGradient;
00974 }
00975
00976 return rotation * minGradient;
00977 }
00978
00979 std::string HierarchicalObstacle::toString() const {
00980 ostringstream os;
00981 os << "HierarchicalObstacle[" << name << ",#components=" << obstacles.size() << "]";
00982 return os.str();
00983 }
00984
00985 void BoxObstacle::reset(fmat::Column<3> centerPoint,
00986 const fmat::SubVector<3,const fmat::fmatReal>& extents,
00987 const fmat::SubMatrix<3,3,const fmat::fmatReal>& rot) {
00988 center = centerPoint;
00989 fmat::Column<3> off = rot * extents;
00990 points.row(TOP_UPPER_RIGHT) = &(center + off)[0];
00991 points.row(BOTTOM_LOWER_LEFT) = &(center - off)[0];
00992 off = rot * fmat::pack(extents[0],-extents[1],extents[2]);
00993 points.row(TOP_LOWER_RIGHT) = &(center + off)[0];
00994 points.row(BOTTOM_UPPER_LEFT) = &(center - off)[0];
00995 off = rot * fmat::pack(-extents[0],-extents[1],extents[2]);
00996 points.row(TOP_LOWER_LEFT) = &(center + off)[0];
00997 points.row(BOTTOM_UPPER_RIGHT) = &(center - off)[0];
00998 off = rot * fmat::pack(-extents[0],extents[1],extents[2]);
00999 points.row(TOP_UPPER_LEFT) = &(center + off)[0];
01000 points.row(BOTTOM_LOWER_RIGHT) = &(center - off)[0];
01001
01002 bBox.min = &points.minR()[0];
01003 bBox.max = &points.maxR()[0];
01004
01005 unrot = rot.transpose();
01006 centerPoint = unrot * centerPoint;
01007 maxEx = centerPoint + extents;
01008 minEx = centerPoint - extents;
01009 }
01010
01011 void BoxObstacle::updatePosition(const fmat::SubVector<3, const fmat::fmatReal>& newPos) {
01012 fmat::Column<3> diff = newPos - getCenter();
01013 center = newPos;
01014 bBox.min += diff;
01015 bBox.max += diff;
01016 points.column(0)+=diff[0];
01017 points.column(1)+=diff[1];
01018 points.column(2)+=diff[2];
01019
01020 diff = unrot * diff;
01021 minEx += diff;
01022 maxEx += diff;
01023 }
01024
01025 void BoxObstacle::rotate(const fmat::SubVector<3,const fmat::fmatReal>& origin,
01026 const fmat::SubMatrix<3,3,const fmat::fmatReal>& rot) {
01027 fmat::Column<3> newCenter = rot * (getCenter() - origin) + origin;
01028 reset(newCenter, getExtents(), unrot.transpose() * rot);
01029 }
01030
01031 std::string BoxObstacle::toString() const {
01032 ostringstream os;
01033 os << "BoxObstacle[" << name << ",points=" << points.fmt() << ",unrot=" << unrot.fmt() << "]";
01034 return os.str();
01035 }
01036
01037 bool BoxObstacle::collides(const fmat::SubVector<3,const fmat::fmatReal>& point) const {
01038 const fmat::Column<3> p2 = unrot * point;
01039 return (minEx[0]<p2[0] && p2[0]<maxEx[0] &&
01040 minEx[1]<p2[1] && p2[1]<maxEx[1] &&
01041 minEx[2]<p2[2] && p2[2]<maxEx[2]);
01042 }
01043
01044 fmat::Column<3> BoxObstacle::getSupport(const fmat::SubVector<3,const fmat::fmatReal>& direction) const {
01045 const fmat::Column<3> dir = unrot * direction;
01046
01047 if (dir[0]>0) {
01048 if (dir[1]>0) {
01049 if (dir[2]>0) {
01050 return points.row(TOP_UPPER_RIGHT).transpose();
01051 } else {
01052 return points.row(BOTTOM_UPPER_RIGHT).transpose();
01053 }
01054 } else {
01055 if (dir[2]>0) {
01056 return points.row(TOP_LOWER_RIGHT).transpose();
01057 } else {
01058 return points.row(BOTTOM_LOWER_RIGHT).transpose();
01059 }
01060 }
01061 } else {
01062 if (dir[1]>0) {
01063 if (dir[2]>0) {
01064 return points.row(TOP_UPPER_LEFT).transpose();
01065 } else {
01066 return points.row(BOTTOM_UPPER_LEFT).transpose();
01067 }
01068 } else {
01069 if (dir[2]>0) {
01070 return points.row(TOP_LOWER_LEFT).transpose();
01071 } else {
01072 return points.row(BOTTOM_LOWER_LEFT).transpose();
01073 }
01074 }
01075 }
01076 }
01077
01078 fmat::Column<3> BoxObstacle::gradient(const fmat::SubVector<3,const fmat::fmatReal>& pt) const {
01079 const fmat::Column<3> p = unrot * pt;
01080
01081 if (p[0]<minEx[0]) {
01082 if (p[1]<minEx[1]) {
01083 if (p[2]<minEx[2]) {
01084 return fmat::Column<3>(points.row(BOTTOM_LOWER_LEFT).transpose()) - pt;
01085 } else if (maxEx[2]<p[2]) {
01086 return fmat::Column<3>(points.row(TOP_LOWER_LEFT).transpose()) - pt;
01087 } else {
01088 return unrot.transpose() * fmat::pack(minEx[0]-p[0], minEx[1]-p[1], 0);
01089 }
01090 } else if (maxEx[1]<p[1]) {
01091 if (p[2]<minEx[2]) {
01092 return fmat::Column<3>(points.row(BOTTOM_UPPER_LEFT).transpose()) - pt;
01093 } else if (maxEx[2]<p[2]) {
01094 return fmat::Column<3>(points.row(TOP_UPPER_LEFT).transpose()) - pt;
01095 } else {
01096 return unrot.transpose() * fmat::pack(minEx[0]-p[0], maxEx[1]-p[1], 0);
01097 }
01098 } else {
01099 if (p[2]<minEx[2]) {
01100 return unrot.transpose() * fmat::pack(minEx[0]-p[0], 0, minEx[2]-p[2]);
01101 } else if (maxEx[2]<p[2]) {
01102 return unrot.transpose() * fmat::pack(minEx[0]-p[0], 0, maxEx[2]-p[2]);
01103 } else {
01104 return unrot.row(0).transpose() * (minEx[0]-p[0]);
01105 }
01106 }
01107 } else if (maxEx[0]<p[0]) {
01108 if (p[1]<minEx[1]) {
01109 if (p[2]<minEx[2]) {
01110 return fmat::Column<3>(points.row(BOTTOM_LOWER_RIGHT).transpose()) - pt;
01111 } else if (maxEx[2]<p[2]) {
01112 return fmat::Column<3>(points.row(TOP_LOWER_RIGHT).transpose()) - pt;
01113 } else {
01114 return unrot.transpose() * fmat::pack(maxEx[0]-p[0], minEx[1]-p[1], 0);
01115 }
01116 } else if (maxEx[1]<p[1]) {
01117 if (p[2]<minEx[2]) {
01118 return fmat::Column<3>(points.row(BOTTOM_UPPER_RIGHT).transpose()) - pt;
01119 } else if (maxEx[2]<p[2]) {
01120 return fmat::Column<3>(points.row(TOP_UPPER_RIGHT).transpose()) - pt;
01121 } else {
01122 return unrot.transpose() * fmat::pack(maxEx[0]-p[0], maxEx[1]-p[1], 0);
01123 }
01124 } else {
01125 if (p[2]<minEx[2]) {
01126 return unrot.transpose() * fmat::pack(maxEx[0]-p[0], 0, minEx[2]-p[2]);
01127 } else if (maxEx[2]<p[2]) {
01128 return unrot.transpose() * fmat::pack(maxEx[0]-p[0], 0, maxEx[1]-p[1]);
01129 } else {
01130 return unrot.row(0).transpose() * (maxEx[0]-p[0]);
01131 }
01132 }
01133 } else if (p[1]<minEx[1]) {
01134 if (p[2]<minEx[2]) {
01135 return unrot.transpose() * fmat::pack(0, minEx[1]-p[1], minEx[2]-p[2]);
01136 } else if (maxEx[2]<p[2]) {
01137 return unrot.transpose() * fmat::pack(0, minEx[1]-p[1], maxEx[2]-p[2]);
01138 } else {
01139 return unrot.row(1).transpose() * (minEx[1]-p[1]);
01140 }
01141 } else if (maxEx[1]<p[1]) {
01142 if (p[2]<minEx[2]) {
01143 return unrot.transpose() * fmat::pack(0, maxEx[1]-p[1], minEx[2]-p[2]);
01144 } else if (maxEx[2]<p[2]) {
01145 return unrot.transpose() * fmat::pack(0, maxEx[1]-p[1], maxEx[2]-p[2]);
01146 } else {
01147 return unrot.row(1).transpose() * (maxEx[1]-p[1]);
01148 }
01149 } else if (p[2]<minEx[2]) {
01150 return unrot.row(2).transpose() * (minEx[2]-p[2]);
01151 } else if (maxEx[2]<p[2]) {
01152 return unrot.row(2).transpose() * (maxEx[2]-p[2]);
01153 } else {
01154 fmatReal dist[6];
01155 dist[0] = p[0]-minEx[0];
01156 dist[1] = p[1]-minEx[1];
01157 dist[2] = p[2]-minEx[2];
01158 dist[3] = maxEx[0]-p[0];
01159 dist[4] = maxEx[1]-p[1];
01160 dist[5] = maxEx[2]-p[2];
01161 if (dist[0] < dist[1]) {
01162 if (dist[0] < dist[2]) {
01163 if (dist[0] < dist[3]) {
01164 if (dist[0] < dist[4]) {
01165 if (dist[0] < dist[5]) {
01166 return unrot.row(0).transpose() * (minEx[0]-p[0]);
01167 }
01168 } else {
01169 if (dist[4] < dist[5]) {
01170 return unrot.row(1).transpose() * (maxEx[1]-p[1]);
01171 }
01172 }
01173 } else {
01174 if (dist[3] < dist[4]) {
01175 if (dist[3] < dist[5]) {
01176 return unrot.row(0).transpose() * (maxEx[0]-p[0]);
01177 }
01178 } else {
01179 if (dist[4] < dist[5]) {
01180 return unrot.row(1).transpose() * (maxEx[1]-p[1]);
01181 }
01182 }
01183 }
01184 } else {
01185 if (dist[2] < dist[3]) {
01186 if (dist[2] < dist[4]) {
01187 if (dist[2] < dist[5]) {
01188 return unrot.row(2).transpose() * (minEx[2]-p[2]);
01189 }
01190 } else {
01191 if (dist[4] < dist[5]) {
01192 return unrot.row(1).transpose() * (maxEx[1]-p[1]);
01193 }
01194 }
01195 } else {
01196 if (dist[3] < dist[4]) {
01197 if (dist[3] < dist[5]) {
01198 return unrot.row(0).transpose() * (maxEx[0]-p[0]);
01199 }
01200 } else {
01201 if (dist[4] < dist[5]) {
01202 return unrot.row(1).transpose() * (maxEx[1]-p[1]);
01203 }
01204 }
01205 }
01206 }
01207 } else {
01208 if (dist[1] < dist[2]) {
01209 if (dist[1] < dist[3]) {
01210 if (dist[1] < dist[4]) {
01211 if (dist[1] < dist[5]) {
01212 return unrot.row(1).transpose() * (minEx[1]-p[1]);
01213 }
01214 } else {
01215 if (dist[4] < dist[5]) {
01216 return unrot.row(1).transpose() * (maxEx[1]-p[1]);
01217 }
01218 }
01219 } else {
01220 if (dist[3] < dist[4]) {
01221 if (dist[3] < dist[5]) {
01222 return unrot.row(0).transpose() * (maxEx[0]-p[0]);
01223 }
01224 } else {
01225 if (dist[4] < dist[5]) {
01226 return unrot.row(1).transpose() * (maxEx[1]-p[1]);
01227 }
01228 }
01229 }
01230 } else {
01231 if (dist[2] < dist[3]) {
01232 if (dist[2] < dist[4]) {
01233 if (dist[2] < dist[4]) {
01234 return unrot.row(2).transpose() * (minEx[2]-p[2]);
01235 }
01236 } else {
01237 if (dist[4] < dist[5]) {
01238 return unrot.row(1).transpose() * (maxEx[1]-p[1]);
01239 }
01240 }
01241 } else {
01242 if (dist[3] < dist[4]) {
01243 if (dist[3] < dist[5]) {
01244 return unrot.row(0).transpose() * (maxEx[0]-p[0]);
01245 }
01246 } else {
01247 if (dist[4] < dist[5]) {
01248 return unrot.row(1).transpose() * (maxEx[1]-p[1]);
01249 }
01250 }
01251 }
01252 }
01253 }
01254 return unrot.row(2).transpose() * (maxEx[2]-p[2]);
01255 }
01256 }
01257
01258 void BoxObstacle::bloat(float amount) {
01259 reset(getCenter(),maxEx+amount,unrot.transpose());
01260 }
01261
01262 void BoxObstacle::contract(float amount) {
01263 bloat(-amount);
01264 }
01265
01266 void BoxObstacle::loadXML(xmlNode* node) {
01267
01268 plist::ArrayOf< plist::Primitive<fmat::fmatReal> > c(3,0,false);
01269 plist::ArrayOf< plist::Primitive<fmat::fmatReal> > d(3,0,false);
01270 plist::ArrayOf< plist::Primitive<fmat::fmatReal> > r(9,0,false);
01271 addEntry("Center",c);
01272 addEntry("Dimensions",d);
01273 addEntry("Orientation",r);
01274 PlannerObstacle3D::loadXML(node);
01275 removeEntry("Center");
01276 removeEntry("Dimensions");
01277 removeEntry("Orientation");
01278 fmat::Matrix<3,3> rot;
01279 reset(fmat::pack(c[0],c[1],c[2]), fmat::pack(d[0]/2,d[1]/2,d[2]/2), rot.importFromCMajor(r));
01280 }
01281
01282 void BoxObstacle::saveXML(xmlNode * node) const {
01283
01284 plist::ArrayOf< plist::Primitive<fmat::fmatReal> > c(3,0,false);
01285 getCenter().exportTo(c);
01286 c.setSaveInlineStyle(true);
01287 plist::ArrayOf< plist::Primitive<fmat::fmatReal> > d(3,0,false);
01288 d[0] = getLength();
01289 d[1] = getWidth();
01290 d[2] = getHeight();
01291 d.setSaveInlineStyle(true);
01292 plist::ArrayOf< plist::Primitive<fmat::fmatReal> > r(9,0,false);
01293 unrot.transpose().exportToCMajor(r);
01294 plist::Dictionary tmp(*this);
01295 tmp.addEntry("Center",c,"Center point");
01296 tmp.addEntry("Dimensions",d,"Width and height");
01297 tmp.addEntry("Orientation",r,"Rotation (3x3 Matrix condensed to float[9])");
01298 tmp.saveXML(node);
01299 }
01300
01301 BoundingBox3D CylindricalObstacle::getBoundingBox() const { return BoundingBox3D(); }
01302
01303 bool CylindricalObstacle::collides(const fmat::SubVector<3,const fmat::fmatReal>& point) const {
01304 fmat::Column<3> newPt = orientation.transpose() * point;
01305 if (std::abs(newPt[2]) < halfHeight && std::sqrt(newPt[0]*newPt[0] + newPt[1]*newPt[1]) < radius)
01306 return true;
01307 else
01308 return false;
01309 }
01310
01311 fmat::Column<3> CylindricalObstacle::getSupport(const fmat::SubVector<3,const fmat::fmatReal>& direction) const {
01312 fmat::Column<3> dir = orientation.transpose() * direction;
01313 fmat::fmatReal sigma = std::sqrt(dir[0]*dir[0] + dir[1]*dir[1]);
01314 if (sigma > 0) {
01315 return orientation.transpose() *
01316 fmat::pack(radius / sigma * dir[0],
01317 radius / sigma * dir[1],
01318 sgn(dir[2]) * halfHeight);
01319 }
01320 else {
01321 return orientation.transpose() *
01322 fmat::pack(0, 0, sgn(dir[2]) * halfHeight);
01323 }
01324 }
01325
01326 fmat::Column<3> CylindricalObstacle::gradient(const fmat::SubVector<3,const fmat::fmatReal>& pt) const { return fmat::Column<3>(); }
01327
01328 void CylindricalObstacle::loadXML(xmlNode* node) {
01329
01330 plist::ArrayOf< plist::Primitive<fmat::fmatReal> > c(3,0,false);
01331 plist::ArrayOf< plist::Primitive<fmat::fmatReal> > o(9,0,false);
01332 plist::Primitive<fmat::fmatReal> r;
01333 plist::Primitive<fmat::fmatReal> hh;
01334 addEntry("Center",c);
01335 addEntry("Orientation",o);
01336 addEntry("Radius",r);
01337 addEntry("HalfHeight",hh);
01338 PlannerObstacle3D::loadXML(node);
01339 removeEntry("Center");
01340 removeEntry("Orientation");
01341 removeEntry("Radius");
01342 removeEntry("HalfHeight");
01343 center.importFrom(c);
01344 radius = r;
01345 orientation.importFromCMajor(o);
01346 halfHeight = hh;
01347 }
01348
01349 void CylindricalObstacle::saveXML(xmlNode * node) const {
01350
01351 plist::ArrayOf< plist::Primitive<fmat::fmatReal> > c(3,0,false);
01352 c.setSaveInlineStyle(true);
01353 center.exportTo(c);
01354 plist::ArrayOf< plist::Primitive<fmat::fmatReal> > o(9,0,false);
01355 o.setSaveInlineStyle(true);
01356 orientation.exportToCMajor(o);
01357 plist::Primitive<fmat::fmatReal> r = radius;
01358 plist::Primitive<fmat::fmatReal> hh = halfHeight;
01359 plist::Dictionary tmp(*this);
01360 tmp.addEntry("Center",c);
01361 tmp.addEntry("Radius",r);
01362 tmp.addEntry("Orientation",o);
01363 tmp.addEntry("HalfHeight",hh);
01364 tmp.saveXML(node);
01365 }
01366
01367 bool SphericalObstacle::collides(const fmat::SubVector<3,const fmat::fmatReal>& point) const {
01368
01369 return (point - center).sumSq() <= radius * radius;
01370 }
01371
01372 fmat::Column<3> SphericalObstacle::getSupport(const fmat::SubVector<3,const fmat::fmatReal>& direction) const {
01373 return center + (direction / direction.norm() * radius);
01374 }
01375
01376 fmat::Column<3> SphericalObstacle::gradient(const fmat::SubVector<3,const fmat::fmatReal>& pt) const {
01377 fmat::Column<3> v = pt - center;
01378 fmat::fmatReal n = v.norm();
01379 if(n == 0)
01380 return fmat::pack(radius,0,0);
01381 return v * ((radius - n)/n);
01382 }
01383
01384 void SphericalObstacle::loadXML(xmlNode* node) {
01385
01386 plist::ArrayOf< plist::Primitive<fmat::fmatReal> > c(3,0,false);
01387 plist::Primitive<fmat::fmatReal> r;
01388 addEntry("Center",c);
01389 addEntry("Radius",r);
01390 PlannerObstacle3D::loadXML(node);
01391 removeEntry("Center");
01392 removeEntry("Radius");
01393 center.importFrom(c);
01394 radius = r;
01395 }
01396
01397 void SphericalObstacle::saveXML(xmlNode * node) const {
01398
01399 plist::ArrayOf< plist::Primitive<fmat::fmatReal> > c(3,0,false);
01400 c.setSaveInlineStyle(true);
01401 center.exportTo(c);
01402 plist::Primitive<fmat::fmatReal> r = radius;
01403 plist::Dictionary tmp(*this);
01404 tmp.addEntry("Center",c);
01405 tmp.addEntry("Radius",r);
01406 tmp.saveXML(node);
01407 }
01408
01409 BoundingBox3D EllipsoidObstacle::getBoundingBox() const { return BoundingBox3D(); }
01410
01411 bool EllipsoidObstacle::collides(const fmat::SubVector<3,const fmat::fmatReal>& point) const {
01412 fmat::Column<3> newPt = orientation.transpose() * point;
01413
01414
01415 newPt[0] /= extents[0];
01416 newPt[1] /= extents[1];
01417 newPt[2] /= extents[2];
01418 if (newPt.sumSq() < 1)
01419 return true;
01420 else
01421 return false;
01422 }
01423
01424 fmat::Column<3> EllipsoidObstacle::getSupport(const fmat::SubVector<3,const fmat::fmatReal>& direction) const {
01425 fmat::Column<3> dir = orientation.transpose() * direction;
01426
01427 if (dir[0] == 0) {
01428 fmat::Column<2> s = get2Support(fmat::pack(dir[1],dir[2]));
01429 return orientation * fmat::pack(0, s[0], s[1]) + center;
01430 }
01431 else if (dir[1] == 0) {
01432 fmat::Column<2> s = get2Support(fmat::pack(dir[0],dir[2]));
01433 return orientation * fmat::pack(s[0], 0, s[1]) + center;
01434 }
01435 else if (dir[2] == 0) {
01436 fmat::Column<2> s = get2Support(fmat::pack(dir[0],dir[1]));
01437 return orientation * fmat::pack(s[0], s[1], 0) + center;
01438 }
01439
01440
01441 fmat::fmatReal a2 = extents[0]*extents[0], b2 = extents[1]*extents[1], c2 = extents[2]*extents[2];
01442
01443
01444 fmat::fmatReal k1 = (dir[1]*b2)/(dir[0]*a2);
01445 fmat::fmatReal k2 = (dir[2]*c2)/(dir[0]*a2);
01446 fmat::fmatReal x = sgn(dir[0]) * std::sqrt(1/((1/(a2)) + (k1*k1/(b2)) + (k2*k2/(c2))));
01447
01448 return orientation * fmat::pack(x, k1*x, k2*x) + center;
01449 }
01450
01451 fmat::Column<2> EllipsoidObstacle::get2Support(const fmat::SubVector<2,const fmat::fmatReal>& direction) const {
01452
01453 if (direction[0] == 0) {
01454 return fmat::pack(0, sgn(direction[1]) * extents[1]);
01455 }
01456 else if (direction[1] == 0) {
01457 return fmat::pack(sgn(direction[0]) * extents[0], 0);
01458 }
01459
01460
01461 fmat::fmatReal a2 = extents[0]*extents[0], b2 = extents[1]*extents[1];
01462
01463
01464 fmat::fmatReal k = (direction[1]*b2)/(direction[0]*a2);
01465 fmat::fmatReal x = sgn(direction[0]) * std::sqrt(1/((1/(a2)) + (k*k/(b2))));
01466
01467 return fmat::pack(x, k*x);
01468 }
01469
01470 fmat::Column<3> EllipsoidObstacle::gradient(const fmat::SubVector<3,const fmat::fmatReal>& pt) const { return fmat::Column<3>(); }
01471
01472 void EllipsoidObstacle::loadXML(xmlNode* node) {
01473
01474 plist::ArrayOf< plist::Primitive<fmat::fmatReal> > c(3,0,false);
01475 plist::ArrayOf< plist::Primitive<fmat::fmatReal> > o(9,0,false);
01476 plist::ArrayOf< plist::Primitive<fmat::fmatReal> > e(3,0,false);
01477 addEntry("Center",c);
01478 addEntry("Orientation",o);
01479 addEntry("Extents",e);
01480 PlannerObstacle3D::loadXML(node);
01481 removeEntry("Center");
01482 removeEntry("Orientation");
01483 removeEntry("Extents");
01484 center.importFrom(c);
01485 orientation.importFromCMajor(o);
01486 extents.importFrom(e);
01487 }
01488
01489 void EllipsoidObstacle::saveXML(xmlNode * node) const {
01490
01491 plist::ArrayOf< plist::Primitive<fmat::fmatReal> > c(3,0,false);
01492 c.setSaveInlineStyle(true);
01493 center.exportTo(c);
01494 plist::ArrayOf< plist::Primitive<fmat::fmatReal> > o(9,0,false);
01495 o.setSaveInlineStyle(true);
01496 orientation.exportToCMajor(o);
01497 plist::ArrayOf< plist::Primitive<fmat::fmatReal> > e(3,0,false);
01498 e.setSaveInlineStyle(true);
01499 extents.exportTo(e);
01500 plist::Dictionary tmp(*this);
01501 tmp.addEntry("Center",c);
01502 tmp.addEntry("Orietation",o);
01503 tmp.addEntry("Extents",e);
01504 tmp.saveXML(node);
01505 }