bodies.cpp
Go to the documentation of this file.
00001 /*********************************************************************
00002 * Software License Agreement (BSD License)
00003 * 
00004 *  Copyright (c) 2008, Willow Garage, Inc.
00005 *  All rights reserved.
00006 * 
00007 *  Redistribution and use in source and binary forms, with or without
00008 *  modification, are permitted provided that the following conditions
00009 *  are met:
00010 * 
00011 *   * Redistributions of source code must retain the above copyright
00012 *     notice, this list of conditions and the following disclaimer.
00013 *   * Redistributions in binary form must reproduce the above
00014 *     copyright notice, this list of conditions and the following
00015 *     disclaimer in the documentation and/or other materials provided
00016 *     with the distribution.
00017 *   * Neither the name of the Willow Garage nor the names of its
00018 *     contributors may be used to endorse or promote products derived
00019 *     from this software without specific prior written permission.
00020 * 
00021 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00022 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00023 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00024 *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
00025 *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00026 *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00027 *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00028 *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00029 *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00030 *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
00031 *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00032 *  POSSIBILITY OF SUCH DAMAGE.
00033 *********************************************************************/
00034 
00037 #include "geometric_shapes/bodies.h"
00038 
00039 #include <ros/console.h>
00040 
00041 extern "C"
00042 {
00043 #ifdef GEOMETRIC_SHAPES_HAVE_QHULL_2011
00044 #include <libqhull/libqhull.h>
00045 #include <libqhull/mem.h>
00046 #include <libqhull/qset.h>
00047 #include <libqhull/geom.h>
00048 #include <libqhull/merge.h>
00049 #include <libqhull/poly.h>
00050 #include <libqhull/io.h>
00051 #include <libqhull/stat.h>
00052 #else
00053 #include <qhull/qhull.h>
00054 #include <qhull/mem.h>
00055 #include <qhull/qset.h>
00056 #include <qhull/geom.h>
00057 #include <qhull/merge.h>
00058 #include <qhull/poly.h>
00059 #include <qhull/io.h>
00060 #include <qhull/stat.h>
00061 #endif
00062 }
00063 
00064 #include <algorithm>
00065 #include <iostream>
00066 #include <cmath>
00067 
00068 bodies::Body* bodies::createBodyFromShape(const shapes::Shape *shape)
00069 {
00070   Body *body = NULL;
00071     
00072   if (shape)
00073     switch (shape->type)
00074     {
00075     case shapes::BOX:
00076       body = new bodies::Box(shape);
00077       break;
00078     case shapes::SPHERE:
00079       body = new bodies::Sphere(shape);
00080       break;
00081     case shapes::CYLINDER:
00082       body = new bodies::Cylinder(shape);
00083       break;
00084     case shapes::MESH:
00085       body = new bodies::ConvexMesh(shape);
00086       break;
00087     default:
00088       ROS_ERROR("Creating body from shape: Unknown shape type %d", (int)shape->type);
00089       break;
00090     }
00091     
00092   return body;
00093 }
00094 
00095 void bodies::mergeBoundingSpheres(const std::vector<BoundingSphere> &spheres, BoundingSphere &mergedSphere)
00096 {
00097   if (spheres.empty())
00098   {
00099     mergedSphere.center.setValue(tfScalar(0), tfScalar(0), tfScalar(0));
00100     mergedSphere.radius = 0.0;
00101   }
00102   else
00103   {
00104     mergedSphere = spheres[0];
00105     for (unsigned int i = 1 ; i < spheres.size() ; ++i)
00106     {
00107       if (spheres[i].radius <= 0.0)
00108         continue;
00109       double d = spheres[i].center.distance(mergedSphere.center);
00110       if (d + mergedSphere.radius <= spheres[i].radius)
00111       {
00112         mergedSphere.center = spheres[i].center;
00113         mergedSphere.radius = spheres[i].radius;
00114       }
00115       else
00116         if (d + spheres[i].radius > mergedSphere.radius)
00117         {
00118           tf::Vector3 delta = mergedSphere.center - spheres[i].center;
00119           mergedSphere.radius = (delta.length() + spheres[i].radius + mergedSphere.radius)/2.0;
00120           mergedSphere.center = delta.normalized() * (mergedSphere.radius - spheres[i].radius) + spheres[i].center;
00121         }
00122     }
00123   }
00124 }
00125 
00126 namespace bodies
00127 {
00128 static const double ZERO = 1e-9;
00129     
00132 static inline double distanceSQR(const tf::Vector3& p, const tf::Vector3& origin, const tf::Vector3& dir)
00133 {
00134   tf::Vector3 a = p - origin;
00135   double d = dir.dot(a);
00136   return a.length2() - d * d;
00137 }
00138     
00139 namespace detail
00140 {
00141         
00142 // temp structure for intersection points (used for ordering them)
00143 struct intersc
00144 {
00145   intersc(const tf::Vector3 &_pt, const double _tm) : pt(_pt), time(_tm) {}
00146             
00147   tf::Vector3 pt;
00148   double    time;
00149 };
00150         
00151 // define order on intersection points
00152 struct interscOrder
00153 {
00154   bool operator()(const intersc &a, const intersc &b) const
00155   {
00156     return a.time < b.time;
00157   }
00158 };
00159 }
00160 }
00161 
00162 bool bodies::Sphere::containsPoint(const tf::Vector3 &p, bool verbose) const 
00163 {
00164   return (m_center - p).length2() < m_radius2;
00165 }
00166 
00167 void bodies::Sphere::useDimensions(const shapes::Shape *shape) // radius
00168 {
00169   m_radius = static_cast<const shapes::Sphere*>(shape)->radius;
00170 }
00171 
00172 void bodies::Sphere::updateInternalData(void)
00173 {
00174   m_radiusU = m_radius * m_scale + m_padding;
00175   m_radius2 = m_radiusU * m_radiusU;
00176   m_center = m_pose.getOrigin();
00177 }
00178 
00179 double bodies::Sphere::computeVolume(void) const
00180 {
00181   return 4.0 * M_PI * m_radiusU * m_radiusU * m_radiusU / 3.0;
00182 }
00183 
00184 void bodies::Sphere::computeBoundingSphere(BoundingSphere &sphere) const
00185 {
00186   sphere.center = m_center;
00187   sphere.radius = m_radiusU;
00188 }
00189 
00190 void bodies::Sphere::computeBoundingCylinder(BoundingCylinder &cylinder) const 
00191 {
00192   cylinder.pose = m_pose;
00193   cylinder.radius = m_radiusU;
00194   cylinder.length = m_radiusU;
00195 
00196 }
00197 
00198 bool bodies::Sphere::intersectsRay(const tf::Vector3& origin, const tf::Vector3& dir, std::vector<tf::Vector3> *intersections, unsigned int count) const
00199 {
00200   if (distanceSQR(m_center, origin, dir) > m_radius2) return false;
00201     
00202   bool result = false;
00203     
00204   tf::Vector3 cp = origin - m_center;
00205   double dpcpv = cp.dot(dir);
00206     
00207   tf::Vector3 w = cp - dpcpv * dir;
00208   tf::Vector3 Q = m_center + w;
00209   double x = m_radius2 - w.length2();
00210     
00211   if (fabs(x) < ZERO)
00212   { 
00213     w = Q - origin;
00214     double dpQv = w.dot(dir);
00215     if (dpQv > ZERO)
00216     {
00217       if (intersections)
00218         intersections->push_back(Q);
00219       result = true;
00220     }
00221   } else 
00222     if (x > 0.0)
00223     {    
00224       x = sqrt(x);
00225       w = dir * x;
00226       tf::Vector3 A = Q - w;
00227       tf::Vector3 B = Q + w;
00228       w = A - origin;
00229       double dpAv = w.dot(dir);
00230       w = B - origin;
00231       double dpBv = w.dot(dir);
00232             
00233       if (dpAv > ZERO)
00234       { 
00235         result = true;
00236         if (intersections)
00237         {
00238           intersections->push_back(A);
00239           if (count == 1)
00240             return result;
00241         }
00242       }
00243             
00244       if (dpBv > ZERO)
00245       {
00246         result = true;
00247         if (intersections)
00248           intersections->push_back(B);
00249       }
00250     }
00251   return result;
00252 }
00253 
00254 bool bodies::Cylinder::containsPoint(const tf::Vector3 &p, bool verbose) const 
00255 {
00256   tf::Vector3 v = p - m_center;         
00257   double pH = v.dot(m_normalH);
00258     
00259   if (fabs(pH) > m_length2)
00260     return false;
00261     
00262   double pB1 = v.dot(m_normalB1);
00263   double remaining = m_radius2 - pB1 * pB1;
00264     
00265   if (remaining < 0.0)
00266     return false;
00267   else
00268   {
00269     double pB2 = v.dot(m_normalB2);
00270     return pB2 * pB2 < remaining;
00271   }             
00272 }
00273 
00274 void bodies::Cylinder::useDimensions(const shapes::Shape *shape) // (length, radius)
00275 {
00276   m_length = static_cast<const shapes::Cylinder*>(shape)->length;
00277   m_radius = static_cast<const shapes::Cylinder*>(shape)->radius;
00278 }
00279 
00280 void bodies::Cylinder::updateInternalData(void)
00281 {
00282   m_radiusU = m_radius * m_scale + m_padding;
00283   m_radius2 = m_radiusU * m_radiusU;
00284   m_length2 = m_scale * m_length / 2.0 + m_padding;
00285   m_center = m_pose.getOrigin();
00286   m_radiusBSqr = m_length2 * m_length2 + m_radius2;
00287   m_radiusB = sqrt(m_radiusBSqr);
00288     
00289   const tf::Matrix3x3& basis = m_pose.getBasis();
00290   m_normalB1 = basis.getColumn(0);
00291   m_normalB2 = basis.getColumn(1);
00292   m_normalH  = basis.getColumn(2);
00293     
00294   double tmp = -m_normalH.dot(m_center);
00295   m_d1 = tmp + m_length2;
00296   m_d2 = tmp - m_length2;
00297 }
00298 
00299 double bodies::Cylinder::computeVolume(void) const
00300 {
00301   return 2.0 * M_PI * m_radius2 * m_length2;
00302 }
00303 
00304 void bodies::Cylinder::computeBoundingSphere(BoundingSphere &sphere) const
00305 {
00306   sphere.center = m_center;
00307   sphere.radius = m_radiusB;
00308 }
00309 
00310 void bodies::Cylinder::computeBoundingCylinder(BoundingCylinder &cylinder) const
00311 {
00312   cylinder.pose = m_pose;
00313   cylinder.radius = m_radiusU;
00314   cylinder.length = m_scale*m_length+m_padding;
00315 }
00316 
00317 bool bodies::Cylinder::intersectsRay(const tf::Vector3& origin, const tf::Vector3& dir, std::vector<tf::Vector3> *intersections, unsigned int count) const
00318 {
00319   if (distanceSQR(m_center, origin, dir) > m_radiusBSqr) return false;
00320 
00321   std::vector<detail::intersc> ipts;
00322     
00323   // intersect bases
00324   double tmp = m_normalH.dot(dir);
00325   if (fabs(tmp) > ZERO)
00326   {
00327     double tmp2 = -m_normalH.dot(origin);
00328     double t1 = (tmp2 - m_d1) / tmp;
00329         
00330     if (t1 > 0.0)
00331     {
00332       tf::Vector3 p1(origin + dir * t1);
00333       tf::Vector3 v1(p1 - m_center);
00334       v1 = v1 - m_normalH.dot(v1) * m_normalH;
00335       if (v1.length2() < m_radius2 + ZERO)
00336       {
00337         if (intersections == NULL)
00338           return true;
00339                 
00340         detail::intersc ip(p1, t1);
00341         ipts.push_back(ip);
00342       }
00343     }
00344         
00345     double t2 = (tmp2 - m_d2) / tmp;
00346     if (t2 > 0.0)
00347     {
00348       tf::Vector3 p2(origin + dir * t2);
00349       tf::Vector3 v2(p2 - m_center);
00350       v2 = v2 - m_normalH.dot(v2) * m_normalH;
00351       if (v2.length2() < m_radius2 + ZERO)
00352       {
00353         if (intersections == NULL)
00354           return true;
00355                 
00356         detail::intersc ip(p2, t2);
00357         ipts.push_back(ip);
00358       }
00359     }
00360   }
00361     
00362   if (ipts.size() < 2)
00363   {
00364     // intersect with infinite cylinder
00365     tf::Vector3 VD(m_normalH.cross(dir));
00366     tf::Vector3 ROD(m_normalH.cross(origin - m_center));
00367     double a = VD.length2();
00368     double b = 2.0 * ROD.dot(VD);
00369     double c = ROD.length2() - m_radius2;
00370     double d = b * b - 4.0 * a * c;
00371     if (d > 0.0 && fabs(a) > ZERO)
00372     {
00373       d = sqrt(d);
00374       double e = -a * 2.0;
00375       double t1 = (b + d) / e;
00376       double t2 = (b - d) / e;
00377             
00378       if (t1 > 0.0)
00379       {
00380         tf::Vector3 p1(origin + dir * t1);
00381         tf::Vector3 v1(m_center - p1);
00382                 
00383         if (fabs(m_normalH.dot(v1)) < m_length2 + ZERO)
00384         {
00385           if (intersections == NULL)
00386             return true;
00387                     
00388           detail::intersc ip(p1, t1);
00389           ipts.push_back(ip);
00390         }
00391       }
00392             
00393       if (t2 > 0.0)
00394       {
00395         tf::Vector3 p2(origin + dir * t2);    
00396         tf::Vector3 v2(m_center - p2);
00397                 
00398         if (fabs(m_normalH.dot(v2)) < m_length2 + ZERO)
00399         {
00400           if (intersections == NULL)
00401             return true;
00402           detail::intersc ip(p2, t2);
00403           ipts.push_back(ip);
00404         }
00405       }
00406     }
00407   }
00408     
00409   if (ipts.empty())
00410     return false;
00411 
00412   std::sort(ipts.begin(), ipts.end(), detail::interscOrder());
00413   const unsigned int n = count > 0 ? std::min<unsigned int>(count, ipts.size()) : ipts.size();
00414   for (unsigned int i = 0 ; i < n ; ++i)
00415     intersections->push_back(ipts[i].pt);
00416     
00417   return true;
00418 }
00419 
00420 bool bodies::Box::containsPoint(const tf::Vector3 &p, bool verbose) const 
00421 {
00422   /*  if(verbose)
00423       fprintf(stderr,"Actual: %f,%f,%f \nDesired: %f,%f,%f \nTolerance:%f,%f,%f\n",p.x(),p.y(),p.z(),m_center.x(),m_center.y(),m_center.z(),m_length2,m_width2,m_height2);*/
00424   tf::Vector3 v = p - m_center;
00425   double pL = v.dot(m_normalL);
00426     
00427   if (fabs(pL) > m_length2)
00428     return false;
00429     
00430   double pW = v.dot(m_normalW);
00431     
00432   if (fabs(pW) > m_width2)
00433     return false;
00434     
00435   double pH = v.dot(m_normalH);
00436     
00437   if (fabs(pH) > m_height2)
00438     return false;
00439     
00440   return true;
00441 }
00442 
00443 void bodies::Box::useDimensions(const shapes::Shape *shape) // (x, y, z) = (length, width, height)
00444 {
00445   const double *size = static_cast<const shapes::Box*>(shape)->size;
00446   m_length = size[0];
00447   m_width  = size[1];
00448   m_height = size[2];
00449 }
00450 
00451 void bodies::Box::updateInternalData(void) 
00452 {
00453   double s2 = m_scale / 2.0;
00454   m_length2 = m_length * s2 + m_padding;
00455   m_width2  = m_width * s2 + m_padding;
00456   m_height2 = m_height * s2 + m_padding;
00457     
00458   m_center  = m_pose.getOrigin();
00459     
00460   m_radius2 = m_length2 * m_length2 + m_width2 * m_width2 + m_height2 * m_height2;
00461   m_radiusB = sqrt(m_radius2);
00462 
00463   const tf::Matrix3x3& basis = m_pose.getBasis();
00464   m_normalL = basis.getColumn(0);
00465   m_normalW = basis.getColumn(1);
00466   m_normalH = basis.getColumn(2);
00467 
00468   const tf::Vector3 tmp(m_normalL * m_length2 + m_normalW * m_width2 + m_normalH * m_height2);
00469   m_corner1 = m_center - tmp;
00470   m_corner2 = m_center + tmp;
00471 }
00472 
00473 double bodies::Box::computeVolume(void) const
00474 {
00475   return 8.0 * m_length2 * m_width2 * m_height2;
00476 }
00477 
00478 void bodies::Box::computeBoundingSphere(BoundingSphere &sphere) const
00479 {
00480   sphere.center = m_center;
00481   sphere.radius = m_radiusB;
00482 }
00483 
00484 void bodies::Box::computeBoundingCylinder(BoundingCylinder &cylinder) const
00485 {
00486   double a, b;
00487   
00488   if(m_length2 > m_width2 && m_length2 > m_height2) {
00489     cylinder.length = m_length2*2.0;
00490     a = m_width2;
00491     b = m_height2;
00492     tf::Transform rot(tf::Quaternion(tf::Vector3(0,1,0),M_PI));
00493     cylinder.pose = m_pose*rot;
00494   } else if(m_width2 > m_height2) {
00495     cylinder.length = m_width2*2.0;
00496     a = m_height2;
00497     b = m_length2;
00498     cylinder.radius = sqrt(m_height2*m_height2+m_length2*m_length2);
00499     tf::Transform rot(tf::Quaternion(tf::Vector3(1,0,0),M_PI));
00500     cylinder.pose = m_pose*rot;
00501   } else {
00502     cylinder.length = m_height2*2.0;
00503     a = m_width2;
00504     b = m_length2;
00505     cylinder.pose = m_pose;
00506   }
00507   cylinder.radius = sqrt((a)*(a)+(b)*(b));
00508   //cylinder.radius = sqrt(2*(max_rad*max_rad));
00509 }
00510 
00511 bool bodies::Box::intersectsRay(const tf::Vector3& origin, const tf::Vector3& dir, std::vector<tf::Vector3> *intersections, unsigned int count) const
00512 {  
00513   if (distanceSQR(m_center, origin, dir) > m_radius2) return false;
00514 
00515   double t_near = -INFINITY;
00516   double t_far  = INFINITY;
00517     
00518   for (int i = 0; i < 3; i++)
00519   {
00520     const tf::Vector3 &vN = i == 0 ? m_normalL : (i == 1 ? m_normalW : m_normalH);
00521     double dp = vN.dot(dir);
00522         
00523     if (fabs(dp) > ZERO)
00524     {
00525       double t1 = vN.dot(m_corner1 - origin) / dp;
00526       double t2 = vN.dot(m_corner2 - origin) / dp;
00527             
00528       if (t1 > t2)
00529         std::swap(t1, t2);
00530             
00531       if (t1 > t_near)
00532         t_near = t1;
00533             
00534       if (t2 < t_far)
00535         t_far = t2;
00536             
00537       if (t_near > t_far)
00538         return false;
00539             
00540       if (t_far < 0.0)
00541         return false;
00542     }
00543     else
00544     {
00545       if (i == 0)
00546       {
00547         if ((std::min(m_corner1.y(), m_corner2.y()) > origin.y() ||
00548              std::max(m_corner1.y(), m_corner2.y()) < origin.y()) && 
00549             (std::min(m_corner1.z(), m_corner2.z()) > origin.z() ||
00550              std::max(m_corner1.z(), m_corner2.z()) < origin.z()))
00551           return false;
00552       }
00553       else
00554       {
00555         if (i == 1)
00556         {
00557           if ((std::min(m_corner1.x(), m_corner2.x()) > origin.x() ||
00558                std::max(m_corner1.x(), m_corner2.x()) < origin.x()) && 
00559               (std::min(m_corner1.z(), m_corner2.z()) > origin.z() ||
00560                std::max(m_corner1.z(), m_corner2.z()) < origin.z()))
00561             return false;
00562         }
00563         else
00564           if ((std::min(m_corner1.x(), m_corner2.x()) > origin.x() ||
00565                std::max(m_corner1.x(), m_corner2.x()) < origin.x()) && 
00566               (std::min(m_corner1.y(), m_corner2.y()) > origin.y() ||
00567                std::max(m_corner1.y(), m_corner2.y()) < origin.y()))
00568             return false;
00569       }
00570     }
00571   }
00572     
00573   if (intersections)
00574   {
00575     if (t_far - t_near > ZERO)
00576     {
00577       intersections->push_back(t_near * dir + origin);
00578       if (count > 1)
00579         intersections->push_back(t_far  * dir + origin);
00580     }
00581     else
00582       intersections->push_back(t_far * dir + origin);
00583   }
00584     
00585   return true;
00586 }
00587 /*
00588   bool bodies::Mesh::containsPoint(const tf::Vector3 &p) const
00589   {
00590   // compute all intersections
00591   std::vector<tf::Vector3> pts;
00592   intersectsRay(p, tf::Vector3(0, 0, 1), &pts);
00593     
00594   // if we have an odd number of intersections, we are inside
00595   return pts.size() % 2 == 1;
00596   }
00597 
00598   namespace bodies
00599   {
00600   namespace detail
00601   {
00602   // callback for bullet 
00603   class myTriangleCallback : public btTriangleCallback
00604   {
00605   public:
00606             
00607   myTriangleCallback(bool keep_triangles) : keep_triangles_(keep_triangles)
00608   {
00609   found_intersections = false;
00610   }
00611             
00612   virtual void processTriangle(tf::Vector3 *triangle, int partId, int triangleIndex)
00613   {
00614   found_intersections = true;
00615   if (keep_triangles_)
00616   triangles.push_back(btTriangleShape(triangle[0], triangle[1], triangle[2]));
00618   }
00619             
00620   bool                         found_intersections;
00621   std::vector<btTriangleShape> triangles;
00622             
00623   private:
00624             
00625   bool                         keep_triangles_;
00626   };
00627 
00628   }
00629   }
00630 
00631   bool bodies::Mesh::intersectsRay(const tf::Vector3& origin, const tf::Vector3& dir, std::vector<tf::Vector3> *intersections, unsigned int count) const
00632   {
00633   if (m_btMeshShape)
00634   {
00635         
00636   if (distanceSQR(m_center, origin, dir) > m_radiusBSqr) return false;
00637         
00638   // transform the ray into the coordinate frame of the mesh
00639   tf::Vector3 orig(m_iPose * origin);
00640   tf::Vector3 dr(m_iPose.getBasis() * dir);
00641         
00642   // find intersection with AABB
00643   tfScalar maxT = 0.0;
00644         
00645   if (fabs(dr.x()) > ZERO)
00646   {
00647   tfScalar t = (m_aabbMax.x() - orig.x()) / dr.x();
00648   if (t < 0.0)
00649   t = (m_aabbMin.x() - orig.x()) / dr.x();
00650   if (t > maxT)
00651   maxT = t;
00652   }
00653   if (fabs(dr.y()) > ZERO)
00654   {
00655   tfScalar t = (m_aabbMax.y() - orig.y()) / dr.y();
00656   if (t < 0.0)
00657   t = (m_aabbMin.y() - orig.y()) / dr.y();
00658   if (t > maxT)
00659   maxT = t;
00660   }
00661   if (fabs(dr.z()) > ZERO)
00662   {
00663   tfScalar t = (m_aabbMax.z() - orig.z()) / dr.z();
00664   if (t < 0.0)
00665   t = (m_aabbMin.z() - orig.z()) / dr.z();
00666   if (t > maxT)
00667   maxT = t;
00668   }
00669         
00670   // the farthest point where we could have an intersection id orig + dr * maxT
00671         
00672   detail::myTriangleCallback cb(intersections != NULL);
00673   m_btMeshShape->performRaycast(&cb, orig, orig + dr * maxT);
00674   if (cb.found_intersections)
00675   {
00676   if (intersections)
00677   {
00678   std::vector<detail::intersc> intpt;
00679   for (unsigned int i = 0 ; i < cb.triangles.size() ; ++i)
00680   {
00681   tf::Vector3 normal;
00682   cb.triangles[i].calcNormal(normal);
00683   tfScalar dv = normal.dot(dr);
00684   if (fabs(dv) > 1e-3)
00685   {
00686   double t = (normal.dot(cb.triangles[i].getVertexPtr(0)) - normal.dot(orig)) / dv;                     
00687   // here we use the input origin & direction, since the transform is linear
00688   detail::intersc ip(origin + dir * t, t);
00689   intpt.push_back(ip);
00690   }
00691   }
00692   std::sort(intpt.begin(), intpt.end(), detail::interscOrder());
00693   const unsigned int n = count > 0 ? std::min<unsigned int>(count, intpt.size()) : intpt.size();
00694   for (unsigned int i = 0 ; i < n ; ++i)
00695   intersections->push_back(intpt[i].pt);
00696   }
00697   return true;      
00698   }
00699   else
00700   return false;
00701   }
00702   else
00703   return false;
00704   }   
00705 
00706   void bodies::Mesh::useDimensions(const shapes::Shape *shape)
00707   {  
00708   const shapes::Mesh *mesh = static_cast<const shapes::Mesh*>(shape);
00709   if (m_btMeshShape)
00710   delete m_btMeshShape;
00711   if (m_btMesh)
00712   delete m_btMesh;
00713     
00714   m_btMesh = new btTriangleMesh();
00715   const unsigned int nt = mesh->triangleCount / 3;
00716   for (unsigned int i = 0 ; i < nt ; ++i)
00717   {
00718   const unsigned int i3 = i *3;
00719   const unsigned int v1 = 3 * mesh->triangles[i3];
00720   const unsigned int v2 = 3 * mesh->triangles[i3 + 1];
00721   const unsigned int v3 = 3 * mesh->triangles[i3 + 2];
00722   m_btMesh->addTriangle(tf::Vector3(mesh->vertices[v1], mesh->vertices[v1 + 1], mesh->vertices[v1 + 2]),
00723   tf::Vector3(mesh->vertices[v2], mesh->vertices[v2 + 1], mesh->vertices[v2 + 2]),
00724   tf::Vector3(mesh->vertices[v3], mesh->vertices[v3 + 1], mesh->vertices[v3 + 2]), true);
00725   }
00726     
00727   m_btMeshShape = new btBvhTriangleMeshShape(m_btMesh, true);
00728   }
00729 
00730   void bodies::Mesh::updateInternalData(void) 
00731   {
00732   if (m_btMeshShape)
00733   {
00734   m_btMeshShape->setLocalScaling(tf::Vector3(m_scale, m_scale, m_scale));
00735   m_btMeshShape->setMargin(m_padding);
00736   }
00737   m_iPose = m_pose.inverse();
00738     
00739   tf::Transform id;
00740   id.setIdentity();
00741   m_btMeshShape->getAabb(id, m_aabbMin, m_aabbMax);
00742 
00743   tf::Vector3 d = (m_aabbMax - m_aabbMin) / 2.0;
00744 
00745   m_center = m_pose.getOrigin() + d;
00746   m_radiusBSqr = d.length2();
00747   m_radiusB = sqrt(m_radiusBSqr);
00748     
00750   }
00751 
00752   double bodies::Mesh::computeVolume(void) const
00753   {
00754   if (m_btMeshShape)
00755   {
00756   // approximation; volume of AABB at identity transform
00757   tf::Vector3 d = m_aabbMax - m_aabbMin;
00758   return d.x() * d.y() * d.z();
00759   }
00760   else
00761   return 0.0;
00762   }
00763 
00764   void bodies::Mesh::computeBoundingSphere(BoundingSphere &sphere) const
00765   {
00766   sphere.center = m_center;
00767   sphere.radius = m_radiusB;
00768   }
00769 
00770 */
00771 
00772 bool bodies::ConvexMesh::containsPoint(const tf::Vector3 &p, bool verbose) const
00773 {
00774   if (m_boundingBox.containsPoint(p))
00775   {
00776     tf::Vector3 ip(m_iPose * p);
00777     ip = m_meshCenter + (ip - m_meshCenter) * m_scale;
00778     return isPointInsidePlanes(ip);
00779   }
00780   else
00781     return false;
00782 }
00783 
00784 void bodies::ConvexMesh::useDimensions(const shapes::Shape *shape)
00785 {  
00786   const shapes::Mesh *mesh = static_cast<const shapes::Mesh*>(shape);
00787 
00788   double maxX = -INFINITY, maxY = -INFINITY, maxZ = -INFINITY;
00789   double minX =  INFINITY, minY =  INFINITY, minZ  = INFINITY;
00790     
00791   for(unsigned int i = 0; i < mesh->vertexCount ; ++i)
00792   {
00793     double vx = mesh->vertices[3 * i    ];
00794     double vy = mesh->vertices[3 * i + 1];
00795     double vz = mesh->vertices[3 * i + 2];
00796         
00797     if (maxX < vx) maxX = vx;
00798     if (maxY < vy) maxY = vy;
00799     if (maxZ < vz) maxZ = vz;
00800         
00801     if (minX > vx) minX = vx;
00802     if (minY > vy) minY = vy;
00803     if (minZ > vz) minZ = vz;
00804   }
00805     
00806   if (maxX < minX) maxX = minX = 0.0;
00807   if (maxY < minY) maxY = minY = 0.0;
00808   if (maxZ < minZ) maxZ = minZ = 0.0;
00809     
00810   shapes::Box *box_shape = new shapes::Box(maxX - minX, maxY - minY, maxZ - minZ);
00811   m_boundingBox.setDimensions(box_shape);
00812   delete box_shape;
00813  
00814   m_boxOffset.setValue((minX + maxX) / 2.0, (minY + maxY) / 2.0, (minZ + maxZ) / 2.0);
00815     
00816   m_planes.clear();
00817   m_triangles.clear();
00818   m_vertices.clear();
00819   m_meshRadiusB = 0.0;
00820   m_meshCenter.setValue(tfScalar(0), tfScalar(0), tfScalar(0));
00821 
00822   double xdim = maxX - minX;
00823   double ydim = maxY - minY;
00824   double zdim = maxZ - minZ;
00825     
00826   double pose1;
00827   double pose2;
00828     
00829   unsigned int off1;
00830   unsigned int off2;
00831     
00832   double cyl_length;
00833   double maxdist = -INFINITY;
00834     
00835   if(xdim > ydim && xdim > zdim) {
00836       
00837     off1 = 1;
00838     off2 = 2;
00839     pose1 = m_boxOffset.y();
00840     pose2 = m_boxOffset.z();
00841     cyl_length = xdim;
00842   } else if(ydim > zdim) {
00843     off1 = 0;
00844     off2 = 2;
00845     pose1 = m_boxOffset.x();
00846     pose2 = m_boxOffset.z();
00847     cyl_length = ydim;
00848   } else {
00849     off1 = 0;
00850     off2 = 1;
00851     pose1 = m_boxOffset.x();
00852     pose2 = m_boxOffset.y();
00853     cyl_length = zdim;
00854   }
00855 
00856 
00857   /* compute convex hull */
00858   coordT *points = (coordT *)calloc(mesh->vertexCount*3, sizeof(coordT));
00859   for(unsigned int i = 0; i < mesh->vertexCount ; ++i)
00860   {
00861     points[3*i+0] = (coordT) mesh->vertices[3*i+0];
00862     points[3*i+1] = (coordT) mesh->vertices[3*i+1];
00863     points[3*i+2] = (coordT) mesh->vertices[3*i+2];
00864 
00865     double dista = mesh->vertices[3 * i + off1]-pose1;
00866     double distb = mesh->vertices[3 * i + off2]-pose2;
00867     double dist = sqrt(((dista*dista)+(distb*distb)));
00868     if(dist > maxdist)
00869       maxdist = dist;
00870   }
00871 
00872   m_boundingCylinder.radius = maxdist;
00873   m_boundingCylinder.length = cyl_length;
00874 
00875   FILE* null = fopen ("/dev/null","w");
00876 
00877   char flags[] = "qhull Tv";
00878   int exitcode = qh_new_qhull(3, mesh->vertexCount, points, true, flags, null, null);
00879 
00880   if (exitcode != 0)
00881   {
00882       ROS_WARN("Convex hull creation failed");
00883     qh_freeqhull (!qh_ALL);
00884     int curlong, totlong;
00885     qh_memfreeshort (&curlong, &totlong);
00886     return;
00887   }
00888 
00889   int num_facets = qh num_facets;
00890 
00891   int num_vertices = qh num_vertices;
00892   m_vertices.reserve(num_vertices);
00893   tf::Vector3 sum(0, 0, 0);
00894 
00895   //necessary for FORALLvertices
00896   std::map<unsigned int, unsigned int> qhull_vertex_table;
00897   vertexT * vertex;
00898   FORALLvertices
00899   {
00900     tf::Vector3 vert(vertex->point[0],
00901                          vertex->point[1],
00902                          vertex->point[2]);
00903     qhull_vertex_table[vertex->id] = m_vertices.size();
00904     sum = sum + vert;
00905     m_vertices.push_back(vert);
00906   }
00907 
00908   m_meshCenter = sum / (double)(num_vertices);
00909   for (unsigned int j = 0 ; j < m_vertices.size() ; ++j)
00910   {
00911       double dist = m_vertices[j].distance2(m_meshCenter);
00912     if (dist > m_radiusB)
00913       m_radiusB = dist;
00914   }
00915 
00916   m_radiusB = sqrt(m_radiusB);
00917   m_triangles.reserve(num_facets);
00918 
00919   //neccessary for qhull macro
00920   facetT * facet;
00921   FORALLfacets
00922   {
00923     tf::tfVector4 planeEquation(facet->normal[0], facet->normal[1], facet->normal[2], facet->offset);
00924     m_planes.push_back(planeEquation);
00925 
00926     // Needed by FOREACHvertex_i_
00927     int vertex_n, vertex_i;
00928     FOREACHvertex_i_ ((*facet).vertices)
00929     {
00930       m_triangles.push_back(qhull_vertex_table[vertex->id]);
00931     }
00932 
00933   }
00934   qh_freeqhull(!qh_ALL);
00935   int curlong, totlong;
00936   qh_memfreeshort (&curlong, &totlong);
00937 
00938 
00939 
00940 
00941   
00942   /*  
00943   HullDesc hd(QF_TRIANGLES, mesh->vertexCount, vertices);
00944   HullResult hr;
00945   HullLibrary hl;
00946   if (hl.CreateConvexHull(hd, hr) == QE_OK)
00947   {
00948     //  std::cout << "Convex hull has " << hr.m_OutputVertices.size() << " vertices (down from " << mesh->vertexCount << "), " << hr.mNumFaces << " faces" << std::endl;
00949 
00950     m_vertices.reserve(hr.m_OutputVertices.size());
00951     tf::Vector3 sum(0, 0, 0);   
00952         
00953     for (int j = 0 ; j < hr.m_OutputVertices.size() ; ++j)
00954     {
00955       tf::Vector3 tfv(hr.m_OutputVertices[j][0],hr.m_OutputVertices[j][1],hr.m_OutputVertices[j][2]);
00956       m_vertices.push_back(tfv);
00957       sum = sum + tfv;
00958     }
00959         
00960     m_meshCenter = sum / (double)(hr.m_OutputVertices.size());
00961     for (unsigned int j = 0 ; j < m_vertices.size() ; ++j)
00962     {
00963       double dist = m_vertices[j].distance2(m_meshCenter);
00964       if (dist > m_meshRadiusB)
00965         m_meshRadiusB = dist;
00966     }
00967 
00968     m_meshRadiusB = sqrt(m_meshRadiusB);
00969     m_triangles.reserve(hr.m_Indices.size());
00970     for (unsigned int j = 0 ; j < hr.mNumFaces ; ++j)
00971     {
00972       tf::Vector3 p1(hr.m_OutputVertices[hr.m_Indices[j * 3    ]][0],hr.m_OutputVertices[hr.m_Indices[j * 3    ]][1],hr.m_OutputVertices[hr.m_Indices[j * 3    ]][2]);
00973       tf::Vector3 p2(hr.m_OutputVertices[hr.m_Indices[j * 3 + 1]][0],hr.m_OutputVertices[hr.m_Indices[j * 3 + 1]][1],hr.m_OutputVertices[hr.m_Indices[j * 3 + 1]][2]);
00974       tf::Vector3 p3(hr.m_OutputVertices[hr.m_Indices[j * 3 + 2]][0],hr.m_OutputVertices[hr.m_Indices[j * 3 + 2]][1],hr.m_OutputVertices[hr.m_Indices[j * 3 + 2]][2]);
00975             
00976       tf::Vector3 edge1 = (p2 - p1);
00977       tf::Vector3 edge2 = (p3 - p1);
00978             
00979       edge1.normalize();
00980       edge2.normalize();
00981 
00982       tf::Vector3 planeNormal = edge1.cross(edge2);
00983             
00984       if (planeNormal.length2() > tfScalar(1e-6))
00985       {
00986         planeNormal.normalize();
00987         tf::tfVector4 planeEquation(planeNormal.getX(), planeNormal.getY(), planeNormal.getZ(), -planeNormal.dot(p1));
00988 
00989         unsigned int behindPlane = countVerticesBehindPlane(planeEquation);
00990         if (behindPlane > 0)
00991         {
00992           tf::tfVector4 planeEquation2(-planeEquation.getX(), -planeEquation.getY(), -planeEquation.getZ(), -planeEquation.getW());
00993           unsigned int behindPlane2 = countVerticesBehindPlane(planeEquation2);
00994           if (behindPlane2 < behindPlane)
00995           {
00996             planeEquation.setValue(planeEquation2.getX(), planeEquation2.getY(), planeEquation2.getZ(), planeEquation2.getW());
00997             behindPlane = behindPlane2;
00998           }
00999         }
01000                 
01001         if (behindPlane > 0)
01002           ROS_DEBUG("Approximate plane: %d of %d points are behind the plane", behindPlane, (int)m_vertices.size());
01003                 
01004         m_planes.push_back(planeEquation);
01005 
01006         m_triangles.push_back(hr.m_Indices[j * 3 + 0]);
01007         m_triangles.push_back(hr.m_Indices[j * 3 + 1]);
01008         m_triangles.push_back(hr.m_Indices[j * 3 + 2]);
01009       }
01010     }
01011   }
01012   else
01013   */
01014 
01015     
01016   //  hl.ReleaseResult(hr);    
01017     //  delete[] vertices;
01018     
01019 }
01020 
01021 void bodies::ConvexMesh::updateInternalData(void) 
01022 {
01023   tf::Transform pose = m_pose;
01024   pose.setOrigin(m_pose * m_boxOffset);
01025   m_boundingBox.setPose(pose);
01026   m_boundingBox.setPadding(m_padding);
01027   m_boundingBox.setScale(m_scale);
01028 
01029   m_iPose = m_pose.inverse();
01030   m_center = m_pose * m_meshCenter;
01031   m_radiusB = m_meshRadiusB * m_scale + m_padding;
01032   m_radiusBSqr = m_radiusB * m_radiusB;
01033 
01034   m_scaledVertices.resize(m_vertices.size());
01035   for (unsigned int i = 0 ; i < m_vertices.size() ; ++i)
01036   {
01037     tf::Vector3 v(m_vertices[i] - m_meshCenter);
01038     tfScalar l = v.length();
01039     m_scaledVertices[i] = m_meshCenter + v * (m_scale + (l > ZERO ? m_padding / l : 0.0));
01040   }
01041 }
01042 
01043 void bodies::ConvexMesh::computeBoundingSphere(BoundingSphere &sphere) const
01044 {
01045   sphere.center = m_center;
01046   sphere.radius = m_radiusB;
01047 }
01048 
01049 void bodies::ConvexMesh::computeBoundingCylinder(BoundingCylinder &cylinder) const
01050 {
01051   cylinder.length = m_boundingCylinder.length;
01052   cylinder.radius = m_boundingCylinder.radius;
01053   //need to do rotation correctly to get pose, which bounding box does
01054   BoundingCylinder cyl;
01055   m_boundingBox.computeBoundingCylinder(cyl);
01056   cylinder.pose = cyl.pose;
01057 }
01058 
01059 bool bodies::ConvexMesh::isPointInsidePlanes(const tf::Vector3& point) const
01060 {
01061   unsigned int numplanes = m_planes.size();
01062   for (unsigned int i = 0 ; i < numplanes ; ++i)
01063   {
01064     const tf::tfVector4& plane = m_planes[i];
01065     tfScalar dist = plane.dot(point) + plane.getW() - m_padding - tfScalar(1e-6);
01066     if (dist > tfScalar(0))
01067       return false;
01068   }
01069   return true;
01070 }
01071 
01072 unsigned int bodies::ConvexMesh::countVerticesBehindPlane(const tf::tfVector4& planeNormal) const
01073 {
01074   unsigned int numvertices = m_vertices.size();
01075   unsigned int result = 0;
01076   for (unsigned int i = 0 ; i < numvertices ; ++i)
01077   {
01078     tfScalar dist = planeNormal.dot(m_vertices[i]) + planeNormal.getW() - tfScalar(1e-6);
01079     if (dist > tfScalar(0))
01080       result++;
01081   }
01082   return result;
01083 }
01084 
01085 double bodies::ConvexMesh::computeVolume(void) const
01086 {
01087   double volume = 0.0;
01088   for (unsigned int i = 0 ; i < m_triangles.size() / 3 ; ++i)
01089   {
01090     const tf::Vector3 &v1 = m_vertices[m_triangles[3*i + 0]];
01091     const tf::Vector3 &v2 = m_vertices[m_triangles[3*i + 1]];
01092     const tf::Vector3 &v3 = m_vertices[m_triangles[3*i + 2]];
01093     volume += v1.x()*v2.y()*v3.z() + v2.x()*v3.y()*v1.z() + v3.x()*v1.y()*v2.z() - v1.x()*v3.y()*v2.z() - v2.x()*v1.y()*v3.z() - v3.x()*v2.y()*v1.z();
01094   }
01095   return fabs(volume)/6.0;
01096 }
01097 
01098 bool bodies::ConvexMesh::intersectsRay(const tf::Vector3& origin, const tf::Vector3& dir, std::vector<tf::Vector3> *intersections, unsigned int count) const
01099 {
01100   if (distanceSQR(m_center, origin, dir) > m_radiusBSqr) return false;
01101   if (!m_boundingBox.intersectsRay(origin, dir)) return false;
01102     
01103   // transform the ray into the coordinate frame of the mesh
01104   tf::Vector3 orig(m_iPose * origin);
01105   tf::Vector3 dr(m_iPose.getBasis() * dir);
01106     
01107   std::vector<detail::intersc> ipts;
01108     
01109   bool result = false;
01110     
01111   // for each triangle 
01112   const unsigned int nt = m_triangles.size() / 3;
01113   for (unsigned int i = 0 ; i < nt ; ++i)
01114   {
01115     tfScalar tmp = m_planes[i].dot(dr);
01116     if (fabs(tmp) > ZERO)
01117     {
01118       double t = -(m_planes[i].dot(orig) + m_planes[i].getW()) / tmp;
01119       if (t > 0.0)
01120       {
01121         const int i3 = 3 * i;
01122         const int v1 = m_triangles[i3 + 0];
01123         const int v2 = m_triangles[i3 + 1];
01124         const int v3 = m_triangles[i3 + 2];
01125                 
01126         const tf::Vector3 &a = m_scaledVertices[v1];
01127         const tf::Vector3 &b = m_scaledVertices[v2];
01128         const tf::Vector3 &c = m_scaledVertices[v3];
01129                 
01130         tf::Vector3 cb(c - b);
01131         tf::Vector3 ab(a - b);
01132                 
01133         // intersection of the plane defined by the triangle and the ray
01134         tf::Vector3 P(orig + dr * t);
01135                 
01136         // check if it is inside the triangle
01137         tf::Vector3 pb(P - b);
01138         tf::Vector3 c1(cb.cross(pb));
01139         tf::Vector3 c2(cb.cross(ab));
01140         if (c1.dot(c2) < 0.0)
01141           continue;
01142                 
01143         tf::Vector3 ca(c - a);
01144         tf::Vector3 pa(P - a);
01145         tf::Vector3 ba(-ab);
01146                 
01147         c1 = ca.cross(pa);
01148         c2 = ca.cross(ba);
01149         if (c1.dot(c2) < 0.0)
01150           continue;
01151                 
01152         c1 = ba.cross(pa);
01153         c2 = ba.cross(ca);
01154                 
01155         if (c1.dot(c2) < 0.0)
01156           continue;
01157                 
01158         result = true;
01159         if (intersections)
01160         {
01161           detail::intersc ip(origin + dir * t, t);
01162           ipts.push_back(ip);
01163         }
01164         else
01165           break;
01166       }
01167     }
01168   }
01169 
01170   if (intersections)
01171   {
01172     std::sort(ipts.begin(), ipts.end(), detail::interscOrder());
01173     const unsigned int n = count > 0 ? std::min<unsigned int>(count, ipts.size()) : ipts.size();
01174     for (unsigned int i = 0 ; i < n ; ++i)
01175       intersections->push_back(ipts[i].pt);
01176   }
01177     
01178   return result;
01179 }
01180 
01181 bodies::BodyVector::BodyVector(){
01182 }
01183 
01184 bodies::BodyVector::BodyVector(const std::vector<shapes::Shape*>& shapes, 
01185                                const std::vector<tf::Transform>& poses,
01186                                double padding)
01187 {
01188   padding_ = padding;
01189   for(unsigned int i = 0; i < shapes.size(); i++) {
01190     addBody(shapes[i],poses[i], padding_);
01191   }
01192 }
01193 
01194 
01195 bodies::BodyVector::~BodyVector() {
01196   for(unsigned int i = 0; i < bodies_.size(); i++) {
01197     delete bodies_[i];
01198   }
01199   for(unsigned int i = 0; i < padded_bodies_.size(); i++) {
01200     delete padded_bodies_[i];
01201   }
01202 }
01203 
01204 void bodies::BodyVector::addBody(const shapes::Shape* shape, const tf::Transform& pose, double padding) {
01205   bodies::Body* body = bodies::createBodyFromShape(shape);
01206   body->setPose(pose);
01207   bodies_.push_back(body);
01208   BoundingSphere sphere;
01209   body->computeBoundingSphere(sphere);
01210   rsqrs_.push_back(sphere.radius*sphere.radius);
01211   if(padding > 0.0) {
01212     bodies::Body* padded_body = bodies::createBodyFromShape(shape);
01213     padded_body->setPose(pose);
01214     padded_body->setPadding(padding);
01215     padded_bodies_.push_back(padded_body);
01216     BoundingSphere padded_sphere;
01217     padded_body->computeBoundingSphere(padded_sphere);
01218     padded_rsqrs_.push_back(padded_sphere.radius*padded_sphere.radius);
01219   }
01220 }
01221 
01222 void bodies::BodyVector::setPose(unsigned int i, const tf::Transform& pose)
01223 {
01224   if(i >= bodies_.size()) return;
01225   bodies_[i]->setPose(pose);
01226   if(padding_ > 0.0) {
01227     padded_bodies_[i]->setPose(pose);
01228   }
01229 }
01230 
01231 const bodies::Body* bodies::BodyVector::getBody(unsigned int i) const
01232 {
01233   if(i >= bodies_.size()) return NULL;
01234   return bodies_[i];
01235 }
01236 
01237 const bodies::Body* bodies::BodyVector::getPaddedBody(unsigned int i) const
01238 {
01239   if(i >= bodies_.size()) return NULL;
01240   if(padding_ > 0.0) {
01241     return padded_bodies_[i];
01242   } 
01243   return bodies_[i];
01244 }
01245 
01246 
01247 bodies::BoundingSphere bodies::BodyVector::getBoundingSphere(unsigned int i) const
01248 {
01249   if(i >= bodies_.size()) {
01250     ROS_WARN("Trying to get sphere for body we don't have.  Probably segfault");
01251   }
01252   BoundingSphere sphere;
01253   bodies_[i]->computeBoundingSphere(sphere);
01254   return sphere;
01255 }
01256 
01257 bodies::BoundingSphere bodies::BodyVector::getPaddedBoundingSphere(unsigned int i) const
01258 {
01259   if(i >= bodies_.size()) {
01260     ROS_WARN("Trying to get sphere for body we don't have.  Probably segfault");
01261   }
01262   BoundingSphere sphere;
01263   if(padding_ > 0.0) {
01264     padded_bodies_[i]->computeBoundingSphere(sphere);
01265   } else {
01266     bodies_[i]->computeBoundingSphere(sphere);
01267   }
01268   return sphere;
01269 }
01270 
01271 double bodies::BodyVector::getBoundingSphereRadiusSquared(unsigned int i) const
01272 {
01273   if(i >= rsqrs_.size()) {
01274     return -1.0;
01275   }
01276   return rsqrs_[i];
01277 }
01278 
01279 double bodies::BodyVector::getPaddedBoundingSphereRadiusSquared(unsigned int i) const
01280 {
01281   if(i >= rsqrs_.size()) {
01282     return -1.0;
01283   }
01284   if(padding_ > 0.0) {
01285     return padded_rsqrs_[i];
01286   } 
01287   return rsqrs_[i];
01288 }


geometric_shapes
Author(s): Ioan Sucan
autogenerated on Thu Dec 12 2013 11:08:55