00001
00002
00003
00004
00005
00006
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
00052
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) {
00061 angle = acos(patch_normal.dot(Eigen::Vector3f(0, 0, 1)));
00062 rot_matrix = Eigen::AngleAxis<float>(angle, cross_product).toRotationMatrix();
00063 } else {
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
00123
00124
00125
00126
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
00138 computePatchesFromCloud(cloud, view_point, map_, not_used_cloud);
00139
00140
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
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
00161 pcl::PointCloud<pcl::PointNormal> pn_cloud;
00162 pcl::concatenateFields(cloud, *cloud_normals, pn_cloud);
00163
00164
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
00174 std::vector<SurfacePatch> new_patches;
00175 computePatchesFromCloud(tmp_cloud, view_point, new_patches, not_used_cloud);
00176
00177
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
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
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
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
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
00243 all_patches.push_back(patch);
00244
00245
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
00253 all_inlier_indices.push_back(patch_inlier);
00254
00255
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
00263 bool done = false;
00264 int loop_c=0;
00265 while (!done) {
00266
00267
00268
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
00279 patches.push_back(all_patches[max_idx]);
00280
00281
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
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
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
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
00310 if (all_patches.size()==0) done=true;
00311 loop_c++;
00312
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
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
00338 std::vector<int> inlier;
00339 std::vector<float> dist;
00340 SurfacePatch tmp = pointNormal2SurfacePatch(p);
00341 tree_.radiusSearch(tmp, radius_, inlier, dist);
00342
00343
00344 for (unsigned int i = 0; i < inlier.size(); ++i) {
00345
00346
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
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
00369
00370 for (unsigned int i = 0; i < inlier.size(); ++i) {
00371
00372
00373 SurfacePatch patch = map_[inlier[i]];
00374 Eigen::Vector3f patch_normal = patch.getNormalVector3fMap();
00375 Eigen::Vector3f patch_origin = patch.getVector3fMap();
00376
00377
00378
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
00385 rot_matrix = Eigen::AngleAxis<float>(angle, cross_product).toRotationMatrix();
00386 } else {
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);
00398 new_p[2] = 0;
00399 float scale = new_p.norm();
00400
00401 if ((dist < ransac_distance_) && (scale < 1.05 * radius_)) {
00402
00403
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
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
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
00471
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)
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) {
00485 angle = acos(best_plane_normal.dot(Eigen::Vector3f(0, 0, 1)));
00486 rot_matrix = Eigen::AngleAxis<float>(angle, cross_product).toRotationMatrix();
00487 } else {
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
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);
00539 new_points.transposeInPlace();
00540 new_points = new_points.array().abs().matrix();
00541
00542
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
00570 marker.header.frame_id = frame_id;
00571 marker.header.stamp = marker_time;
00572
00573
00574
00575 marker.ns = "coverage";
00576 marker.id = i;
00577
00578
00579 marker.type = visualization_msgs::Marker::CYLINDER;
00580
00581
00582 marker.action = visualization_msgs::Marker::MODIFY;
00583
00584
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
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
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
00617 marker.header.frame_id = frame_id;
00618 marker.header.stamp = marker_time;
00619
00620
00621
00622 marker.ns = "coverage";
00623 marker.id = i;
00624
00625
00626 marker.type = visualization_msgs::Marker::CYLINDER;
00627
00628
00629 marker.action = visualization_msgs::Marker::MODIFY;
00630
00631
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
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
00645 if (reachable[i]) {
00646 marker.color.r = 0;
00647 marker.color.g = 0;
00648 marker.color.b = 0.9;
00649 } else {
00650 marker.color.r = 0.7;
00651 marker.color.g = 0;
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
00670 marker.header.frame_id = frame_id;
00671 marker.header.stamp = marker_time;
00672
00673
00674
00675 marker.ns = "coverage";
00676 marker.id = i;
00677
00678
00679 marker.type = visualization_msgs::Marker::CYLINDER;
00680
00681
00682 marker.action = visualization_msgs::Marker::MODIFY;
00683
00684
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
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
00699 if (reachable[i]) {
00700 marker.color.r = 0;
00701 marker.color.g = 0;
00702 marker.color.b = 0.9;
00703 } else if (collision[i]) {
00704 marker.color.r = 0.9;
00705 marker.color.g = 0.9;
00706 marker.color.b = 0.3;
00707 } else {
00708 marker.color.r = 0.7;
00709 marker.color.g = 0;
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
00726 marker.header.frame_id = frame_id;
00727 marker.header.stamp = marker_time;
00728
00729
00730
00731 marker.ns = "coverage";
00732 marker.id = i;
00733
00734
00735 marker.type = visualization_msgs::Marker::ARROW;
00736
00737
00738 marker.action = visualization_msgs::Marker::MODIFY;
00739
00740
00741 marker.scale.x = 0.01;
00742 marker.scale.y = 0.01;
00743 marker.scale.z = 0.01;
00744
00745
00746 marker.color.r = 1.0;
00747 marker.color.g = 0;
00748 marker.color.b = 0;
00749 marker.color.a = 1.0;
00750
00751 marker.points.clear();
00752
00753
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 }