00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
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
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
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)
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)
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
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
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
00423
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)
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
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
00589
00590
00591
00592
00593
00594
00595
00596
00597
00598
00599
00600
00601
00602
00603
00604
00605
00606
00607
00608
00609
00610
00611
00612
00613
00614
00615
00616
00618
00619
00620
00621
00622
00623
00624
00625
00626
00627
00628
00629
00630
00631
00632
00633
00634
00635
00636
00637
00638
00639
00640
00641
00642
00643
00644
00645
00646
00647
00648
00649
00650
00651
00652
00653
00654
00655
00656
00657
00658
00659
00660
00661
00662
00663
00664
00665
00666
00667
00668
00669
00670
00671
00672
00673
00674
00675
00676
00677
00678
00679
00680
00681
00682
00683
00684
00685
00686
00687
00688
00689
00690
00691
00692
00693
00694
00695
00696
00697
00698
00699
00700
00701
00702
00703
00704
00705
00706
00707
00708
00709
00710
00711
00712
00713
00714
00715
00716
00717
00718
00719
00720
00721
00722
00723
00724
00725
00726
00727
00728
00729
00730
00731
00732
00733
00734
00735
00736
00737
00738
00739
00740
00741
00742
00743
00744
00745
00746
00747
00748
00750
00751
00752
00753
00754
00755
00756
00757
00758
00759
00760
00761
00762
00763
00764
00765
00766
00767
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
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
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
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
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
00944
00945
00946
00947
00948
00949
00950
00951
00952
00953
00954
00955
00956
00957
00958
00959
00960
00961
00962
00963
00964
00965
00966
00967
00968
00969
00970
00971
00972
00973
00974
00975
00976
00977
00978
00979
00980
00981
00982
00983
00984
00985
00986
00987
00988
00989
00990
00991
00992
00993
00994
00995
00996
00997
00998
00999
01000
01001
01002
01003
01004
01005
01006
01007
01008
01009
01010
01011
01012
01013
01014
01015
01016
01017
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
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
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
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
01134 tf::Vector3 P(orig + dr * t);
01135
01136
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 }