PatchMap.cpp
Go to the documentation of this file.
00001 
00002 /*
00003  * PatchMap.cpp
00004  *
00005  *  Created on: 14.11.2011
00006  *      Author: hess
00007  */
00008 
00009 #include <surfacelet/PatchMap.h>
00010 
00011 #include <iostream>
00012 #include <limits>
00013 #include <cmath>
00014 #include <cstdlib>
00015 
00016 #include <boost/thread/thread.hpp>
00017 #include <pcl/common/common_headers.h>
00018 #include <pcl/features/normal_3d.h>
00019 #include <pcl/io/pcd_io.h>
00020 #include <pcl/console/parse.h>
00021 #include <pcl/point_types.h>
00022 #include <pcl/filters/statistical_outlier_removal.h>
00023 #include <pcl/point_types.h>
00024 #include <pcl/features/normal_3d.h>
00025 #include <sensor_msgs/PointCloud2.h>
00026 #include <sensor_msgs/point_cloud_conversion.h>
00027 #include <pcl/ModelCoefficients.h>
00028 #include <pcl/io/pcd_io.h>
00029 #include <pcl/point_types.h>
00030 #include <pcl/features/normal_3d.h>
00031 #include <pcl/filters/extract_indices.h>
00032 #include <pcl/filters/passthrough.h>
00033 
00034 #include <ros/ros.h>
00035 #include <pcl_ros/transforms.h>
00036 #include <sensor_msgs/PointCloud2.h>
00037 
00038 #include <tf/tf.h>
00039 #include <visualization_msgs/Marker.h>
00040 #include <visualization_msgs/MarkerArray.h>
00041 #include <eigen3/Eigen/src/Core/EigenBase.h>
00042 #include <eigen3/Eigen/src/Geometry/Quaternion.h>
00043 
00044 using namespace surfacelet;
00045 
00046 tf::Pose tfPoseFromPatch(const SurfacePatch& patch) {
00047 
00048     tf::Pose pose;
00049     pose.setOrigin(tf::Point(patch.x, patch.y, patch.z));
00050 
00051     //compute angle-axis representation
00052     //compute cross product of normal and z-axis and get the rotation with smallest angle
00053     Eigen::Vector3f patch_normal(patch.normal_x, patch.normal_y, patch.normal_z);
00054     patch_normal.normalize();
00055     Eigen::Vector3f cross_product = Eigen::Vector3f(0, 0, 1).cross(patch_normal);
00056     Eigen::Matrix3f rot_matrix;
00057     cross_product.normalize();
00058 
00059     float angle = 0;
00060     if (cross_product.norm() > 0.000000001) { //everything ok
00061         angle = acos(patch_normal.dot(Eigen::Vector3f(0, 0, 1)));
00062         rot_matrix = Eigen::AngleAxis<float>(angle, cross_product).toRotationMatrix();
00063     } else { //cross product 0 - normal either in or exactly opposite of z-axis
00064         double tmp = patch_normal.dot(Eigen::Vector3f(0, 0, 1));
00065         if (tmp > 0) {
00066             rot_matrix = Eigen::Matrix3f::Identity();
00067         } else {
00068             angle = M_PI;
00069             rot_matrix = Eigen::AngleAxis<float>(angle, Eigen::Vector3f(0, 1, 0)).toRotationMatrix();
00070         }
00071     }
00072     Eigen::Quaternion<float> quat(rot_matrix);
00073     tf::Quaternion tf_quat(quat.x(), quat.y(), quat.z(), quat.w());
00074     pose.setRotation(tf_quat);
00075     return pose;
00076 
00077 }
00078 
00079 void eigenToTf(const Eigen::Vector3f& origin, const Eigen::Matrix3f& rot_matrix, tf::Pose& pose) {
00080 
00081     pose.setOrigin(tf::Point(origin[0], origin[1], origin[2]));
00082     Eigen::Quaternion<float> quat(rot_matrix);
00083 
00084     tf::Quaternion tf_quat(quat.x(), quat.y(), quat.z(), quat.w());
00085     pose.setRotation(tf_quat);
00086 
00087 }
00088 
00089 SurfacePatch pointNormal2SurfacePatch(const pcl::PointNormal& p1) {
00090     SurfacePatch p2;
00091     p2.x = p1.x;
00092     p2.y = p1.y;
00093     p2.z = p1.z;
00094 
00095     p2.normal_x = p1.x;
00096     p2.normal_y = p1.y;
00097     p2.normal_z = p1.z;
00098 
00099     return p2;
00100 
00101 }
00102 
00103 SurfacePatch point2SurfacePatch(const pcl::PointXYZ& p1) {
00104     SurfacePatch p2;
00105     p2.x = p1.x;
00106     p2.y = p1.y;
00107     p2.z = p1.z;
00108 
00109     p2.normal_x = 0;
00110     p2.normal_y = 0;
00111     p2.normal_z = 1;
00112 
00113     return p2;
00114 
00115 }
00116 
00117 PatchMap::PatchMap() :
00118     first_insert(true), radius_(0.03), ransac_distance_(0.01), ransac_iterations_(50) {
00119 
00120 }
00121 
00122 //std::vector<SurfacePatch>  PatchMap::getMap(){
00123 //    return map_;
00124 //}
00125 //void  PatchMap::setMap(std::vector<SurfacePatch> patches){
00126 //    map_=patches;
00127 //}
00128 void PatchMap::insertScan(pcl::PointCloud<pcl::PointXYZ>& cloud, pcl::PointCloud<pcl::PointXYZ>& not_used_cloud) {
00129     pcl::PointXYZ view_point(0, 0, 0);
00130     insertScan(cloud, not_used_cloud, view_point);
00131 }
00132 void PatchMap::insertScan(pcl::PointCloud<pcl::PointXYZ>& cloud, pcl::PointCloud<pcl::PointXYZ>& not_used_cloud,
00133     pcl::PointXYZ view_point) {
00134 
00135     if (first_insert) {
00136 
00137         //compute patches
00138         computePatchesFromCloud(cloud, view_point, map_, not_used_cloud);
00139 
00140         //get new kdtree for patches
00141         pcl::PointCloud<SurfacePatch> patch_cloud;
00142         patch_cloud.height = 1;
00143         patch_cloud.width = map_.size();
00144         patch_cloud.points.insert(patch_cloud.points.begin(), map_.begin(), map_.end());
00145         tree_.setInputCloud(patch_cloud.makeShared());
00146 
00147         first_insert = false;
00148     } else {
00149 
00150         //compute normals
00151         pcl::PointCloud<pcl::Normal>::Ptr cloud_normals(new pcl::PointCloud<pcl::Normal>);
00152         pcl::NormalEstimation<pcl::PointXYZ, pcl::Normal> ne;
00153         pcl::search::KdTree<pcl::PointXYZ>::Ptr tree(new pcl::search::KdTree<pcl::PointXYZ>());
00154         ne.setViewPoint(view_point.x, view_point.y, view_point.z);
00155         ne.setSearchMethod(tree);
00156         ne.setInputCloud(cloud.makeShared());
00157         ne.setRadiusSearch(radius_);
00158         ne.compute(*cloud_normals);
00159 
00160         //construct pointcloud including the normals
00161         pcl::PointCloud<pcl::PointNormal> pn_cloud;
00162         pcl::concatenateFields(cloud, *cloud_normals, pn_cloud);
00163 
00164         //remove already represented points
00165         pcl::PointCloud<pcl::PointXYZ> tmp_cloud;
00166         for (unsigned int i = 0; i < cloud.size(); ++i) {
00167             if (!pointRepresented(pn_cloud.points[i]))
00168                 tmp_cloud.points.push_back(cloud[i]);
00169         }
00170         tmp_cloud.height = 1;
00171         tmp_cloud.width = tmp_cloud.points.size();
00172 
00173         //compute patches for the rest of the points
00174         std::vector<SurfacePatch> new_patches;
00175         computePatchesFromCloud(tmp_cloud, view_point, new_patches, not_used_cloud);
00176 
00177         //add patches to the current map and pointcloud
00178         map_.insert(map_.end(), new_patches.begin(), new_patches.end());
00179         pcl::PointCloud<SurfacePatch> patch_cloud;
00180         patch_cloud.height = 1;
00181         patch_cloud.width = map_.size();
00182         patch_cloud.points.insert(patch_cloud.points.begin(), map_.begin(), map_.end());
00183 
00184         //update the kdtree for patch searching
00185         tree_.setInputCloud(patch_cloud.makeShared());
00186     }
00187 }
00188 
00189 void PatchMap::computePatchesFromCloud(pcl::PointCloud<pcl::PointXYZ>& cloud, const pcl::PointXYZ view_point,
00190     std::vector<SurfacePatch>& patches, pcl::PointCloud<pcl::PointXYZ>& not_used_cloud) {
00191 
00192     if (cloud.points.size() == 0) {
00193         ROS_ERROR("Pointcloud is empty.");
00194     }
00195 
00196     patches.clear();
00197 
00198     pcl::search::KdTree<pcl::PointXYZ> tree;
00199     tree.setInputCloud(cloud.makeShared());
00200 
00201     std::set<int> usable_indexes;
00202     for (unsigned int i = 0; i < cloud.points.size(); i++) {
00203         usable_indexes.insert(i);
00204     }
00205     std::vector<unsigned int> mask(cloud.points.size(), 0);
00206 
00207     int j = 0;
00208     int pr = 0;
00209     while ((usable_indexes.size() > 0)) {
00210         std::set<int>::iterator it = usable_indexes.begin();
00211         std::advance(it, rand() % usable_indexes.size());
00212         int index = *it;
00213 
00214         std::vector<int> inlier_indices;
00215         std::vector<int> patch_cloud_indices;
00216         std::vector<int> removed_points;
00217         std::vector<int> inlier_mask;
00218         inlier_indices.clear();
00219         patch_cloud_indices.clear();
00220         removed_points.clear();
00221         inlier_mask.clear();
00222 
00223         std::vector<float> dist;
00224         tree.radiusSearch(index, radius_, inlier_indices, dist);
00225 
00226         //build patch cloud
00227         pcl::PointCloud<pcl::PointXYZ> patch_cloud;
00228         for (unsigned int k = 0; k < inlier_indices.size(); ++k) {
00229 //            if (mask[inlier_indices[k]] == 0) {
00230             patch_cloud_indices.push_back(inlier_indices[k]);
00231             inlier_mask.push_back(mask[inlier_indices[k]]);
00232             patch_cloud.points.push_back(cloud.points[inlier_indices[k]]);
00233 //            }
00234         }
00235         patch_cloud.height = 1;
00236         patch_cloud.width = patch_cloud.points.size();
00237 
00238         SurfacePatch patch;
00239         bool flat = false;
00240         if (patch_cloud.points.size() > 2) {
00241             flat = generatePatch(patch_cloud, view_point, cloud.points[index], inlier_mask, patch, removed_points);
00242         }
00243 
00244         if (flat) {
00245 
00246             for (unsigned int i = 0; i < removed_points.size(); ++i) {
00247                 unsigned int removed_point_index = patch_cloud_indices[removed_points[i]];
00248                 mask[removed_point_index] = 1;
00249                 pr++;
00250 
00251                 //remove from set
00252                 it = usable_indexes.find(removed_point_index);
00253                 if (!(it == usable_indexes.end()))
00254                     usable_indexes.erase(it);
00255             }
00256             patches.push_back(patch);
00257         }
00258 
00259         it = usable_indexes.find(index);
00260         if (!(it == usable_indexes.end()))
00261             usable_indexes.erase(it);
00262         ROS_DEBUG_STREAM("PatchMap::computePatchesFromCloud: iteration " << j);
00263         j++;
00264     }
00265 
00266     ROS_DEBUG_STREAM("PatchMap::computePatchesFromCloud: Total points " << cloud.size() << " removed point " << pr);
00267     pcl::PointCloud<SurfacePatch> patch_cloud;
00268     patch_cloud.height = 1;
00269     patch_cloud.width = map_.size();
00270     patch_cloud.points.insert(patch_cloud.points.begin(), patches.begin(), patches.end());
00271     tree_.setInputCloud(patch_cloud.makeShared());
00272 
00273     //collect the points which were not inserted into a patch
00274     not_used_cloud.points.clear();
00275     for (unsigned int i = 0; i < mask.size(); ++i) {
00276         if (mask[i] == 0) {
00277             //try to match outlier point
00278             if (!searchPatchForPoint(cloud.points[i])) {
00279                 not_used_cloud.points.push_back(cloud.points[i]);
00280             }
00281         }
00282     }
00283     not_used_cloud.height = 1;
00284     not_used_cloud.width = not_used_cloud.points.size();
00285 }
00286 
00287 bool PatchMap::pointRepresented(pcl::PointNormal p) {
00288 
00289     bool represented = false;
00290     //search for close patches
00291     std::vector<int> inlier;
00292     std::vector<float> dist;
00293     SurfacePatch tmp = pointNormal2SurfacePatch(p);
00294     tree_.radiusSearch(tmp, radius_, inlier, dist);
00295 
00296     //check if point represented by any inlier patch
00297     for (unsigned int i = 0; i < inlier.size(); ++i) {
00298 
00299         //compute angle-axis representation and compare point normal to patch normal
00300         SurfacePatch patch = map_[inlier[i]];
00301         Eigen::Vector3f patch_normal = patch.getNormalVector3fMap();
00302         Eigen::Vector3f patch_origin = map_[inlier[i]].getVector3fMap();
00303         float angle = acos(patch_normal.normalized().dot(patch_origin.normalized()));
00304         float dist = fabs(patch_normal.dot(patch_origin - p.getVector3fMap()));
00305         if ((dist < ransac_distance_) && (dist < (patch.std_dev_z)) && (angle < M_PI / 6.0)) {
00306             represented = true;
00307         }
00308     }
00309 
00310     return represented;
00311 }
00312 
00313 bool PatchMap::searchPatchForPoint(pcl::PointXYZ p) {
00314 
00315     //search for close patches
00316     std::vector<int> inlier;
00317     std::vector<float> dist;
00318     SurfacePatch tmp = point2SurfacePatch(p);
00319     tree_.radiusSearch(tmp, radius_ * 1.05, inlier, dist);
00320 
00321     //check if point represented by any inlier patch
00322 
00323     for (unsigned int i = 0; i < inlier.size(); ++i) {
00324 
00325         //compute angle-axis representation and compare point normal to patch normal
00326         SurfacePatch patch = map_[inlier[i]];
00327         Eigen::Vector3f patch_normal = patch.getNormalVector3fMap();
00328         Eigen::Vector3f patch_origin = patch.getVector3fMap();
00329 
00330         //compute angle-axis representation
00331         //compute cross product of normal and z-axis
00332         Eigen::Vector3f cross_product = Eigen::Vector3f(0, 0, 1).cross(patch_normal);
00333         Eigen::Matrix3f rot_matrix;
00334         if (cross_product.norm() > 0.000000001) {
00335             float angle = asin(cross_product.norm());
00336             cross_product.normalize();
00337             //get rotation matrix
00338             rot_matrix = Eigen::AngleAxis<float>(angle, cross_product).toRotationMatrix();
00339         } else { //cross product 0 - normal either in or exactly opposite of z-axis
00340             double tmp = patch_normal.dot(Eigen::Vector3f(0, 0, 1));
00341             if (tmp > 0) {
00342                 rot_matrix = Eigen::Matrix3f::Identity();
00343             } else {
00344                 float angle = M_PI;
00345                 rot_matrix = Eigen::AngleAxis<float>(angle, Eigen::Vector3f(0, 1, 0)).toRotationMatrix();
00346             }
00347         }
00348 
00349         float dist = fabs(patch_normal.dot(patch_origin - p.getVector3fMap()));
00350         Eigen::Vector3f new_p = rot_matrix * (p.getVector3fMap() - patch_origin); // U - rotation matrix, U^T is inverse rotation matrix
00351         new_p[2] = 0;
00352         float scale = new_p.norm();
00353 
00354         if ((dist < ransac_distance_) && (scale < 1.05 * radius_)) {
00355 
00356             //set marker scale
00357             if ((scale > map_[inlier[i]].scale_x / 2.0) || (scale > map_[inlier[i]].scale_y / 2.0)) {
00358                 map_[inlier[i]].scale_x = 2 * scale;
00359                 map_[inlier[i]].scale_y = 2 * scale;
00360             }
00361             return true;
00362         }
00363     }
00364 
00365     return false;
00366 }
00367 
00368 bool PatchMap::generatePatch(const pcl::PointCloud<pcl::PointXYZ>& cloud, const pcl::PointXYZ view_point,
00369     const pcl::PointXYZ center, const std::vector<int>& mask, SurfacePatch& patch, std::vector<int>& removed_points) {
00370 
00371     ROS_DEBUG_STREAM("PatchMap::generatePatch: view point " << view_point.getVector3fMap());
00372     removed_points.clear();
00373     Eigen::Vector3f best_plane_normal(0, 0, 0);
00374     Eigen::Vector3f best_plane_p(0, 0, 0);
00375     bool plane_found = false;
00376     double best_plane_d;
00377     best_plane_d = 0;
00378     double best_mse = std::numeric_limits<double>::max();
00379 
00380     for (int iter = 0; iter < ransac_iterations_; iter++) {
00381 
00382         double tmp_mse = 0;
00383 
00384         Eigen::Vector3f p1 = cloud.points[rand() % cloud.points.size()].getVector3fMap();
00385         Eigen::Vector3f p2 = cloud.points[rand() % cloud.points.size()].getVector3fMap();
00386         Eigen::Vector3f p3 = cloud.points[rand() % cloud.points.size()].getVector3fMap();
00387 
00388         if (cloud.points.size() == 3) {
00389             // sample 3 points TODO:check
00390             p1 = cloud.points[0].getVector3fMap();
00391             p2 = cloud.points[1].getVector3fMap();
00392             p3 = cloud.points[2].getVector3fMap();
00393 
00394         }
00395 
00396         if ((p1 == p2) || (p1 == p3) || (p2 == p3))
00397             continue;
00398         // compute plane normal
00399         Eigen::Vector3f plane_normal = (p2 - p1).cross(p3 - p1);
00400         plane_normal.normalize();
00401         float plane_d = plane_normal.dot(p1);
00402 
00403         if (isinf(plane_d) || isnan(plane_d))
00404             continue;
00405 
00406         for (unsigned int i = 0; i < cloud.points.size(); i++) {
00407 
00408             double tmp = fabs(plane_normal.dot(p1 - cloud.points[i].getVector3fMap()));
00409             tmp_mse += (tmp * tmp);
00410         }
00411         if (tmp_mse < best_mse) {
00412             best_plane_normal = plane_normal;
00413             best_plane_d = plane_d;
00414             best_plane_p = p1;
00415             best_mse = tmp_mse;
00416             plane_found = true;
00417         }
00418         if (cloud.points.size() == 3)
00419             break;
00420     }
00421 
00422     if (!plane_found)
00423         return false;
00424 
00425     // recompute model coefficients
00426     //get viewing direction
00427 
00428     Eigen::Vector3f viewing_dir = best_plane_p - view_point.getVector3fMap();
00429     viewing_dir.normalize();
00430     if (best_plane_normal.dot(viewing_dir) > 0) // flip towards viewing direction
00431         best_plane_normal = -best_plane_normal;
00432 
00433     best_plane_normal.normalize();
00434     Eigen::Vector3f cross_product = Eigen::Vector3f(0, 0, 1).cross(best_plane_normal);
00435     Eigen::Matrix3f rot_matrix;
00436     cross_product.normalize();
00437 
00438     float angle = 0;
00439     if (cross_product.norm() > 0.000000001) { //everything ok
00440         angle = acos(best_plane_normal.dot(Eigen::Vector3f(0, 0, 1)));
00441         rot_matrix = Eigen::AngleAxis<float>(angle, cross_product).toRotationMatrix();
00442     } else { //cross product 0 - normal either in or exactly opposite of z-axis
00443         double tmp = best_plane_normal.dot(Eigen::Vector3f(0, 0, 1));
00444         if (tmp > 0) {
00445             rot_matrix = Eigen::Matrix3f::Identity();
00446         } else {
00447             angle = M_PI;
00448             rot_matrix = Eigen::AngleAxis<float>(angle, Eigen::Vector3f(0, 1, 0)).toRotationMatrix();
00449         }
00450     }
00451 
00452     pcl::PointCloud<pcl::PointXYZ> tmp_cloud;
00453 
00454     for (unsigned int i = 0; i < cloud.points.size(); ++i) {
00455 
00456         float dist = fabs(best_plane_normal.dot(best_plane_p - cloud.points[i].getVector3fMap()));
00457         if ((dist < ransac_distance_) && (mask[i] == 0)) {
00458             tmp_cloud.points.push_back(cloud.points[i]);
00459             removed_points.push_back(i);
00460         }
00461     }
00462 
00463     ROS_DEBUG_STREAM("PatchMap::generatePatch: tmp point size " << tmp_cloud.points.size());
00464     if (tmp_cloud.points.size() < 3) {
00465         tmp_cloud.clear();
00466         removed_points.clear();
00467 
00468         for (unsigned int i = 0; i < cloud.points.size(); ++i) {
00469 
00470             float dist = fabs(best_plane_normal.dot(best_plane_p - cloud.points[i].getVector3fMap()));
00471             if ((dist < ransac_distance_)) {
00472                 tmp_cloud.points.push_back(cloud.points[i]);
00473                 removed_points.push_back(i);
00474             }
00475         }
00476         if (tmp_cloud.points.size() < 3) {
00477             removed_points.clear();
00478             return false;
00479         }
00480     }
00481 
00482     tmp_cloud.height = 1;
00483     tmp_cloud.width = tmp_cloud.points.size();
00484 
00485     Eigen::Vector4f centroid;
00486     pcl::compute3DCentroid(tmp_cloud, centroid);
00487 
00488     // Subtract the centroid
00489     Eigen::Vector4f center_in_plane = centroid;
00490     Eigen::MatrixXf cloud_demean;
00491     demeanPointCloud(tmp_cloud, center_in_plane, cloud_demean);
00492 
00493     Eigen::MatrixXf new_points = rot_matrix.transpose() * cloud_demean.topRows(3); // U - rotation matrix, U^T is inverse rotation matrix
00494     new_points.transposeInPlace();
00495     new_points = new_points.array().abs().matrix();
00496 
00497     //set marker scale
00498     double scale = new_points.leftCols(2).rowwise().norm().maxCoeff();
00499 
00500     patch.x = center_in_plane[0];
00501     patch.y = center_in_plane[1];
00502     patch.z = center_in_plane[2];
00503     patch.normal_x = best_plane_normal[0];
00504     patch.normal_y = best_plane_normal[1];
00505     patch.normal_z = best_plane_normal[2];
00506     patch.scale_x = 2 * scale;
00507     patch.scale_y = 2 * scale;
00508     patch.scale_z = 2 * new_points.col(2).maxCoeff();
00509     if (isnan(patch.scale_z) || isinf(patch.scale_z)) {
00510         ROS_WARN_STREAM(
00511             "PatchMap::generatePatch: patch scale in z direction is nan.  " << std::endl <<"new points  coeff " << new_points.col(0).maxCoeff() << " " << new_points.col(1).maxCoeff() << " " << new_points.col(2).maxCoeff());
00512     }
00513 
00514     return true;
00515 }
00516 
00517 void PatchMap::constructMarker(const std::string frame_id, visualization_msgs::MarkerArray& array) {
00518 
00519     array.markers.clear();
00520 
00521     ros::Time marker_time = ros::Time::now() - ros::Duration(0.2);
00522     for (unsigned int i = 0; i < map_.size(); ++i) {
00523         visualization_msgs::Marker marker;
00524         // Set the frame ID and timestamp.  See the TF tutorials for information on these.
00525         marker.header.frame_id = frame_id;
00526         marker.header.stamp = marker_time;
00527 
00528         // Set the namespace and id for this marker.  This serves to create a unique ID
00529         // Any marker sent with the same namespace and id will overwrite the old one
00530         marker.ns = "coverage";
00531         marker.id = i;
00532 
00533         // Set the marker type.  Initially this is CUBE, and cycles between that and SPHERE, ARROW, and CYLINDER
00534         marker.type = visualization_msgs::Marker::CYLINDER;
00535 
00536         // Set the marker action.  Options are ADD and DELETE
00537         marker.action = visualization_msgs::Marker::MODIFY;
00538 
00539         // Set the pose of the marker.  This is a full 6DOF pose relative to the frame/time specified in the header
00540         tf::poseTFToMsg(tfPoseFromPatch(map_[i]), marker.pose);
00541 
00542         if (isnan(marker.pose.position.x) || isnan(marker.pose.position.y) || isnan(marker.pose.position.z)
00543             || isnan(marker.pose.orientation.x) || isnan(marker.scale.x)) {
00544             ROS_WARN_STREAM(
00545                 "PatchMap::constructMarker: something in the pose of the marker is nan. See output below" <<std::endl << map_[i].x << " " << map_[i].y << " " << map_[i].z << " " << map_[i].normal_x << " " << map_[i].normal_y << " " << map_[i].normal_z << " " << map_[i].scale_x << " " << map_[i].scale_y << " " << map_[i].scale_z << " " << map_[i].std_dev_z);
00546         }
00547 
00548         // Set the scale of the marker -- 1x1x1 here means 1m on a side
00549         marker.scale.x = map_[i].scale_x;
00550         marker.scale.y = map_[i].scale_y;
00551         marker.scale.z = map_[i].scale_z;
00552 
00553         // Set the color -- be sure to set alpha to something non-zero!
00554         marker.color.r = 0;
00555         marker.color.g = 0;
00556         marker.color.b = 0.9;
00557         marker.color.a = 0.5;
00558         array.markers.push_back(marker);
00559     }
00560 }
00561 
00562 void PatchMap::constructMarker(const std::string frame_id, const std::vector<bool>& reachable,
00563     visualization_msgs::MarkerArray& array) {
00564 
00565     ROS_ASSERT(reachable.size()==map_.size());
00566     array.markers.clear();
00567 
00568     ros::Time marker_time = ros::Time::now() - ros::Duration(0.2);
00569     for (unsigned int i = 0; i < map_.size(); ++i) {
00570         visualization_msgs::Marker marker;
00571         // Set the frame ID and timestamp.  See the TF tutorials for information on these.
00572         marker.header.frame_id = frame_id;
00573         marker.header.stamp = marker_time;
00574 
00575         // Set the namespace and id for this marker.  This serves to create a unique ID
00576         // Any marker sent with the same namespace and id will overwrite the old one
00577         marker.ns = "coverage";
00578         marker.id = i;
00579 
00580         // Set the marker type.  Initially this is CUBE, and cycles between that and SPHERE, ARROW, and CYLINDER
00581         marker.type = visualization_msgs::Marker::CYLINDER;
00582 
00583         // Set the marker action.  Options are ADD and DELETE
00584         marker.action = visualization_msgs::Marker::MODIFY;
00585 
00586         // Set the pose of the marker.  This is a full 6DOF pose relative to the frame/time specified in the header
00587         tf::poseTFToMsg(tfPoseFromPatch(map_[i]), marker.pose);
00588 
00589         if (isnan(marker.pose.position.x) || isnan(marker.pose.position.y) || isnan(marker.pose.position.z)
00590             || isnan(marker.pose.orientation.x) || isnan(marker.scale.x)) {
00591             ROS_WARN_STREAM(
00592                 "PatchMap::constructMarker: something in the pose of the marker is nan. See output below" <<std::endl << map_[i].x << " " << map_[i].y << " " << map_[i].z << " " << map_[i].normal_x << " " << map_[i].normal_y << " " << map_[i].normal_z << " " << map_[i].scale_x << " " << map_[i].scale_y << " " << map_[i].scale_z << " " << map_[i].std_dev_z);
00593         }
00594 
00595         // Set the scale of the marker -- 1x1x1 here means 1m on a side
00596         marker.scale.x = map_[i].scale_x;
00597         marker.scale.y = map_[i].scale_y;
00598         marker.scale.z = map_[i].scale_z;
00599         // Set the color -- be sure to set alpha to something non-zero!
00600         if (reachable[i]) {
00601             marker.color.r = 0; //(1.0/patches.size())*i;
00602             marker.color.g = 0; //(1.0/patches.size())*i;
00603             marker.color.b = 0.9;
00604         } else {
00605             marker.color.r = 0.7; //(1.0/patches.size())*i;
00606             marker.color.g = 0; //(1.0/patches.size())*i;
00607             marker.color.b = 0;
00608 
00609         }
00610         marker.color.a = 0.7;
00611         array.markers.push_back(marker);
00612     }
00613 }
00614 
00615 void PatchMap::constructMarker(const std::string frame_id, const std::vector<bool>& reachable,
00616     const std::vector<bool>& collision, visualization_msgs::MarkerArray& array) {
00617 
00618     ROS_ASSERT(reachable.size()==map_.size());
00619     array.markers.clear();
00620 
00621     ros::Time marker_time = ros::Time::now() - ros::Duration(0.2);
00622     for (unsigned int i = 0; i < map_.size(); ++i) {
00623         visualization_msgs::Marker marker;
00624         // Set the frame ID and timestamp.  See the TF tutorials for information on these.
00625         marker.header.frame_id = frame_id;
00626         marker.header.stamp = marker_time;
00627 
00628         // Set the namespace and id for this marker.  This serves to create a unique ID
00629         // Any marker sent with the same namespace and id will overwrite the old one
00630         marker.ns = "coverage";
00631         marker.id = i;
00632 
00633         // Set the marker type.  Initially this is CUBE, and cycles between that and SPHERE, ARROW, and CYLINDER
00634         marker.type = visualization_msgs::Marker::CYLINDER;
00635 
00636         // Set the marker action.  Options are ADD and DELETE
00637         marker.action = visualization_msgs::Marker::MODIFY;
00638 
00639         // Set the pose of the marker.  This is a full 6DOF pose relative to the frame/time specified in the header
00640         tf::poseTFToMsg(tfPoseFromPatch(map_[i]), marker.pose);
00641 
00642         if (isnan(marker.pose.position.x) || isnan(marker.pose.position.y) || isnan(marker.pose.position.z)
00643             || isnan(marker.pose.orientation.x) || isnan(marker.scale.x)) {
00644             ROS_WARN_STREAM(
00645                 "PatchMap::constructMarker: something in the pose of the marker is nan. See output below" <<std::endl << map_[i].x << " " << map_[i].y << " " << map_[i].z << " " << map_[i].normal_x << " " << map_[i].normal_y << " " << map_[i].normal_z << " " << map_[i].scale_x << " " << map_[i].scale_y << " " << map_[i].scale_z << " " << map_[i].std_dev_z);
00646         }
00647 
00648         // Set the scale of the marker -- 1x1x1 here means 1m on a side
00649         marker.scale.x = map_[i].scale_x;
00650         marker.scale.y = map_[i].scale_y;
00651         marker.scale.z = map_[i].scale_z;
00652 
00653         // Set the color -- be sure to set alpha to something non-zero!
00654         if (reachable[i]) {
00655             marker.color.r = 0; //(1.0/patches.size())*i;
00656             marker.color.g = 0; //(1.0/patches.size())*i;
00657             marker.color.b = 0.9;
00658         } else if (collision[i]) {
00659             marker.color.r = 0.9; //(1.0/patches.size())*i;
00660             marker.color.g = 0.9; //(1.0/patches.size())*i;
00661             marker.color.b = 0.3;
00662         } else {
00663             marker.color.r = 0.7; //(1.0/patches.size())*i;
00664             marker.color.g = 0; //(1.0/patches.size())*i;
00665             marker.color.b = 0;
00666 
00667         }
00668         marker.color.a = 0.9;
00669         array.markers.push_back(marker);
00670     }
00671 }
00672 
00673 void PatchMap::constructNormalMarker(const std::string frame_id, visualization_msgs::MarkerArray& array) const {
00674 
00675     array.markers.clear();
00676     ros::Time marker_time = ros::Time::now() - ros::Duration(0.2);
00677     for (unsigned int i = 0; i < map_.size(); ++i) {
00678         visualization_msgs::Marker marker;
00679 
00680         // Set the frame ID and timestamp.  See the TF tutorials for information on these.
00681         marker.header.frame_id = frame_id;
00682         marker.header.stamp = marker_time;
00683 
00684         // Set the namespace and id for this marker.  This serves to create a unique ID
00685         // Any marker sent with the same namespace and id will overwrite the old one
00686         marker.ns = "coverage";
00687         marker.id = i;
00688 
00689         // Set the marker type.  Initially this is CUBE, and cycles between that and SPHERE, ARROW, and CYLINDER
00690         marker.type = visualization_msgs::Marker::ARROW;
00691 
00692         // Set the marker action.  Options are ADD and DELETE
00693         marker.action = visualization_msgs::Marker::MODIFY;
00694 
00695         // Set the scale of the marker -- 1x1x1 here means 1m on a side
00696         marker.scale.x = 0.01;
00697         marker.scale.y = 0.01;
00698         marker.scale.z = 0.01;
00699 
00700         // Set the color -- be sure to set alpha to something non-zero!
00701         marker.color.r = 1.0; //(1.0/patches.size())*i;
00702         marker.color.g = 0; //(1.0/patches.size())*i;
00703         marker.color.b = 0;
00704         marker.color.a = 1.0;
00705 
00706         marker.points.clear();
00707 
00708         // Set the pose of the marker.  This is a full 6DOF pose relative to the frame/time specified in the header
00709         geometry_msgs::Point start;
00710         start.x = map_[i].x;
00711         start.y = map_[i].y;
00712         start.z = map_[i].z;
00713 
00714         geometry_msgs::Point end;
00715         end.x = map_[i].x + 0.05 * map_[i].normal_x;
00716         end.y = map_[i].y + 0.05 * map_[i].normal_y;
00717         end.z = map_[i].z + 0.05 * map_[i].normal_z;
00718 
00719         marker.points.push_back(start);
00720         marker.points.push_back(end);
00721         array.markers.push_back(marker);
00722     }
00723 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Properties Friends


surfacelet
Author(s): Juergen Hess
autogenerated on Wed Dec 26 2012 15:24:47