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 #define BOOST_PARAMETER_MAX_ARITY 7
00037 #include "jsk_pcl_ros/octomap_server_contact.h"
00038 #include <algorithm>
00039 
00040 using namespace octomap;
00041 using octomap_msgs::Octomap;
00042 
00043 namespace jsk_pcl_ros
00044 {
00045   OctomapServerContact::OctomapServerContact(const ros::NodeHandle &privateNh)
00046   : OctomapServer(privateNh),
00047     DiagnosticNodelet("OctomapServerContact"),
00048     m_octreeContact(NULL),
00049     m_publishUnknownSpace(false),
00050     m_publishFrontierSpace(false),
00051     m_offsetVisualizeUnknown(0),
00052     m_maxRangeProximity(0.05),
00053     m_occupancyMinX(-std::numeric_limits<double>::max()),
00054     m_occupancyMaxX(std::numeric_limits<double>::max()),
00055     m_occupancyMinY(-std::numeric_limits<double>::max()),
00056     m_occupancyMaxY(std::numeric_limits<double>::max()),
00057     m_useContactSurface(true)
00058   {
00059     delete m_octree;
00060     m_octree = NULL;
00061     m_octree = new OcTreeContact(m_res);
00062     m_octreeContact = dynamic_cast<OcTreeContact*>(m_octree);
00063     if (!m_octreeContact) {
00064       ROS_ERROR("Could not convert OcTreeContact from OcTree");
00065       assert(m_octreeContact);
00066     }
00067 
00068     m_useHeightMap = false;
00069 
00070     privateNh.param("publish_unknown_space", m_publishUnknownSpace, m_publishUnknownSpace);
00071     privateNh.param("offset_vis_unknown", m_offsetVisualizeUnknown, m_offsetVisualizeUnknown);
00072     privateNh.param("sensor_model/max_range_proximity", m_maxRangeProximity, m_maxRangeProximity);
00073     privateNh.param("publish_frontier_space", m_publishFrontierSpace, m_publishFrontierSpace);
00074 
00075     privateNh.param("occupancy_min_x", m_occupancyMinX,m_occupancyMinX);
00076     privateNh.param("occupancy_max_x", m_occupancyMaxX,m_occupancyMaxX);
00077     privateNh.param("occupancy_min_y", m_occupancyMinY,m_occupancyMinY);
00078     privateNh.param("occupancy_max_y", m_occupancyMaxY,m_occupancyMaxY);
00079 
00080     privateNh.param("use_contact_surface", m_useContactSurface,m_useContactSurface);
00081 
00082     double r, g, b, a;
00083     privateNh.param("color_unknown/r", r, 0.5);
00084     privateNh.param("color_unknown/g", g, 0.5);
00085     privateNh.param("color_unknown/b", b, 0.7);
00086     privateNh.param("color_unknown/a", a, 1.0);
00087     m_colorUnknown.r = r;
00088     m_colorUnknown.g = g;
00089     m_colorUnknown.b = b;
00090     m_colorUnknown.a = a;
00091     privateNh.param("color_frontier/r", r, 1.0);
00092     privateNh.param("color_frontier/g", g, 0.0);
00093     privateNh.param("color_frontier/b", b, 0.0);
00094     privateNh.param("color_frontier/a", a, 1.0);
00095     m_colorFrontier.r = r;
00096     m_colorFrontier.g = g;
00097     m_colorFrontier.b = b;
00098     m_colorFrontier.a = a;
00099 
00100     m_unknownPointCloudPub = m_nh.advertise<sensor_msgs::PointCloud2>("octomap_unknown_point_cloud_centers", 1, m_latchedTopics);
00101     m_umarkerPub = m_nh.advertise<visualization_msgs::MarkerArray>("unknown_cells_vis_array", 1, m_latchedTopics);
00102 
00103     m_pointProximitySub = new message_filters::Subscriber<sensor_msgs::PointCloud2> (m_nh, "proximity_in", 5);
00104     m_tfPointProximitySub = new tf::MessageFilter<sensor_msgs::PointCloud2> (*m_pointProximitySub, m_tfListener, m_worldFrameId, 5);
00105     m_tfPointProximitySub->registerCallback(boost::bind(&OctomapServerContact::insertProximityCallback, this, _1));
00106 
00107     m_frontierPointCloudPub = m_nh.advertise<sensor_msgs::PointCloud2>("octomap_frontier_point_cloud_centers", 1, m_latchedTopics);
00108     m_fromarkerPub = m_nh.advertise<visualization_msgs::MarkerArray>("frontier_cells_vis_array", 1, m_latchedTopics);
00109 
00110     m_contactSensorSub.subscribe(m_nh, "contact_sensors_in", 2);
00111     m_tfContactSensorSub.reset(new tf::MessageFilter<jsk_recognition_msgs::ContactSensorArray> (
00112                                  m_contactSensorSub, m_tfListener, m_worldFrameId, 2));
00113     m_tfContactSensorSub->registerCallback(boost::bind(&OctomapServerContact::insertContactSensorCallback, this, _1));
00114 
00115     initContactSensor(privateNh);
00116   }
00117 
00118   OctomapServerContact::~OctomapServerContact() {
00119   }
00120 
00121   void OctomapServerContact::initContactSensor(const ros::NodeHandle &privateNh) {
00122     double defaultPadding, defaultScale;
00123     privateNh.param<double>("self_see_defaultPadding", defaultPadding, .01);
00124     privateNh.param<double>("self_see_defaultScale", defaultScale, 1.0);
00125     std::vector<robot_self_filter::LinkInfo> links;
00126 
00127     if (!privateNh.hasParam("self_see_links")) {
00128       ROS_WARN("No links specified for self filtering.");
00129     }
00130     else {
00131       XmlRpc::XmlRpcValue sslVals;;
00132       privateNh.getParam("self_see_links", sslVals);
00133       if (sslVals.getType() != XmlRpc::XmlRpcValue::TypeArray) {
00134         ROS_WARN("Self see links need to be an array");
00135       }
00136       else {
00137         if (sslVals.size() == 0) {
00138           ROS_WARN("No values in self see links array");
00139         }
00140         else {
00141           for (int i = 0; i < sslVals.size(); i++) {
00142             robot_self_filter::LinkInfo li;
00143             if (sslVals[i].getType() != XmlRpc::XmlRpcValue::TypeStruct) {
00144               ROS_WARN("Self see links entry %d is not a structure.  Stopping processing of self see links",i);
00145               break;
00146             }
00147             if (!sslVals[i].hasMember("name")) {
00148               ROS_WARN("Self see links entry %d has no name.  Stopping processing of self see links",i);
00149               break;
00150             }
00151             li.name = std::string(sslVals[i]["name"]);
00152             if (!sslVals[i].hasMember("padding")) {
00153               ROS_DEBUG("Self see links entry %d has no padding.  Assuming default padding of %g",i,defaultPadding);
00154               li.padding = defaultPadding;
00155             }
00156             else {
00157               li.padding = sslVals[i]["padding"];
00158             }
00159             if (!sslVals[i].hasMember("scale")) {
00160               ROS_DEBUG("Self see links entry %d has no scale.  Assuming default scale of %g",i,defaultScale);
00161               li.scale = defaultScale;
00162             }
00163             else {
00164               li.scale = sslVals[i]["scale"];
00165             }
00166             links.push_back(li);
00167           }
00168         }
00169       }
00170     }
00171     m_selfMask = boost::shared_ptr<robot_self_filter::SelfMaskNamedLink>(new robot_self_filter::SelfMaskNamedLink(m_tfListener, links));
00172   }
00173 
00174   void OctomapServerContact::insertProximityCallback(const sensor_msgs::PointCloud2::ConstPtr& cloud) {
00175     
00176 
00177     ros::WallTime startTime = ros::WallTime::now();
00178 
00179     
00180     
00181     
00182     PCLPointCloud pc; 
00183     pcl::fromROSMsg(*cloud, pc);
00184 
00185     tf::StampedTransform sensorToWorldTf;
00186     try {
00187       m_tfListener.lookupTransform(m_worldFrameId, cloud->header.frame_id, cloud->header.stamp, sensorToWorldTf);
00188     } catch(tf::TransformException& ex){
00189       ROS_ERROR_STREAM( "Transform error of sensor data: " << ex.what() << ", quitting callback");
00190       return;
00191     }
00192 
00193     Eigen::Matrix4f sensorToWorld;
00194     pcl_ros::transformAsMatrix(sensorToWorldTf, sensorToWorld);
00195 
00196     
00197     pcl::transformPointCloud(pc, pc, sensorToWorld);
00198 
00199     pc.header = pc.header;
00200 
00201     insertScanProximity(sensorToWorldTf.getOrigin(), pc);
00202 
00203     double total_elapsed = (ros::WallTime::now() - startTime).toSec();
00204     ROS_DEBUG("Pointcloud insertion in OctomapServer done (%zu pts, %f sec)", pc.size(), total_elapsed);
00205 
00206     publishAll(cloud->header.stamp);
00207   }
00208 
00209   void OctomapServerContact::insertScanProximity(const tf::Point& sensorOriginTf, const PCLPointCloud& pc) {
00210     point3d sensorOrigin = pointTfToOctomap(sensorOriginTf);
00211 
00212     if (!m_octree->coordToKeyChecked(sensorOrigin, m_updateBBXMin)
00213         || !m_octree->coordToKeyChecked(sensorOrigin, m_updateBBXMax))
00214       {
00215         ROS_ERROR_STREAM("Could not generate Key for origin "<<sensorOrigin);
00216       }
00217 
00218 #ifdef COLOR_OCTOMAP_SERVER
00219     unsigned char* colors = new unsigned char[3];
00220 #endif
00221 
00222     
00223     KeySet free_cells, occupied_cells;
00224 
00225     
00226     for (PCLPointCloud::const_iterator it = pc.begin(); it != pc.end(); ++it) {
00227       point3d point(it->x, it->y, it->z);
00228       
00229       if ((m_maxRangeProximity < 0.0) || ((point - sensorOrigin).norm() <= m_maxRangeProximity) ) {
00230 
00231         
00232         if (m_octree->computeRayKeys(sensorOrigin, point, m_keyRay)){
00233           free_cells.insert(m_keyRay.begin(), m_keyRay.end());
00234         }
00235         
00236         OcTreeKey key;
00237         if (m_octree->coordToKeyChecked(point, key)){
00238           occupied_cells.insert(key);
00239 
00240           updateMinKey(key, m_updateBBXMin);
00241           updateMaxKey(key, m_updateBBXMax);
00242 
00243 #ifdef COLOR_OCTOMAP_SERVER // NB: Only read and interpret color if it's an occupied node
00244           const int rgb = *reinterpret_cast<const int*>(&(it->rgb)); 
00245           colors[0] = ((rgb >> 16) & 0xff);
00246           colors[1] = ((rgb >> 8) & 0xff);
00247           colors[2] = (rgb & 0xff);
00248           m_octree->averageNodeColor(it->x, it->y, it->z, colors[0], colors[1], colors[2]);
00249 #endif
00250         }
00251       } else {
00252         point3d new_end = sensorOrigin + (point - sensorOrigin).normalized() * m_maxRangeProximity;
00253         if (m_octree->computeRayKeys(sensorOrigin, new_end, m_keyRay)){
00254           free_cells.insert(m_keyRay.begin(), m_keyRay.end());
00255 
00256           octomap::OcTreeKey endKey;
00257           if (m_octree->coordToKeyChecked(new_end, endKey)){
00258             updateMinKey(endKey, m_updateBBXMin);
00259             updateMaxKey(endKey, m_updateBBXMax);
00260           } else{
00261             ROS_ERROR_STREAM("Could not generate Key for endpoint "<<new_end);
00262           }
00263         }
00264       }
00265     }
00266 
00267     
00268     for(KeySet::iterator it = free_cells.begin(), end=free_cells.end(); it!= end; ++it){
00269       if (occupied_cells.find(*it) == occupied_cells.end()){
00270         m_octree->updateNode(*it, false);
00271       }
00272     }
00273 
00274     
00275     for (KeySet::iterator it = occupied_cells.begin(), end=occupied_cells.end(); it!= end; it++) {
00276       m_octree->updateNode(*it, true);
00277     }
00278 
00279     
00280     
00281     
00282     octomap::point3d minPt, maxPt;
00283     ROS_DEBUG_STREAM("Bounding box keys (before): " << m_updateBBXMin[0] << " " <<m_updateBBXMin[1] << " " << m_updateBBXMin[2] << " / " <<m_updateBBXMax[0] << " "<<m_updateBBXMax[1] << " "<< m_updateBBXMax[2]);
00284 
00285     
00286     
00287     
00288     
00289     
00290     
00291     
00292     
00293     
00294     
00295     
00296 
00297     
00298     minPt = m_octree->keyToCoord(m_updateBBXMin);
00299     maxPt = m_octree->keyToCoord(m_updateBBXMax);
00300     ROS_DEBUG_STREAM("Updated area bounding box: "<< minPt << " - "<<maxPt);
00301     ROS_DEBUG_STREAM("Bounding box keys (after): " << m_updateBBXMin[0] << " " <<m_updateBBXMin[1] << " " << m_updateBBXMin[2] << " / " <<m_updateBBXMax[0] << " "<<m_updateBBXMax[1] << " "<< m_updateBBXMax[2]);
00302 
00303     if (m_compressMap)
00304       m_octree->prune();
00305   }
00306 
00307   void OctomapServerContact::insertContactSensor(const jsk_recognition_msgs::ContactSensorArray::ConstPtr& msg) {
00308     std::vector<jsk_recognition_msgs::ContactSensor> datas = msg->datas;
00309 
00310     
00311     {
00312       std_msgs::Header tmpHeader;
00313       tmpHeader.frame_id = m_worldFrameId;
00314       tmpHeader.stamp = msg->header.stamp;
00315       if(!m_selfMask->assumeFrame(tmpHeader)) {
00316         ROS_ERROR_STREAM("failed tf transformation in insertContactSensor");
00317         return;
00318       }
00319     }
00320 
00321     
00322     point3d pmin_raw( m_occupancyMinX, m_occupancyMinY, m_occupancyMinZ );
00323     point3d pmax_raw( m_occupancyMaxX, m_occupancyMaxY, m_occupancyMaxZ );
00324     point3d pmin = m_octree->keyToCoord(m_octree->coordToKey(pmin_raw));
00325     point3d pmax = m_octree->keyToCoord(m_octree->coordToKey(pmax_raw));
00326     float diff[3];
00327     unsigned int steps[3];
00328     double resolution = m_octreeContact->getResolution();
00329     for (int i = 0; i < 3; ++i) {
00330       diff[i] = pmax(i) - pmin(i);
00331       steps[i] = floor(diff[i] / resolution);
00332       
00333     }
00334 
00335     
00336     if (m_useContactSurface) {
00337       std::vector< std::vector<bool> > containFlag(datas.size(), std::vector<bool>(8));
00338       point3d p = pmin;
00339       for (unsigned int x = 0; x < steps[0]; ++x) {
00340         p.x() += resolution;
00341         for (unsigned int y = 0; y < steps[1]; ++y) {
00342           p.y() += resolution;
00343           for (unsigned int z = 0; z < steps[2]; ++z) {
00344             
00345             p.z() += resolution;
00346             
00347             point3d vertexOffset(-resolution/2.0, -resolution/2.0, -resolution/2.0);
00348             point3d vertex;
00349             for (int i = 0; i < 2; i++) {
00350               if (i == 1) { vertexOffset.z() += resolution; }
00351               for (int j = 0; j < 2; j++) {
00352                 if (j == 1) { vertexOffset.y() += resolution; }
00353                 for (int k = 0; k < 2; k++) {
00354                   if (k == 1) { vertexOffset.x() += resolution; }
00355                   vertex = p + vertexOffset;
00356                   
00357                   
00358                   for (int l=0; l<datas.size(); l++) {
00359                     if (m_selfMask->getMaskContainmentforNamedLink(vertex(0), vertex(1), vertex(2), datas[l].link_name) == robot_self_filter::INSIDE) {
00360                       
00361                       containFlag[l][i+j*2+k*4] = true;
00362                     }
00363                     else {
00364                       containFlag[l][i+j*2+k*4] = false;
00365                     }
00366                   }
00367                 }
00368                 vertexOffset.x() -= resolution;
00369               }
00370               vertexOffset.y() -= resolution;
00371             }
00372 
00373             
00374             std::vector<bool> containFlagLinkSum(8, false);
00375             std::vector<bool> containFlagVerticesSum(datas.size(), false);
00376             std::vector<bool> containFlagVerticesProd(datas.size(), true);
00377             bool insideFlag = false;
00378             bool surfaceFlag = false;
00379             for (int l = 0; l < datas.size(); l++) {
00380               for (int i = 0; i < 8; i++) {
00381                 if (containFlag[l][i]) {
00382                   containFlagLinkSum[i] = true;
00383                   containFlagVerticesSum[l] = true;
00384                 }
00385                 else {
00386                   containFlagVerticesProd[l] = false;
00387                 }
00388               }
00389             }
00390             insideFlag = (std::find(containFlagLinkSum.begin(), containFlagLinkSum.end(), false) == containFlagLinkSum.end()); 
00391             for (int l = 0; l < datas.size(); l++) {
00392               if (containFlagVerticesSum[l] && !(containFlagVerticesProd[l]) ) {
00393                 if (datas[l].contact) {
00394                   surfaceFlag = true;
00395                 }
00396               }
00397             }
00398             if (insideFlag) { 
00399               octomap::OcTreeKey pKey;
00400               if (m_octreeContact->coordToKeyChecked(p, pKey)) {
00401                 m_octreeContact->updateNode(pKey, m_octreeContact->getProbMissContactSensorLog());
00402                 
00403               }
00404             }
00405             else if (surfaceFlag) { 
00406               octomap::OcTreeKey pKey;
00407               if (m_octreeContact->coordToKeyChecked(p, pKey)) {
00408                 m_octreeContact->updateNode(pKey, m_octreeContact->getProbHitContactSensorLog());
00409                 
00410               }
00411             }
00412           }
00413           p.z() = pmin.z();
00414         }
00415         p.y() = pmin.y();
00416       }
00417     }
00418     else {
00419       point3d vertexOffset(-resolution/2.0, -resolution/2.0, -resolution/2.0);
00420 #pragma omp parallel for
00421       for (unsigned int cnt = 0; cnt < steps[0] * steps[1] * steps[2]; ++cnt) {
00422         
00423         point3d p;
00424         {
00425           unsigned int id[3];
00426           id[0] = cnt / (steps[1] * steps[2]);
00427           id[1] = (cnt % (steps[1] * steps[2])) / steps[2];
00428           id[2] = (cnt % (steps[1] * steps[2])) % steps[2];
00429           p.x() = pmin(0) + resolution * id[0];
00430           p.y() = pmin(1) + resolution * id[1];
00431           p.z() = pmin(2) + resolution * id[2];
00432         }
00433         point3d vertex;
00434         vertex = p + vertexOffset;
00435         
00436         for (int l=0; l<datas.size(); l++) {
00437           if (m_selfMask->getMaskContainmentforNamedLink(vertex(0), vertex(1), vertex(2), datas[l].link_name) == robot_self_filter::INSIDE) {
00438             octomap::OcTreeKey pKey;
00439             if (m_octreeContact->coordToKeyChecked(p, pKey)) {
00440 #pragma omp critical
00441               m_octreeContact->updateNode(pKey, m_octreeContact->getProbMissContactSensorLog());
00442             }
00443             break;
00444           }
00445         }
00446       }
00447     }
00448     m_octreeContact->updateInnerOccupancy();
00449   }
00450 
00451   void OctomapServerContact::insertContactSensorCallback(const jsk_recognition_msgs::ContactSensorArray::ConstPtr& msg) {
00452     NODELET_INFO("insert contact sensor");
00453     insertContactSensor(msg);
00454 
00455     publishAll(msg->header.stamp);
00456   }
00457 
00458   void OctomapServerContact::publishAll(const ros::Time& rostime) {
00459     ros::WallTime startTime = ros::WallTime::now();
00460     size_t octomapSize = m_octreeContact->size();
00461     
00462     if (octomapSize <= 1) {
00463       ROS_WARN("Nothing to publish, octree is empty");
00464       return;
00465     }
00466 
00467     bool publishFreeMarkerArray = m_publishFreeSpace && (m_latchedTopics || m_fmarkerPub.getNumSubscribers() > 0);
00468     bool publishUnknownMarkerArray = m_publishUnknownSpace && (m_latchedTopics || m_umarkerPub.getNumSubscribers() > 0);
00469     bool publishFrontierMarkerArray = m_publishFrontierSpace && (m_latchedTopics || m_fromarkerPub.getNumSubscribers() > 0);
00470     bool publishMarkerArray = (m_latchedTopics || m_markerPub.getNumSubscribers() > 0);
00471     bool publishPointCloud = (m_latchedTopics || m_pointCloudPub.getNumSubscribers() > 0);
00472     bool publishBinaryMap = (m_latchedTopics || m_binaryMapPub.getNumSubscribers() > 0);
00473     bool publishFullMap = (m_latchedTopics || m_fullMapPub.getNumSubscribers() > 0);
00474     m_publish2DMap = (m_latchedTopics || m_mapPub.getNumSubscribers() > 0);
00475 
00476     
00477     visualization_msgs::MarkerArray freeNodesVis;
00478     
00479     freeNodesVis.markers.resize(m_treeDepth+1);
00480 
00481     geometry_msgs::Pose pose;
00482     pose.orientation = tf::createQuaternionMsgFromYaw(0.0);
00483 
00484     
00485     visualization_msgs::MarkerArray occupiedNodesVis;
00486     
00487     occupiedNodesVis.markers.resize(m_treeDepth+1);
00488 
00489     
00490     pcl::PointCloud<pcl::PointXYZ> pclCloud;
00491 
00492     
00493     handlePreNodeTraversal(rostime);
00494 
00495     
00496     for (OcTree::iterator it = m_octreeContact->begin(m_maxTreeDepth), end = m_octreeContact->end(); it != end; ++it) {
00497       bool inUpdateBBX = isInUpdateBBX(it);
00498 
00499       
00500       handleNode(it);
00501       if (inUpdateBBX) {
00502         handleNodeInBBX(it);
00503       }
00504 
00505       if (m_octreeContact->isNodeOccupied(*it)) {
00506         double x = it.getX();
00507         double y = it.getY();
00508         double z = it.getZ();
00509         if (x > m_occupancyMinX && x < m_occupancyMaxX && y > m_occupancyMinY && y < m_occupancyMaxY && z > m_occupancyMinZ && z < m_occupancyMaxZ) {
00510           double size = it.getSize();
00511           double x = it.getX();
00512           double y = it.getY();
00513 
00514           
00515           if (m_filterSpeckles && (it.getDepth() == m_treeDepth +1) && isSpeckleNode(it.getKey())) {
00516             ROS_DEBUG("Ignoring single speckle at (%f,%f,%f)", x, y, z);
00517             continue;
00518           } 
00519 
00520           handleOccupiedNode(it);
00521           if (inUpdateBBX) {
00522             handleOccupiedNodeInBBX(it);
00523           }
00524 
00525           
00526           if (publishMarkerArray) {
00527             unsigned idx = it.getDepth();
00528             assert(idx < occupiedNodesVis.markers.size());
00529 
00530             geometry_msgs::Point cubeCenter;
00531             cubeCenter.x = x;
00532             cubeCenter.y = y;
00533             cubeCenter.z = z;
00534 
00535             occupiedNodesVis.markers[idx].points.push_back(cubeCenter);
00536             if (m_useHeightMap) {
00537               double minX, minY, minZ, maxX, maxY, maxZ;
00538               m_octreeContact->getMetricMin(minX, minY, minZ);
00539               m_octreeContact->getMetricMax(maxX, maxY, maxZ);
00540 
00541               double h = (1.0 - std::min(std::max((cubeCenter.z-minZ)/ (maxZ - minZ), 0.0), 1.0)) *m_colorFactor;
00542               occupiedNodesVis.markers[idx].colors.push_back(heightMapColor(h));
00543             }
00544           }
00545 
00546           
00547           if (publishPointCloud) {
00548             pclCloud.push_back(pcl::PointXYZ(x, y, z));
00549           }
00550 
00551         }
00552       } else { 
00553         double x = it.getX();
00554         double y = it.getY();
00555         double z = it.getZ();
00556         if (x > m_occupancyMinX && x < m_occupancyMaxX && y > m_occupancyMinY && y < m_occupancyMaxY && z > m_occupancyMinZ && z < m_occupancyMaxZ) {
00557           handleFreeNode(it);
00558           if (inUpdateBBX)
00559             handleFreeNodeInBBX(it);
00560 
00561           if (m_publishFreeSpace) {
00562             double x = it.getX();
00563             double y = it.getY();
00564 
00565             
00566             if (publishFreeMarkerArray) {
00567               unsigned idx = it.getDepth();
00568               assert(idx < freeNodesVis.markers.size());
00569 
00570               geometry_msgs::Point cubeCenter;
00571               cubeCenter.x = x;
00572               cubeCenter.y = y;
00573               cubeCenter.z = z;
00574 
00575               freeNodesVis.markers[idx].points.push_back(cubeCenter);
00576             }
00577           }
00578         }
00579       }
00580     }
00581 
00582     
00583     handlePostNodeTraversal(rostime);
00584 
00585     
00586     if (publishMarkerArray) {
00587       for (unsigned i = 0; i < occupiedNodesVis.markers.size(); ++i) {
00588         double size = m_octreeContact->getNodeSize(i);
00589 
00590         occupiedNodesVis.markers[i].header.frame_id = m_worldFrameId;
00591         occupiedNodesVis.markers[i].header.stamp = rostime;
00592         occupiedNodesVis.markers[i].ns = m_worldFrameId;
00593         occupiedNodesVis.markers[i].id = i;
00594         occupiedNodesVis.markers[i].type = visualization_msgs::Marker::CUBE_LIST;
00595         occupiedNodesVis.markers[i].scale.x = size;
00596         occupiedNodesVis.markers[i].scale.y = size;
00597         occupiedNodesVis.markers[i].scale.z = size;
00598         occupiedNodesVis.markers[i].color = m_color;
00599 
00600 
00601         if (occupiedNodesVis.markers[i].points.size() > 0) {
00602           occupiedNodesVis.markers[i].action = visualization_msgs::Marker::ADD;
00603         }
00604         else {
00605           occupiedNodesVis.markers[i].action = visualization_msgs::Marker::DELETE;
00606         }
00607       }
00608 
00609       m_markerPub.publish(occupiedNodesVis);
00610     }
00611 
00612 
00613     
00614     if (publishFreeMarkerArray) {
00615       for (unsigned i = 0; i < freeNodesVis.markers.size(); ++i) {
00616         double size = m_octreeContact->getNodeSize(i);
00617 
00618         freeNodesVis.markers[i].header.frame_id = m_worldFrameId;
00619         freeNodesVis.markers[i].header.stamp = rostime;
00620         freeNodesVis.markers[i].ns = m_worldFrameId;
00621         freeNodesVis.markers[i].id = i;
00622         freeNodesVis.markers[i].type = visualization_msgs::Marker::CUBE_LIST;
00623         freeNodesVis.markers[i].scale.x = size;
00624         freeNodesVis.markers[i].scale.y = size;
00625         freeNodesVis.markers[i].scale.z = size;
00626         freeNodesVis.markers[i].color = m_colorFree;
00627 
00628 
00629         if (freeNodesVis.markers[i].points.size() > 0) {
00630           freeNodesVis.markers[i].action = visualization_msgs::Marker::ADD;
00631         }
00632         else {
00633           freeNodesVis.markers[i].action = visualization_msgs::Marker::DELETE;
00634         }
00635       }
00636 
00637       m_fmarkerPub.publish(freeNodesVis);
00638     }
00639 
00640 
00641     
00642     if (publishUnknownMarkerArray) {
00643       visualization_msgs::MarkerArray unknownNodesVis;
00644       unknownNodesVis.markers.resize(1);
00645 
00646       point3d_list unknownLeaves;
00647       double offset = m_offsetVisualizeUnknown;
00648       point3d pMin(m_occupancyMinX + offset, m_occupancyMinY + offset, m_occupancyMinZ + offset);
00649       point3d pMax(m_occupancyMaxX - offset, m_occupancyMaxY - offset, m_occupancyMaxZ - offset);
00650 
00651       m_octreeContact->getUnknownLeafCenters(unknownLeaves, pMin, pMax);
00652       pcl::PointCloud<pcl::PointXYZ> unknownCloud;
00653 
00654       for (point3d_list::iterator it = unknownLeaves.begin(); it != unknownLeaves.end(); it++) {
00655         float x = (*it).x();
00656         float y = (*it).y();
00657         float z = (*it).z();
00658         unknownCloud.push_back(pcl::PointXYZ(x, y, z));
00659 
00660         geometry_msgs::Point cubeCenter;
00661         cubeCenter.x = x;
00662         cubeCenter.y = y;
00663         cubeCenter.z = z;
00664         if (m_useHeightMap) {
00665           double minX, minY, minZ, maxX, maxY, maxZ;
00666           m_octreeContact->getMetricMin(minX, minY, minZ);
00667           m_octreeContact->getMetricMax(maxX, maxY, maxZ);
00668           double h = (1.0 - std::min(std::max((cubeCenter.z-minZ)/ (maxZ - minZ), 0.0), 1.0)) *m_colorFactor;
00669           unknownNodesVis.markers[0].colors.push_back(heightMapColor(h));
00670         }
00671         unknownNodesVis.markers[0].points.push_back(cubeCenter);
00672       }
00673 
00674       double size = m_octreeContact->getNodeSize(m_maxTreeDepth);
00675       unknownNodesVis.markers[0].header.frame_id = m_worldFrameId;
00676       unknownNodesVis.markers[0].header.stamp = rostime;
00677       unknownNodesVis.markers[0].ns = m_worldFrameId;
00678       unknownNodesVis.markers[0].id = 0;
00679       unknownNodesVis.markers[0].type = visualization_msgs::Marker::CUBE_LIST;
00680       unknownNodesVis.markers[0].scale.x = size;
00681       unknownNodesVis.markers[0].scale.y = size;
00682       unknownNodesVis.markers[0].scale.z = size;
00683       unknownNodesVis.markers[0].color = m_colorUnknown;
00684 
00685       if (unknownNodesVis.markers[0].points.size() > 0) {
00686         unknownNodesVis.markers[0].action = visualization_msgs::Marker::ADD;
00687       }
00688       else {
00689         unknownNodesVis.markers[0].action = visualization_msgs::Marker::DELETE;
00690       }
00691       m_umarkerPub.publish(unknownNodesVis);
00692 
00693       
00694       sensor_msgs::PointCloud2 unknownRosCloud;
00695       pcl::toROSMsg (unknownCloud, unknownRosCloud);
00696       unknownRosCloud.header.frame_id = m_worldFrameId;
00697       unknownRosCloud.header.stamp = rostime;
00698       m_unknownPointCloudPub.publish(unknownRosCloud);
00699 
00700       
00701       if (publishFrontierMarkerArray) {
00702         visualization_msgs::MarkerArray frontierNodesVis;
00703         frontierNodesVis.markers.resize(1);
00704         pcl::PointCloud<pcl::PointXYZ> frontierCloud;
00705         double resolution = m_octreeContact->getResolution();
00706         
00707         int x_num = int(((m_occupancyMaxX - m_occupancyMinX) / resolution));
00708         int y_num = int(((m_occupancyMaxY - m_occupancyMinY) / resolution));
00709         int z_num = int(((m_occupancyMaxZ - m_occupancyMinZ) / resolution));
00710         std::vector< std::vector< std::vector<int> > > check_unknown(x_num, std::vector< std::vector<int> >(y_num, std::vector<int>(z_num)));
00711         std::vector< std::vector< std::vector<int> > > check_occupied(x_num, std::vector< std::vector<int> >(y_num, std::vector<int>(z_num)));
00712         std::vector< std::vector< std::vector<int> > > check_frontier(x_num, std::vector< std::vector<int> >(y_num, std::vector<int>(z_num)));
00713 
00714         for (int i = 0; i < x_num; i++) {
00715           for (int j = 0; j < y_num; j++) {
00716             for (int k = 0; k < z_num; k++) {
00717               check_unknown[i][j][k] = 0;
00718               check_occupied[i][j][k] = 0;
00719               check_frontier[i][j][k] = 0;
00720             }
00721           }
00722         }
00723 
00724         
00725         for (point3d_list::iterator it_unknown = unknownLeaves.begin();
00726              it_unknown != unknownLeaves.end();
00727              it_unknown++) {
00728           
00729           double x_unknown = it_unknown->x();
00730           double y_unknown = it_unknown->y();
00731           double z_unknown = it_unknown->z();
00732           int x_index = int(std::round((x_unknown - m_occupancyMinX) / resolution - 1));
00733           int y_index = int(std::round((y_unknown - m_occupancyMinY) / resolution - 1));
00734           int z_index = int(std::round((z_unknown - m_occupancyMinZ) / resolution - 1));
00735           check_unknown[x_index][y_index][z_index] = 1;
00736         }
00737 
00738         
00739         for (int idx = 0; idx < occupiedNodesVis.markers.size(); idx++) {
00740           double size_occupied = occupiedNodesVis.markers[idx].scale.x;
00741           for (int id = 0; id < occupiedNodesVis.markers[idx].points.size(); id++) {
00742             double x_occupied = occupiedNodesVis.markers[idx].points[id].x;
00743             double y_occupied = occupiedNodesVis.markers[idx].points[id].y;
00744             double z_occupied = occupiedNodesVis.markers[idx].points[id].z;
00745             int x_min_index = std::round((x_occupied - (size_occupied / 2.0) - m_occupancyMinX) / resolution);
00746             int y_min_index = std::round((y_occupied - (size_occupied / 2.0) - m_occupancyMinY) / resolution);
00747             int z_min_index = std::round((z_occupied - (size_occupied / 2.0) - m_occupancyMinZ) / resolution);
00748             for (int i = x_min_index; i < x_min_index + int(size_occupied/resolution); i++) {
00749               for (int j = y_min_index; j < y_min_index + int(size_occupied/resolution); j++) {
00750                 for (int k = z_min_index; k < z_min_index + int(size_occupied/resolution); k++) {
00751                   check_occupied[i][j][k] = 1;
00752                 }
00753               }
00754             }
00755           }
00756         }
00757 
00758         
00759         
00760         
00761         geometry_msgs::Point cubeCenter;
00762         for (int i = 0; i < x_num; i++) {
00763           for (int j = 0; j < y_num; j++) {
00764             for (int k = 0; k < z_num-1; k++) {
00765               for (int l = -1; l <= 1; l++) {
00766                 if ( i+l < 0 || x_num <= i+l ) continue;
00767                 for (int m = -1; m <= 1; m++) {
00768                   if ( j+m < 0 || y_num <= j+m ) continue;
00769                   for (int n = -1; n <= 1; n++) {
00770                     if (  k+n < 0 || z_num <= k+n ) continue;
00771                     if (l == 0 && m == 0 && n== 0) continue;
00772                     if (check_unknown[i+l][j+m][k+n] == 1 && check_unknown[i][j][k] == 0 && check_occupied[i][j][k] == 0 && check_frontier[i][j][k] == 0) {
00773                       check_frontier[i][j][k] = 1;
00774                       cubeCenter.x = (i+0.5)*resolution + m_occupancyMinX;
00775                       cubeCenter.y = (j+0.5)*resolution + m_occupancyMinY;
00776                       cubeCenter.z = (k+0.5)*resolution + m_occupancyMinZ;
00777                       if (m_useHeightMap) {
00778                         double minX, minY, minZ, maxX, maxY, maxZ;
00779                         m_octreeContact->getMetricMin(minX, minY, minZ);
00780                         m_octreeContact->getMetricMax(maxX, maxY, maxZ);
00781                         double h = (1.0 - std::min(std::max((cubeCenter.z-minZ)/ (maxZ - minZ), 0.0), 1.0)) *m_colorFactor;
00782                         frontierNodesVis.markers[0].colors.push_back(heightMapColor(h));
00783                       }
00784                       frontierNodesVis.markers[0].points.push_back(cubeCenter);
00785                     }
00786                   }
00787                 }
00788               }
00789             }
00790           }
00791         }
00792 
00793         
00794         double size = m_octreeContact->getNodeSize(m_maxTreeDepth);
00795         frontierNodesVis.markers[0].header.frame_id = m_worldFrameId;
00796         frontierNodesVis.markers[0].header.stamp = rostime;
00797         frontierNodesVis.markers[0].ns = m_worldFrameId;
00798         frontierNodesVis.markers[0].id = 0;
00799         frontierNodesVis.markers[0].type = visualization_msgs::Marker::CUBE_LIST;
00800         frontierNodesVis.markers[0].scale.x = size;
00801         frontierNodesVis.markers[0].scale.y = size;
00802         frontierNodesVis.markers[0].scale.z = size;
00803         frontierNodesVis.markers[0].color = m_colorFrontier;
00804 
00805         if (frontierNodesVis.markers[0].points.size() > 0) {
00806           frontierNodesVis.markers[0].action = visualization_msgs::Marker::ADD;
00807         }
00808         else {
00809           frontierNodesVis.markers[0].action = visualization_msgs::Marker::DELETE;
00810         }
00811 
00812         m_fromarkerPub.publish(frontierNodesVis);
00813 
00814         
00815         sensor_msgs::PointCloud2 frontierRosCloud;
00816         pcl::toROSMsg (frontierCloud, frontierRosCloud);
00817         frontierRosCloud.header.frame_id = m_worldFrameId;
00818         frontierRosCloud.header.stamp = rostime;
00819         m_frontierPointCloudPub.publish(frontierRosCloud);
00820       }
00821     }
00822 
00823     
00824     if (publishPointCloud) {
00825       sensor_msgs::PointCloud2 cloud;
00826       pcl::toROSMsg (pclCloud, cloud);
00827       cloud.header.frame_id = m_worldFrameId;
00828       cloud.header.stamp = rostime;
00829       m_pointCloudPub.publish(cloud);
00830     }
00831 
00832     if (publishBinaryMap) {
00833       publishBinaryOctoMap(rostime);
00834     }
00835 
00836     if (publishFullMap) {
00837       publishFullOctoMap(rostime);
00838     }
00839 
00840     double totalElapsed = (ros::WallTime::now() - startTime).toSec();
00841     ROS_DEBUG("Map publishing in OctomapServer took %f sec", totalElapsed);
00842   }
00843 
00844   void OctomapServerContact::onInit(void)
00845   {
00846     DiagnosticNodelet::onInit();
00847     onInitPostProcess();
00848   }
00849 }
00850 
00851 #include <pluginlib/class_list_macros.h>
00852 PLUGINLIB_EXPORT_CLASS (jsk_pcl_ros::OctomapServerContact, nodelet::Nodelet);