00001
00002
00003
00004
00005
00006
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
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 PatchMap::PatchMap() :
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 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
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 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
00227 pcl::PointCloud<pcl::PointXYZ> patch_cloud;
00228 for (unsigned int k = 0; k < inlier_indices.size(); ++k) {
00229
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
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
00274 not_used_cloud.points.clear();
00275 for (unsigned int i = 0; i < mask.size(); ++i) {
00276 if (mask[i] == 0) {
00277
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
00291 std::vector<int> inlier;
00292 std::vector<float> dist;
00293 SurfacePatch tmp = pointNormal2SurfacePatch(p);
00294 tree_.radiusSearch(tmp, radius_, inlier, dist);
00295
00296
00297 for (unsigned int i = 0; i < inlier.size(); ++i) {
00298
00299
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
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
00322
00323 for (unsigned int i = 0; i < inlier.size(); ++i) {
00324
00325
00326 SurfacePatch patch = map_[inlier[i]];
00327 Eigen::Vector3f patch_normal = patch.getNormalVector3fMap();
00328 Eigen::Vector3f patch_origin = patch.getVector3fMap();
00329
00330
00331
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
00338 rot_matrix = Eigen::AngleAxis<float>(angle, cross_product).toRotationMatrix();
00339 } else {
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);
00351 new_p[2] = 0;
00352 float scale = new_p.norm();
00353
00354 if ((dist < ransac_distance_) && (scale < 1.05 * radius_)) {
00355
00356
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
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
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
00426
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)
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) {
00440 angle = acos(best_plane_normal.dot(Eigen::Vector3f(0, 0, 1)));
00441 rot_matrix = Eigen::AngleAxis<float>(angle, cross_product).toRotationMatrix();
00442 } else {
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
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);
00494 new_points.transposeInPlace();
00495 new_points = new_points.array().abs().matrix();
00496
00497
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
00525 marker.header.frame_id = frame_id;
00526 marker.header.stamp = marker_time;
00527
00528
00529
00530 marker.ns = "coverage";
00531 marker.id = i;
00532
00533
00534 marker.type = visualization_msgs::Marker::CYLINDER;
00535
00536
00537 marker.action = visualization_msgs::Marker::MODIFY;
00538
00539
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
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
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
00572 marker.header.frame_id = frame_id;
00573 marker.header.stamp = marker_time;
00574
00575
00576
00577 marker.ns = "coverage";
00578 marker.id = i;
00579
00580
00581 marker.type = visualization_msgs::Marker::CYLINDER;
00582
00583
00584 marker.action = visualization_msgs::Marker::MODIFY;
00585
00586
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
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
00600 if (reachable[i]) {
00601 marker.color.r = 0;
00602 marker.color.g = 0;
00603 marker.color.b = 0.9;
00604 } else {
00605 marker.color.r = 0.7;
00606 marker.color.g = 0;
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
00625 marker.header.frame_id = frame_id;
00626 marker.header.stamp = marker_time;
00627
00628
00629
00630 marker.ns = "coverage";
00631 marker.id = i;
00632
00633
00634 marker.type = visualization_msgs::Marker::CYLINDER;
00635
00636
00637 marker.action = visualization_msgs::Marker::MODIFY;
00638
00639
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
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
00654 if (reachable[i]) {
00655 marker.color.r = 0;
00656 marker.color.g = 0;
00657 marker.color.b = 0.9;
00658 } else if (collision[i]) {
00659 marker.color.r = 0.9;
00660 marker.color.g = 0.9;
00661 marker.color.b = 0.3;
00662 } else {
00663 marker.color.r = 0.7;
00664 marker.color.g = 0;
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
00681 marker.header.frame_id = frame_id;
00682 marker.header.stamp = marker_time;
00683
00684
00685
00686 marker.ns = "coverage";
00687 marker.id = i;
00688
00689
00690 marker.type = visualization_msgs::Marker::ARROW;
00691
00692
00693 marker.action = visualization_msgs::Marker::MODIFY;
00694
00695
00696 marker.scale.x = 0.01;
00697 marker.scale.y = 0.01;
00698 marker.scale.z = 0.01;
00699
00700
00701 marker.color.r = 1.0;
00702 marker.color.g = 0;
00703 marker.color.b = 0;
00704 marker.color.a = 1.0;
00705
00706 marker.points.clear();
00707
00708
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 }