SubmodMap.cpp
Go to the documentation of this file.
00001 
00002 /*
00003  * SubmodMap.cpp
00004  *
00005  *  Created on: 14.11.2011
00006  *      Author: hess
00007  */
00008 
00009 #include <surfacelet/SubmodMap.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 SubmodMap::SubmodMap() :
00118     first_insert(true), radius_(0.03), ransac_distance_(0.01), ransac_iterations_(50) {
00119 
00120 }
00121 
00122 //std::vector<SurfacePatch>  SubmodMap::getMap(){
00123 //    return map_;
00124 //}
00125 //void  SubmodMap::setMap(std::vector<SurfacePatch> patches){
00126 //    map_=patches;
00127 //}
00128 void SubmodMap::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 SubmodMap::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 SubmodMap::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     std::vector<SurfacePatch> all_patches;
00208     std::vector<std::vector<int> > all_inlier_indices;
00209     std::vector<int> all_inlier_num;
00210 
00211     ROS_INFO("SubmodMap::computePatchesFromCloud: construction all patches");
00212     //construct one patch for each point in the cloud
00213     for (unsigned int i = 0; i < cloud.points.size(); ++i) {
00214 
00215         if ((i%100)==0)  ROS_INFO_STREAM("SubmodMap::computePatchesFromCloud: patch " << i << " of " << cloud.points.size());
00216         //search for nearest neighbors
00217         std::vector<int> inlier_indices;
00218         std::vector<float> dist;
00219         int index=i;
00220         tree.radiusSearch(index, radius_, inlier_indices, dist);
00221 
00222         //build patch cloud
00223         std::vector<int> inlier_mask;
00224         std::vector<int> patch_cloud_indices;
00225         pcl::PointCloud<pcl::PointXYZ> patch_cloud;
00226         for (unsigned int k = 0; k < inlier_indices.size(); ++k) {
00227             patch_cloud_indices.push_back(inlier_indices[k]);
00228             inlier_mask.push_back(mask[inlier_indices[k]]);
00229             patch_cloud.points.push_back(cloud.points[inlier_indices[k]]);
00230         }
00231         patch_cloud.height = 1;
00232         patch_cloud.width = patch_cloud.points.size();
00233 
00234         SurfacePatch patch;
00235         bool flat = false;
00236         std::vector<int> removed_points;
00237         if (patch_cloud.points.size() > 2) {
00238             flat = generatePatch(patch_cloud, view_point, cloud.points[index], inlier_mask, patch, removed_points);
00239         }
00240 
00241         if (flat) {
00242             //save the patch
00243             all_patches.push_back(patch);
00244 
00245             //iterate over all points that are now represented by the patch --> Note: might only be a subset of the inliers from the distance search
00246             std::vector<int> patch_inlier;
00247             for (unsigned int j = 0; j < removed_points.size(); ++j) {
00248                 int removed_point_index = patch_cloud_indices[removed_points[j]];
00249                 patch_inlier.push_back(removed_point_index);
00250             }
00251 
00252             //save the indices to the represented points
00253             all_inlier_indices.push_back(patch_inlier);
00254 
00255             //for convenience save the number of points represented
00256             all_inlier_num.push_back(patch_inlier.size());
00257             if ((i%100)==0)    ROS_INFO_STREAM("SubmodMap::computePatchesFromCloud:inliers" << patch_inlier.size());
00258         }
00259     }
00260 
00261     ROS_INFO("SubmodMap::computePatchesFromCloud: starting patch selection");
00262     //while there are still points not represented
00263     bool done = false; // we are done if there are no more patches left or no more points
00264     int loop_c=0;
00265     while (!done) {
00266 
00267         //find the index of the patch which represents the largest set of points
00268         //Don't you think its odd that there is still no c++ built-in function to determine the index and the language is still alive...
00269         unsigned int max_idx = 0;
00270         int max_val = 0;
00271         for (unsigned int i = 0; i < all_patches.size(); ++i) {
00272             if (all_inlier_num[i] > max_val) {
00273                 max_val = all_inlier_num[i];
00274                 max_idx = i;
00275             }
00276         }
00277 
00278         //save the patch
00279         patches.push_back(all_patches[max_idx]);
00280 
00281         //mark point indices used in the mask
00282         for (unsigned int i = 0; i < all_inlier_indices[max_idx].size(); ++i) {
00283             mask[all_inlier_indices[max_idx][i]]=1;
00284         }
00285 
00286         //delete the patch
00287         all_patches.erase (all_patches.begin()+max_idx);
00288         all_inlier_indices.erase (all_inlier_indices.begin()+max_idx);
00289         all_inlier_num.erase (all_inlier_num.begin()+max_idx);
00290 
00291         //update the points now represented by the rest of the patches
00292         std::vector<int> ind_zero_p;
00293         for (unsigned int i = 0; i < all_patches.size(); ++i) {
00294             int num_p=0;
00295             for (unsigned int j = 0; j < all_inlier_indices[i].size(); ++j) {
00296                 if (mask[all_inlier_indices[i][j]]==0) num_p++;
00297             }
00298             all_inlier_num[i]=num_p;
00299         }
00300 
00301         //done? no more points
00302         done = true;
00303         int mask_p=0;
00304         for (unsigned int i = 0; i < mask.size(); ++i) {
00305             if (mask[i]==0) done =false;
00306             if (mask[i]==1 )mask_p++;
00307         }
00308 
00309         //done? no more patches?
00310         if (all_patches.size()==0) done=true;
00311         loop_c++;
00312 //        if ((loop_c%100)==0)
00313             ROS_INFO_STREAM("SubmodMap::computePatchesFromCloud: patch selection state " << all_patches.size() << " " <<mask_p << " " << max_val << " " <<max_idx);
00314             ROS_INFO_STREAM("SubmodMap::computePatchesFromCloud: patch selection state " << all_inlier_indices.size() << " " << all_inlier_num.size());
00315     }
00316 
00317     pcl::PointCloud<SurfacePatch> patch_cloud;
00318     patch_cloud.height = 1;
00319     patch_cloud.width = map_.size();
00320     patch_cloud.points.insert(patch_cloud.points.begin(), patches.begin(), patches.end());
00321     tree_.setInputCloud(patch_cloud.makeShared());
00322 
00323     //collect the points which were not inserted into a patch
00324     not_used_cloud.points.clear();
00325     for (unsigned int i = 0; i < mask.size(); ++i) {
00326         if (mask[i] == 0) {
00327                 not_used_cloud.points.push_back(cloud.points[i]);
00328         }
00329     }
00330     not_used_cloud.height = 1;
00331     not_used_cloud.width = not_used_cloud.points.size();
00332 }
00333 
00334 bool SubmodMap::pointRepresented(pcl::PointNormal p) {
00335 
00336     bool represented = false;
00337     //search for close patches
00338     std::vector<int> inlier;
00339     std::vector<float> dist;
00340     SurfacePatch tmp = pointNormal2SurfacePatch(p);
00341     tree_.radiusSearch(tmp, radius_, inlier, dist);
00342 
00343     //check if point represented by any inlier patch
00344     for (unsigned int i = 0; i < inlier.size(); ++i) {
00345 
00346         //compute angle-axis representation and compare point normal to patch normal
00347         SurfacePatch patch = map_[inlier[i]];
00348         Eigen::Vector3f patch_normal = patch.getNormalVector3fMap();
00349         Eigen::Vector3f patch_origin = map_[inlier[i]].getVector3fMap();
00350         float angle = acos(patch_normal.normalized().dot(patch_origin.normalized()));
00351         float dist = fabs(patch_normal.dot(patch_origin - p.getVector3fMap()));
00352         if ((dist < ransac_distance_) && (dist < (patch.std_dev_z)) && (angle < M_PI / 6.0)) {
00353             represented = true;
00354         }
00355     }
00356 
00357     return represented;
00358 }
00359 
00360 bool SubmodMap::searchPatchForPoint(pcl::PointXYZ p) {
00361 
00362     //search for close patches
00363     std::vector<int> inlier;
00364     std::vector<float> dist;
00365     SurfacePatch tmp = point2SurfacePatch(p);
00366     tree_.radiusSearch(tmp, radius_ * 1.05, inlier, dist);
00367 
00368     //check if point represented by any inlier patch
00369 
00370     for (unsigned int i = 0; i < inlier.size(); ++i) {
00371 
00372         //compute angle-axis representation and compare point normal to patch normal
00373         SurfacePatch patch = map_[inlier[i]];
00374         Eigen::Vector3f patch_normal = patch.getNormalVector3fMap();
00375         Eigen::Vector3f patch_origin = patch.getVector3fMap();
00376 
00377         //compute angle-axis representation
00378         //compute cross product of normal and z-axis
00379         Eigen::Vector3f cross_product = Eigen::Vector3f(0, 0, 1).cross(patch_normal);
00380         Eigen::Matrix3f rot_matrix;
00381         if (cross_product.norm() > 0.000000001) {
00382             float angle = asin(cross_product.norm());
00383             cross_product.normalize();
00384             //get rotation matrix
00385             rot_matrix = Eigen::AngleAxis<float>(angle, cross_product).toRotationMatrix();
00386         } else { //cross product 0 - normal either in or exactly opposite of z-axis
00387             double tmp = patch_normal.dot(Eigen::Vector3f(0, 0, 1));
00388             if (tmp > 0) {
00389                 rot_matrix = Eigen::Matrix3f::Identity();
00390             } else {
00391                 float angle = M_PI;
00392                 rot_matrix = Eigen::AngleAxis<float>(angle, Eigen::Vector3f(0, 1, 0)).toRotationMatrix();
00393             }
00394         }
00395 
00396         float dist = fabs(patch_normal.dot(patch_origin - p.getVector3fMap()));
00397         Eigen::Vector3f new_p = rot_matrix * (p.getVector3fMap() - patch_origin); // U - rotation matrix, U^T is inverse rotation matrix
00398         new_p[2] = 0;
00399         float scale = new_p.norm();
00400 
00401         if ((dist < ransac_distance_) && (scale < 1.05 * radius_)) {
00402 
00403             //set marker scale
00404             if ((scale > map_[inlier[i]].scale_x / 2.0) || (scale > map_[inlier[i]].scale_y / 2.0)) {
00405                 map_[inlier[i]].scale_x = 2 * scale;
00406                 map_[inlier[i]].scale_y = 2 * scale;
00407             }
00408             return true;
00409         }
00410     }
00411 
00412     return false;
00413 }
00414 
00415 bool SubmodMap::generatePatch(const pcl::PointCloud<pcl::PointXYZ>& cloud, const pcl::PointXYZ view_point,
00416     const pcl::PointXYZ center, const std::vector<int>& mask, SurfacePatch& patch, std::vector<int>& removed_points) {
00417 
00418     ROS_DEBUG_STREAM("SubmodMap::generatePatch: view point " << view_point.getVector3fMap());
00419     removed_points.clear();
00420     Eigen::Vector3f best_plane_normal(0, 0, 0);
00421     Eigen::Vector3f best_plane_p(0, 0, 0);
00422     bool plane_found = false;
00423     double best_plane_d=0;
00424     double best_mse = std::numeric_limits<double>::max();
00425 
00426     for (int iter = 0; iter < ransac_iterations_; iter++) {
00427 
00428         double tmp_mse = 0;
00429 
00430         Eigen::Vector3f p1 = cloud.points[rand() % cloud.points.size()].getVector3fMap();
00431         Eigen::Vector3f p2 = cloud.points[rand() % cloud.points.size()].getVector3fMap();
00432         Eigen::Vector3f p3 = cloud.points[rand() % cloud.points.size()].getVector3fMap();
00433 
00434         if (cloud.points.size() == 3) {
00435             // sample 3 points
00436             p1 = cloud.points[0].getVector3fMap();
00437             p2 = cloud.points[1].getVector3fMap();
00438             p3 = cloud.points[2].getVector3fMap();
00439         }
00440 
00441         if ((p1 == p2) || (p1 == p3) || (p2 == p3))
00442             continue;
00443         // compute plane normal
00444         Eigen::Vector3f plane_normal = (p2 - p1).cross(p3 - p1);
00445         plane_normal.normalize();
00446         float plane_d = plane_normal.dot(p1);
00447 
00448         if (isinf(plane_d) || isnan(plane_d))
00449             continue;
00450 
00451         for (unsigned int i = 0; i < cloud.points.size(); i++) {
00452 
00453             double tmp = fabs(plane_normal.dot(p1 - cloud.points[i].getVector3fMap()));
00454             tmp_mse += (tmp * tmp);
00455         }
00456         if (tmp_mse < best_mse) {
00457             best_plane_normal = plane_normal;
00458             best_plane_d = plane_d;
00459             best_plane_p = p1;
00460             best_mse = tmp_mse;
00461             plane_found = true;
00462         }
00463         if (cloud.points.size() == 3)
00464             break;
00465     }
00466 
00467     if (!plane_found)
00468         return false;
00469 
00470     // recompute model coefficients
00471     //get viewing direction
00472 
00473     Eigen::Vector3f viewing_dir = best_plane_p - view_point.getVector3fMap();
00474     viewing_dir.normalize();
00475     if (best_plane_normal.dot(viewing_dir) > 0) // flip towards viewing direction
00476         best_plane_normal = -best_plane_normal;
00477 
00478     best_plane_normal.normalize();
00479     Eigen::Vector3f cross_product = Eigen::Vector3f(0, 0, 1).cross(best_plane_normal);
00480     Eigen::Matrix3f rot_matrix;
00481     cross_product.normalize();
00482 
00483     float angle = 0;
00484     if (cross_product.norm() > 0.000000001) { //everything ok
00485         angle = acos(best_plane_normal.dot(Eigen::Vector3f(0, 0, 1)));
00486         rot_matrix = Eigen::AngleAxis<float>(angle, cross_product).toRotationMatrix();
00487     } else { //cross product 0 - normal either in or exactly opposite of z-axis
00488         double tmp = best_plane_normal.dot(Eigen::Vector3f(0, 0, 1));
00489         if (tmp > 0) {
00490             rot_matrix = Eigen::Matrix3f::Identity();
00491         } else {
00492             angle = M_PI;
00493             rot_matrix = Eigen::AngleAxis<float>(angle, Eigen::Vector3f(0, 1, 0)).toRotationMatrix();
00494         }
00495     }
00496 
00497     pcl::PointCloud<pcl::PointXYZ> tmp_cloud;
00498 
00499     for (unsigned int i = 0; i < cloud.points.size(); ++i) {
00500 
00501         float dist = fabs(best_plane_normal.dot(best_plane_p - cloud.points[i].getVector3fMap()));
00502         if ((dist < ransac_distance_) && (mask[i] == 0)) {
00503             tmp_cloud.points.push_back(cloud.points[i]);
00504             removed_points.push_back(i);
00505         }
00506     }
00507 
00508     ROS_DEBUG_STREAM("SubmodMap::generatePatch: tmp point size " << tmp_cloud.points.size());
00509     if (tmp_cloud.points.size() < 3) {
00510         tmp_cloud.clear();
00511         removed_points.clear();
00512 
00513         for (unsigned int i = 0; i < cloud.points.size(); ++i) {
00514 
00515             float dist = fabs(best_plane_normal.dot(best_plane_p - cloud.points[i].getVector3fMap()));
00516             if ((dist < ransac_distance_)) {
00517                 tmp_cloud.points.push_back(cloud.points[i]);
00518                 removed_points.push_back(i);
00519             }
00520         }
00521         if (tmp_cloud.points.size() < 3) {
00522             removed_points.clear();
00523             return false;
00524         }
00525     }
00526 
00527     tmp_cloud.height = 1;
00528     tmp_cloud.width = tmp_cloud.points.size();
00529 
00530     Eigen::Vector4f centroid;
00531     pcl::compute3DCentroid(tmp_cloud, centroid);
00532 
00533     // Subtract the centroid
00534     Eigen::Vector4f center_in_plane = centroid;
00535     Eigen::MatrixXf cloud_demean;
00536     demeanPointCloud(tmp_cloud, center_in_plane, cloud_demean);
00537 
00538     Eigen::MatrixXf new_points = rot_matrix.transpose() * cloud_demean.topRows(3); // U - rotation matrix, U^T is inverse rotation matrix
00539     new_points.transposeInPlace();
00540     new_points = new_points.array().abs().matrix();
00541 
00542     //set marker scale
00543     double scale = new_points.leftCols(2).rowwise().norm().maxCoeff();
00544 
00545     patch.x = center_in_plane[0];
00546     patch.y = center_in_plane[1];
00547     patch.z = center_in_plane[2];
00548     patch.normal_x = best_plane_normal[0];
00549     patch.normal_y = best_plane_normal[1];
00550     patch.normal_z = best_plane_normal[2];
00551     patch.scale_x = 2 * scale;
00552     patch.scale_y = 2 * scale;
00553     patch.scale_z = 2 * new_points.col(2).maxCoeff();
00554     if (isnan(patch.scale_z) || isinf(patch.scale_z)) {
00555         ROS_WARN_STREAM(
00556             "SubmodMap::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());
00557     }
00558 
00559     return true;
00560 }
00561 
00562 void SubmodMap::constructMarker(const std::string frame_id, visualization_msgs::MarkerArray& array) {
00563 
00564     array.markers.clear();
00565 
00566     ros::Time marker_time = ros::Time::now() - ros::Duration(0.2);
00567     for (unsigned int i = 0; i < map_.size(); ++i) {
00568         visualization_msgs::Marker marker;
00569         // Set the frame ID and timestamp.  See the TF tutorials for information on these.
00570         marker.header.frame_id = frame_id;
00571         marker.header.stamp = marker_time;
00572 
00573         // Set the namespace and id for this marker.  This serves to create a unique ID
00574         // Any marker sent with the same namespace and id will overwrite the old one
00575         marker.ns = "coverage";
00576         marker.id = i;
00577 
00578         // Set the marker type.  Initially this is CUBE, and cycles between that and SPHERE, ARROW, and CYLINDER
00579         marker.type = visualization_msgs::Marker::CYLINDER;
00580 
00581         // Set the marker action.  Options are ADD and DELETE
00582         marker.action = visualization_msgs::Marker::MODIFY;
00583 
00584         // Set the pose of the marker.  This is a full 6DOF pose relative to the frame/time specified in the header
00585         tf::poseTFToMsg(tfPoseFromPatch(map_[i]), marker.pose);
00586 
00587         if (isnan(marker.pose.position.x) || isnan(marker.pose.position.y) || isnan(marker.pose.position.z)
00588             || isnan(marker.pose.orientation.x) || isnan(marker.scale.x)) {
00589             ROS_WARN_STREAM(
00590                 "SubmodMap::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);
00591         }
00592 
00593         // Set the scale of the marker -- 1x1x1 here means 1m on a side
00594         marker.scale.x = map_[i].scale_x;
00595         marker.scale.y = map_[i].scale_y;
00596         marker.scale.z = map_[i].scale_z;
00597 
00598         // Set the color -- be sure to set alpha to something non-zero!
00599         marker.color.r = 1;
00600         marker.color.g=std::fabs(1.0 - ((double) i / (double) map_.size()));
00601         marker.color.b=std::fabs(1.0 - ((double) i / (double) map_.size()));
00602         marker.color.a = 0.8;
00603         array.markers.push_back(marker);
00604     }
00605 }
00606 
00607 void SubmodMap::constructMarker(const std::string frame_id, const std::vector<bool>& reachable,
00608     visualization_msgs::MarkerArray& array) {
00609 
00610     ROS_ASSERT(reachable.size()==map_.size());
00611     array.markers.clear();
00612 
00613     ros::Time marker_time = ros::Time::now() - ros::Duration(0.2);
00614     for (unsigned int i = 0; i < map_.size(); ++i) {
00615         visualization_msgs::Marker marker;
00616         // Set the frame ID and timestamp.  See the TF tutorials for information on these.
00617         marker.header.frame_id = frame_id;
00618         marker.header.stamp = marker_time;
00619 
00620         // Set the namespace and id for this marker.  This serves to create a unique ID
00621         // Any marker sent with the same namespace and id will overwrite the old one
00622         marker.ns = "coverage";
00623         marker.id = i;
00624 
00625         // Set the marker type.  Initially this is CUBE, and cycles between that and SPHERE, ARROW, and CYLINDER
00626         marker.type = visualization_msgs::Marker::CYLINDER;
00627 
00628         // Set the marker action.  Options are ADD and DELETE
00629         marker.action = visualization_msgs::Marker::MODIFY;
00630 
00631         // Set the pose of the marker.  This is a full 6DOF pose relative to the frame/time specified in the header
00632         tf::poseTFToMsg(tfPoseFromPatch(map_[i]), marker.pose);
00633 
00634         if (isnan(marker.pose.position.x) || isnan(marker.pose.position.y) || isnan(marker.pose.position.z)
00635             || isnan(marker.pose.orientation.x) || isnan(marker.scale.x)) {
00636             ROS_WARN_STREAM(
00637                 "SubmodMap::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);
00638         }
00639 
00640         // Set the scale of the marker -- 1x1x1 here means 1m on a side
00641         marker.scale.x = map_[i].scale_x;
00642         marker.scale.y = map_[i].scale_y;
00643         marker.scale.z = map_[i].scale_z;
00644         // Set the color -- be sure to set alpha to something non-zero!
00645         if (reachable[i]) {
00646             marker.color.r = 0; //(1.0/patches.size())*i;
00647             marker.color.g = 0; //(1.0/patches.size())*i;
00648             marker.color.b = 0.9;
00649         } else {
00650             marker.color.r = 0.7; //(1.0/patches.size())*i;
00651             marker.color.g = 0; //(1.0/patches.size())*i;
00652             marker.color.b = 0;
00653 
00654         }
00655         marker.color.a = 0.7;
00656         array.markers.push_back(marker);
00657     }
00658 }
00659 
00660 void SubmodMap::constructMarker(const std::string frame_id, const std::vector<bool>& reachable,
00661     const std::vector<bool>& collision, visualization_msgs::MarkerArray& array) {
00662 
00663     ROS_ASSERT(reachable.size()==map_.size());
00664     array.markers.clear();
00665 
00666     ros::Time marker_time = ros::Time::now() - ros::Duration(0.2);
00667     for (unsigned int i = 0; i < map_.size(); ++i) {
00668         visualization_msgs::Marker marker;
00669         // Set the frame ID and timestamp.  See the TF tutorials for information on these.
00670         marker.header.frame_id = frame_id;
00671         marker.header.stamp = marker_time;
00672 
00673         // Set the namespace and id for this marker.  This serves to create a unique ID
00674         // Any marker sent with the same namespace and id will overwrite the old one
00675         marker.ns = "coverage";
00676         marker.id = i;
00677 
00678         // Set the marker type.  Initially this is CUBE, and cycles between that and SPHERE, ARROW, and CYLINDER
00679         marker.type = visualization_msgs::Marker::CYLINDER;
00680 
00681         // Set the marker action.  Options are ADD and DELETE
00682         marker.action = visualization_msgs::Marker::MODIFY;
00683 
00684         // Set the pose of the marker.  This is a full 6DOF pose relative to the frame/time specified in the header
00685         tf::poseTFToMsg(tfPoseFromPatch(map_[i]), marker.pose);
00686 
00687         if (isnan(marker.pose.position.x) || isnan(marker.pose.position.y) || isnan(marker.pose.position.z)
00688             || isnan(marker.pose.orientation.x) || isnan(marker.scale.x)) {
00689             ROS_WARN_STREAM(
00690                 "SubmodMap::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);
00691         }
00692 
00693         // Set the scale of the marker -- 1x1x1 here means 1m on a side
00694         marker.scale.x = map_[i].scale_x;
00695         marker.scale.y = map_[i].scale_y;
00696         marker.scale.z = map_[i].scale_z;
00697 
00698         // Set the color -- be sure to set alpha to something non-zero!
00699         if (reachable[i]) {
00700             marker.color.r = 0; //(1.0/patches.size())*i;
00701             marker.color.g = 0; //(1.0/patches.size())*i;
00702             marker.color.b = 0.9;
00703         } else if (collision[i]) {
00704             marker.color.r = 0.9; //(1.0/patches.size())*i;
00705             marker.color.g = 0.9; //(1.0/patches.size())*i;
00706             marker.color.b = 0.3;
00707         } else {
00708             marker.color.r = 0.7; //(1.0/patches.size())*i;
00709             marker.color.g = 0; //(1.0/patches.size())*i;
00710             marker.color.b = 0;
00711 
00712         }
00713         marker.color.a = 0.9;
00714         array.markers.push_back(marker);
00715     }
00716 }
00717 
00718 void SubmodMap::constructNormalMarker(const std::string frame_id, visualization_msgs::MarkerArray& array) const {
00719 
00720     array.markers.clear();
00721     ros::Time marker_time = ros::Time::now() - ros::Duration(0.2);
00722     for (unsigned int i = 0; i < map_.size(); ++i) {
00723         visualization_msgs::Marker marker;
00724 
00725         // Set the frame ID and timestamp.  See the TF tutorials for information on these.
00726         marker.header.frame_id = frame_id;
00727         marker.header.stamp = marker_time;
00728 
00729         // Set the namespace and id for this marker.  This serves to create a unique ID
00730         // Any marker sent with the same namespace and id will overwrite the old one
00731         marker.ns = "coverage";
00732         marker.id = i;
00733 
00734         // Set the marker type.  Initially this is CUBE, and cycles between that and SPHERE, ARROW, and CYLINDER
00735         marker.type = visualization_msgs::Marker::ARROW;
00736 
00737         // Set the marker action.  Options are ADD and DELETE
00738         marker.action = visualization_msgs::Marker::MODIFY;
00739 
00740         // Set the scale of the marker -- 1x1x1 here means 1m on a side
00741         marker.scale.x = 0.01;
00742         marker.scale.y = 0.01;
00743         marker.scale.z = 0.01;
00744 
00745         // Set the color -- be sure to set alpha to something non-zero!
00746         marker.color.r = 1.0; //(1.0/patches.size())*i;
00747         marker.color.g = 0; //(1.0/patches.size())*i;
00748         marker.color.b = 0;
00749         marker.color.a = 1.0;
00750 
00751         marker.points.clear();
00752 
00753         // Set the pose of the marker.  This is a full 6DOF pose relative to the frame/time specified in the header
00754         geometry_msgs::Point start;
00755         start.x = map_[i].x;
00756         start.y = map_[i].y;
00757         start.z = map_[i].z;
00758 
00759         geometry_msgs::Point end;
00760         end.x = map_[i].x + 0.05 * map_[i].normal_x;
00761         end.y = map_[i].y + 0.05 * map_[i].normal_y;
00762         end.z = map_[i].z + 0.05 * map_[i].normal_z;
00763 
00764         marker.points.push_back(start);
00765         marker.points.push_back(end);
00766         array.markers.push_back(marker);
00767     }
00768 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Properties Friends


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