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 
00035 
00036 
00037 #include "geometric_shapes/shape_operations.h"
00038 
00039 #include <cstdio>
00040 #include <cmath>
00041 #include <algorithm>
00042 #include <set>
00043 #include <float.h>
00044 
00045 #include <console_bridge/console.h>
00046 
00047 #include <Eigen/Geometry>
00048 
00049 #include <shape_tools/shape_to_marker.h>
00050 #include <shape_tools/shape_extents.h>
00051 #include <shape_tools/solid_primitive_dims.h>
00052 
00053 namespace shapes
00054 {
00055 
00056 Shape* constructShapeFromMsg(const shape_msgs::Plane &shape_msg)
00057 {
00058   return new Plane(shape_msg.coef[0], shape_msg.coef[1], shape_msg.coef[2], shape_msg.coef[3]);
00059 }
00060 
00061 Shape* constructShapeFromMsg(const shape_msgs::Mesh &shape_msg)
00062 {
00063   if (shape_msg.triangles.empty() || shape_msg.vertices.empty())
00064   {
00065     logWarn("Mesh definition is empty");
00066     return NULL;
00067   }
00068   else
00069   {
00070     EigenSTL::vector_Vector3d vertices(shape_msg.vertices.size());
00071     std::vector<unsigned int> triangles(shape_msg.triangles.size() * 3);
00072     for (unsigned int i = 0 ; i < shape_msg.vertices.size() ; ++i)
00073       vertices[i] = Eigen::Vector3d(shape_msg.vertices[i].x, shape_msg.vertices[i].y, shape_msg.vertices[i].z);
00074     for (unsigned int i = 0 ; i < shape_msg.triangles.size() ; ++i)
00075     {
00076       unsigned int i3 = i * 3;
00077       triangles[i3++] = shape_msg.triangles[i].vertex_indices[0];
00078       triangles[i3++] = shape_msg.triangles[i].vertex_indices[1];
00079       triangles[i3] = shape_msg.triangles[i].vertex_indices[2];
00080     }
00081     return createMeshFromVertices(vertices, triangles);
00082   }
00083 }
00084 
00085 Shape* constructShapeFromMsg(const shape_msgs::SolidPrimitive &shape_msg)
00086 {
00087   Shape *shape = NULL;
00088   if (shape_msg.type == shape_msgs::SolidPrimitive::SPHERE)
00089   {
00090     if (shape_msg.dimensions.size() > shape_msgs::SolidPrimitive::SPHERE_RADIUS)
00091       shape = new Sphere(shape_msg.dimensions[shape_msgs::SolidPrimitive::SPHERE_RADIUS]);
00092   }
00093   else
00094     if (shape_msg.type == shape_msgs::SolidPrimitive::BOX)
00095     {
00096       if (shape_msg.dimensions.size() > shape_msgs::SolidPrimitive::BOX_X &&
00097           shape_msg.dimensions.size() > shape_msgs::SolidPrimitive::BOX_Y &&
00098           shape_msg.dimensions.size() > shape_msgs::SolidPrimitive::BOX_Z)
00099         shape = new Box(shape_msg.dimensions[shape_msgs::SolidPrimitive::BOX_X],
00100                         shape_msg.dimensions[shape_msgs::SolidPrimitive::BOX_Y],
00101                         shape_msg.dimensions[shape_msgs::SolidPrimitive::BOX_Z]);
00102     }
00103     else
00104       if (shape_msg.type == shape_msgs::SolidPrimitive::CYLINDER)
00105       {
00106         if (shape_msg.dimensions.size() > shape_msgs::SolidPrimitive::CYLINDER_RADIUS &&
00107             shape_msg.dimensions.size() > shape_msgs::SolidPrimitive::CYLINDER_HEIGHT)
00108           shape = new Cylinder(shape_msg.dimensions[shape_msgs::SolidPrimitive::CYLINDER_RADIUS],
00109                                shape_msg.dimensions[shape_msgs::SolidPrimitive::CYLINDER_HEIGHT]);
00110       }
00111       else
00112         if (shape_msg.type == shape_msgs::SolidPrimitive::CONE)
00113         {
00114           if (shape_msg.dimensions.size() > shape_msgs::SolidPrimitive::CONE_RADIUS &&
00115               shape_msg.dimensions.size() > shape_msgs::SolidPrimitive::CONE_HEIGHT)
00116             shape = new Cone(shape_msg.dimensions[shape_msgs::SolidPrimitive::CONE_RADIUS],
00117                              shape_msg.dimensions[shape_msgs::SolidPrimitive::CONE_HEIGHT]);
00118         }
00119   if (shape == NULL)
00120     logError("Unable to construct shape corresponding to shape_msgect of type %d", (int)shape_msg.type);
00121 
00122   return shape;
00123 }
00124 
00125 namespace
00126 {
00127 
00128 class ShapeVisitorAlloc : public boost::static_visitor<Shape*>
00129 {
00130 public:
00131 
00132   Shape* operator()(const shape_msgs::Plane &shape_msg) const
00133   {
00134     return constructShapeFromMsg(shape_msg);
00135   }
00136 
00137   Shape* operator()(const shape_msgs::Mesh &shape_msg) const
00138   {
00139     return constructShapeFromMsg(shape_msg);
00140   }
00141 
00142   Shape* operator()(const shape_msgs::SolidPrimitive &shape_msg) const
00143   {
00144     return constructShapeFromMsg(shape_msg);
00145   }
00146 };
00147 
00148 }
00149 
00150 Shape* constructShapeFromMsg(const ShapeMsg &shape_msg)
00151 {
00152   return boost::apply_visitor(ShapeVisitorAlloc(), shape_msg);
00153 }
00154 
00155 namespace
00156 {
00157 
00158 class ShapeVisitorMarker : public boost::static_visitor<void>
00159 {
00160 public:
00161 
00162   ShapeVisitorMarker(visualization_msgs::Marker *marker, bool use_mesh_triangle_list) :
00163     boost::static_visitor<void>(),
00164     use_mesh_triangle_list_(use_mesh_triangle_list),
00165     marker_(marker)
00166   {
00167   }
00168 
00169   void operator()(const shape_msgs::Plane &shape_msg) const
00170   {
00171     throw std::runtime_error("No visual markers can be constructed for planes");
00172   }
00173 
00174   void operator()(const shape_msgs::Mesh &shape_msg) const
00175   {
00176     shape_tools::constructMarkerFromShape(shape_msg, *marker_, use_mesh_triangle_list_);
00177   }
00178 
00179   void operator()(const shape_msgs::SolidPrimitive &shape_msg) const
00180   {
00181     shape_tools::constructMarkerFromShape(shape_msg, *marker_);
00182   }
00183 
00184 private:
00185 
00186   bool use_mesh_triangle_list_;
00187   visualization_msgs::Marker *marker_;
00188 };
00189 
00190 }
00191 
00192 bool constructMarkerFromShape(const Shape* shape, visualization_msgs::Marker &marker, bool use_mesh_triangle_list)
00193 {
00194   ShapeMsg shape_msg;
00195   if (constructMsgFromShape(shape, shape_msg))
00196   {
00197     bool ok = false;
00198     try
00199     {
00200       boost::apply_visitor(ShapeVisitorMarker(&marker, use_mesh_triangle_list), shape_msg);
00201       ok = true;
00202     }
00203     catch (std::runtime_error &ex)
00204     {
00205       logError("%s", ex.what());
00206     }
00207     if (ok)
00208       return true;
00209   }
00210   return false;
00211 }
00212 
00213 namespace
00214 {
00215 
00216 class ShapeVisitorComputeExtents : public boost::static_visitor<Eigen::Vector3d>
00217 {
00218 public:
00219 
00220   Eigen::Vector3d operator()(const shape_msgs::Plane &shape_msg) const
00221   {
00222     Eigen::Vector3d e(0.0, 0.0, 0.0);
00223     return e;
00224   }
00225 
00226   Eigen::Vector3d operator()(const shape_msgs::Mesh &shape_msg) const
00227   {
00228     double x_extent, y_extent, z_extent;
00229     shape_tools::getShapeExtents(shape_msg, x_extent, y_extent, z_extent);
00230     Eigen::Vector3d e(x_extent, y_extent, z_extent);
00231     return e;
00232   }
00233 
00234   Eigen::Vector3d operator()(const shape_msgs::SolidPrimitive &shape_msg) const
00235   {
00236     double x_extent, y_extent, z_extent;
00237     shape_tools::getShapeExtents(shape_msg, x_extent, y_extent, z_extent);
00238     Eigen::Vector3d e(x_extent, y_extent, z_extent);
00239     return e;
00240   }
00241 };
00242 
00243 }
00244 
00245 Eigen::Vector3d computeShapeExtents(const ShapeMsg &shape_msg)
00246 {
00247   return boost::apply_visitor(ShapeVisitorComputeExtents(), shape_msg);
00248 }
00249 
00250 Eigen::Vector3d computeShapeExtents(const Shape *shape)
00251 {
00252   if (shape->type == SPHERE)
00253   {
00254     double d = static_cast<const Sphere*>(shape)->radius * 2.0;
00255     return Eigen::Vector3d(d, d, d);
00256   }
00257   else
00258     if (shape->type == BOX)
00259     {
00260       const double* sz = static_cast<const Box*>(shape)->size;
00261       return Eigen::Vector3d(sz[0], sz[1], sz[2]);
00262     }
00263     else
00264       if (shape->type == CYLINDER)
00265       {
00266         double d = static_cast<const Cylinder*>(shape)->radius * 2.0;
00267         return Eigen::Vector3d(d, d, static_cast<const Cylinder*>(shape)->length);
00268       }
00269       else
00270         if (shape->type == CONE)
00271         {
00272           double d = static_cast<const Cone*>(shape)->radius * 2.0;
00273           return Eigen::Vector3d(d, d, static_cast<const Cone*>(shape)->length);
00274         }
00275         else
00276           if (shape->type == MESH)
00277           {
00278             const Mesh *mesh = static_cast<const Mesh*>(shape);
00279             if (mesh->vertex_count > 1)
00280             {
00281               std::vector<double> vmin(3, std::numeric_limits<double>::max());
00282               std::vector<double> vmax(3, -std::numeric_limits<double>::max());
00283               for (unsigned int i = 0; i < mesh->vertex_count ; ++i)
00284               {
00285                 unsigned int i3 = i * 3;
00286                 for (unsigned int k = 0 ; k < 3 ; ++k)
00287                 {
00288                   unsigned int i3k = i3 + k;
00289                   if (mesh->vertices[i3k] > vmax[k])
00290                     vmax[k] = mesh->vertices[i3k];
00291                   if (mesh->vertices[i3k] < vmin[k])
00292                     vmin[k] = mesh->vertices[i3k];
00293                 }
00294               }
00295               return Eigen::Vector3d(vmax[0] - vmin[0], vmax[1] - vmin[1], vmax[2] - vmin[2]);
00296             }
00297             else
00298               return Eigen::Vector3d(0.0, 0.0, 0.0);
00299           }
00300           else
00301             return Eigen::Vector3d(0.0, 0.0, 0.0);
00302 }
00303 
00304 void computeShapeBoundingSphere(const Shape *shape, Eigen::Vector3d& center, double& radius)
00305 {
00306   center.x() = 0.0;
00307   center.y() = 0.0;
00308   center.z() = 0.0;
00309   radius = 0.0;
00310 
00311   if (shape->type == SPHERE)
00312   {
00313     radius = static_cast<const Sphere*>(shape)->radius;
00314   }
00315   else if (shape->type == BOX)
00316   {
00317     const double* sz = static_cast<const Box*>(shape)->size;
00318     double half_width = sz[0] * 0.5;
00319     double half_height = sz[1] * 0.5;
00320     double half_depth = sz[2] * 0.5;
00321     radius = std::sqrt( half_width * half_width +
00322                         half_height * half_height +
00323                         half_depth * half_depth);
00324   }
00325   else if (shape->type == CYLINDER)
00326   {
00327     double cyl_radius = static_cast<const Cylinder*>(shape)->radius;
00328     double half_len = static_cast<const Cylinder*>(shape)->length * 0.5;
00329     radius = std::sqrt( cyl_radius * cyl_radius +
00330                         half_len * half_len);
00331   }
00332   else if (shape->type == CONE)
00333   {
00334     double cone_radius = static_cast<const Cone*>(shape)->radius;
00335     double cone_height = static_cast<const Cone*>(shape)->length;
00336 
00337     if (cone_height > cone_radius)
00338     {
00339       
00340       double z = (cone_height - (cone_radius * cone_radius / cone_height)) * 0.5;
00341       center.z() = z - (cone_height * 0.5);
00342       radius = cone_height - z;
00343     }
00344     else
00345     {
00346       
00347       center.z() = - (cone_height * 0.5);
00348       radius = cone_radius;
00349     }
00350   }
00351   else if (shape->type == MESH)
00352   {
00353     const Mesh *mesh = static_cast<const Mesh*>(shape);
00354     if (mesh->vertex_count > 1)
00355     {
00356       double mx = std::numeric_limits<double>::max();
00357       Eigen::Vector3d min( mx,  mx,  mx);
00358       Eigen::Vector3d max(-mx, -mx, -mx);
00359       unsigned int cnt = mesh->vertex_count * 3;
00360       for (unsigned int i = 0; i < cnt ; i+=3)
00361       {
00362         Eigen::Vector3d v(mesh->vertices[i+0], mesh->vertices[i+1], mesh->vertices[i+2]);
00363         min = min.cwiseMin(v);
00364         max = max.cwiseMax(v);
00365       }
00366 
00367       center = (min + max) * 0.5;
00368       radius = (max - min).norm() * 0.5;
00369     }
00370   }
00371 }
00372 
00373 
00374 bool constructMsgFromShape(const Shape* shape, ShapeMsg &shape_msg)
00375 {
00376   if (shape->type == SPHERE)
00377   {
00378     shape_msgs::SolidPrimitive s;
00379     s.type = shape_msgs::SolidPrimitive::SPHERE;
00380     s.dimensions.resize(shape_tools::SolidPrimitiveDimCount<shape_msgs::SolidPrimitive::SPHERE>::value);
00381     s.dimensions[shape_msgs::SolidPrimitive::SPHERE_RADIUS] = static_cast<const Sphere*>(shape)->radius;
00382     shape_msg = s;
00383   }
00384   else
00385     if (shape->type == BOX)
00386     {
00387       shape_msgs::SolidPrimitive s;
00388       s.type = shape_msgs::SolidPrimitive::BOX;
00389       const double* sz = static_cast<const Box*>(shape)->size;
00390       s.dimensions.resize(shape_tools::SolidPrimitiveDimCount<shape_msgs::SolidPrimitive::BOX>::value);
00391       s.dimensions[shape_msgs::SolidPrimitive::BOX_X] = sz[0];
00392       s.dimensions[shape_msgs::SolidPrimitive::BOX_Y] = sz[1];
00393       s.dimensions[shape_msgs::SolidPrimitive::BOX_Z] = sz[2];
00394       shape_msg = s;
00395     }
00396     else
00397       if (shape->type == CYLINDER)
00398       {
00399         shape_msgs::SolidPrimitive s;
00400         s.type = shape_msgs::SolidPrimitive::CYLINDER;
00401         s.dimensions.resize(shape_tools::SolidPrimitiveDimCount<shape_msgs::SolidPrimitive::CYLINDER>::value);
00402         s.dimensions[shape_msgs::SolidPrimitive::CYLINDER_RADIUS] = static_cast<const Cylinder*>(shape)->radius;
00403         s.dimensions[shape_msgs::SolidPrimitive::CYLINDER_HEIGHT] = static_cast<const Cylinder*>(shape)->length;
00404         shape_msg = s;
00405       }
00406       else
00407         if (shape->type == CONE)
00408         {
00409           shape_msgs::SolidPrimitive s;
00410           s.type = shape_msgs::SolidPrimitive::CONE;
00411           s.dimensions.resize(shape_tools::SolidPrimitiveDimCount<shape_msgs::SolidPrimitive::CONE>::value);
00412           s.dimensions[shape_msgs::SolidPrimitive::CONE_RADIUS] = static_cast<const Cone*>(shape)->radius;
00413           s.dimensions[shape_msgs::SolidPrimitive::CONE_HEIGHT] = static_cast<const Cone*>(shape)->length;
00414           shape_msg = s;
00415         }
00416         else
00417           if (shape->type == PLANE)
00418           {
00419             shape_msgs::Plane s;
00420             const Plane *p = static_cast<const Plane*>(shape);
00421             s.coef[0] = p->a;
00422             s.coef[1] = p->b;
00423             s.coef[2] = p->c;
00424             s.coef[3] = p->d;
00425             shape_msg = s;
00426           }
00427           else
00428             if (shape->type == MESH)
00429             {
00430               shape_msgs::Mesh s;
00431               const Mesh *mesh = static_cast<const Mesh*>(shape);
00432               s.vertices.resize(mesh->vertex_count);
00433               s.triangles.resize(mesh->triangle_count);
00434 
00435               for (unsigned int i = 0 ; i < mesh->vertex_count ; ++i)
00436               {
00437                 unsigned int i3 = i * 3;
00438                 s.vertices[i].x = mesh->vertices[i3];
00439                 s.vertices[i].y = mesh->vertices[i3 + 1];
00440                 s.vertices[i].z = mesh->vertices[i3 + 2];
00441               }
00442 
00443               for (unsigned int i = 0 ; i < s.triangles.size() ; ++i)
00444               {
00445                 unsigned int i3 = i * 3;
00446                 s.triangles[i].vertex_indices[0] = mesh->triangles[i3];
00447                 s.triangles[i].vertex_indices[1] = mesh->triangles[i3 + 1];
00448                 s.triangles[i].vertex_indices[2] = mesh->triangles[i3 + 2];
00449               }
00450               shape_msg = s;
00451             }
00452             else
00453             {
00454               logError("Unable to construct shape message for shape of type %d", (int)shape->type);
00455               return false;
00456             }
00457 
00458   return true;
00459 }
00460 
00461 void saveAsText(const Shape *shape, std::ostream &out)
00462 {
00463   if (shape->type == SPHERE)
00464   {
00465     out << Sphere::STRING_NAME << std::endl;
00466     out << static_cast<const Sphere*>(shape)->radius << std::endl;
00467   }
00468   else
00469     if (shape->type == BOX)
00470     {
00471       out << Box::STRING_NAME << std::endl;
00472       const double* sz = static_cast<const Box*>(shape)->size;
00473       out << sz[0] << " " << sz[1] << " " << sz[2] << std::endl;
00474     }
00475     else
00476       if (shape->type == CYLINDER)
00477       {
00478         out << Cylinder::STRING_NAME << std::endl;
00479         out << static_cast<const Cylinder*>(shape)->radius << " " << static_cast<const Cylinder*>(shape)->length << std::endl;
00480       }
00481       else
00482         if (shape->type == CONE)
00483         {
00484           out << Cone::STRING_NAME << std::endl;
00485           out << static_cast<const Cone*>(shape)->radius << " " << static_cast<const Cone*>(shape)->length << std::endl;
00486         }
00487         else
00488           if (shape->type == PLANE)
00489           {
00490             out << Plane::STRING_NAME << std::endl;
00491             const Plane *p = static_cast<const Plane*>(shape);
00492             out << p->a << " " << p->b << " " << p->c << " " << p->d << std::endl;
00493           }
00494           else
00495             if (shape->type == MESH)
00496             {
00497               out << Mesh::STRING_NAME << std::endl;
00498               const Mesh *mesh = static_cast<const Mesh*>(shape);
00499               out << mesh->vertex_count << " " << mesh->triangle_count << std::endl;
00500 
00501               for (unsigned int i = 0 ; i < mesh->vertex_count ; ++i)
00502               {
00503                 unsigned int i3 = i * 3;
00504                 out << mesh->vertices[i3] << " " << mesh->vertices[i3 + 1] << " " << mesh->vertices[i3 + 2] << std::endl;
00505               }
00506 
00507               for (unsigned int i = 0 ; i < mesh->triangle_count ; ++i)
00508               {
00509                 unsigned int i3 = i * 3;
00510                 out << mesh->triangles[i3] << " " << mesh->triangles[i3 + 1] << " " << mesh->triangles[i3 + 2] << std::endl;
00511               }
00512             }
00513             else
00514             {
00515               logError("Unable to save shape of type %d", (int)shape->type);
00516             }
00517 }
00518 
00519 Shape* constructShapeFromText(std::istream &in)
00520 {
00521   Shape *result = NULL;
00522   if (in.good() && !in.eof())
00523   {
00524     std::string type;
00525     in >> type;
00526     if (in.good() && !in.eof())
00527     {
00528       if (type == Sphere::STRING_NAME)
00529       {
00530         double radius;
00531         in >> radius;
00532         result = new Sphere(radius);
00533       }
00534       else
00535         if (type == Box::STRING_NAME)
00536         {
00537           double x, y, z;
00538           in >> x >> y >> z;
00539           result = new Box(x, y, z);
00540         }
00541         else
00542           if (type == Cylinder::STRING_NAME)
00543           {
00544             double r, l;
00545             in >> r >> l;
00546             result = new Cylinder(r, l);
00547           }
00548           else
00549             if (type == Cone::STRING_NAME)
00550             {
00551               double r, l;
00552               in >> r >> l;
00553               result = new Cone(r, l);
00554             }
00555             else
00556               if (type == Plane::STRING_NAME)
00557               {
00558                 double a, b, c, d;
00559                 in >> a >> b >> c >> d;
00560                 result = new Plane(a, b, c, d);
00561               }
00562               else
00563                 if (type == Mesh::STRING_NAME)
00564                 {
00565                   unsigned int v, t;
00566                   in >> v >> t;
00567                   Mesh *m = new Mesh(v, t);
00568                   result = m;
00569                   for (unsigned int i = 0 ; i < m->vertex_count ; ++i)
00570                   {
00571                     unsigned int i3 = i * 3;
00572                     in >> m->vertices[i3] >> m->vertices[i3 + 1] >> m->vertices[i3 + 2];
00573                   }
00574                   for (unsigned int i = 0 ; i < m->triangle_count ; ++i)
00575                   {
00576                     unsigned int i3 = i * 3;
00577                     in >> m->triangles[i3] >> m->triangles[i3 + 1] >> m->triangles[i3 + 2];
00578                   }
00579                   m->computeTriangleNormals();
00580                   m->computeVertexNormals();
00581                 }
00582                 else
00583                   logError("Unknown shape type: '%s'", type.c_str());
00584     }
00585   }
00586   return result;
00587 }
00588 
00589 const std::string& shapeStringName(const Shape *shape)
00590 {
00591   static const std::string unknown = "unknown";
00592   if (shape)
00593     switch (shape->type)
00594     {
00595     case SPHERE:
00596       return Sphere::STRING_NAME;
00597     case CYLINDER:
00598       return Cylinder::STRING_NAME;
00599     case CONE:
00600       return Cone::STRING_NAME;
00601     case BOX:
00602       return Box::STRING_NAME;
00603     case PLANE:
00604       return Plane::STRING_NAME;
00605     case MESH:
00606       return Mesh::STRING_NAME;
00607     case OCTREE:
00608       return OcTree::STRING_NAME;
00609     default:
00610       return unknown;
00611     }
00612   else
00613   {
00614     static const std::string empty;
00615     return empty;
00616   }
00617 }
00618 
00619 }