NeigborhoodGraph.cpp
Go to the documentation of this file.
00001 
00002 #include <coverage_3d_planning/NeighborhoodGraph.h>
00003 #include <coverage_3d_tools/conversions.h>
00004 #include <coverage_3d_arm_navigation/openrave_ik.h>
00005 #include <eigen3/Eigen/src/Core/EigenBase.h>
00006 #include <eigen3/Eigen/src/Geometry/Quaternion.h>
00007 #include <pcl/kdtree/kdtree_flann.h>
00008 
00009 #include <tf/tf.h>
00010 #include <voro/voro++.hh>
00011 
00012 NeighborhoodGraph::NeighborhoodGraph(ros::NodeHandle& nh) :
00013                 nh_(nh), dist_above_surface_(0.06), max_neigborhood_(8), max_neigborhood_radius_(0.08), octomap_(0), coll_checker_(
00014                                 0), n_ik_samples_(1), coll_check_(true) {
00015         if (coll_check_) {
00016                 coll_checker_ = new CollisionCheck(nh_);
00017         }
00018 }
00019 NeighborhoodGraph::NeighborhoodGraph(ros::NodeHandle& nh, bool coll_check) :
00020                 nh_(nh), dist_above_surface_(0.06), max_neigborhood_(8), max_neigborhood_radius_(0.08), octomap_(0), coll_checker_(
00021                                 0), n_ik_samples_(1), coll_check_(coll_check) {
00022         if (coll_check_) {
00023                 coll_checker_ = new CollisionCheck(nh_);
00024         }
00025 }
00026 
00027 NeighborhoodGraph::NeighborhoodGraph(ros::NodeHandle& nh, std::vector<SurfacePatch> patches,
00028                 octomap::OctomapROS<octomap::OcTree>* octomap) :
00029                 nh_(nh), dist_above_surface_(0.06), max_neigborhood_(8), max_neigborhood_radius_(0.08), octomap_(0), coll_checker_(
00030                                 0), n_ik_samples_(1), coll_check_(true) {
00031         surface_ = patches;
00032         octomap_ = octomap;
00033         if (coll_check_) {
00034                 coll_checker_ = new CollisionCheck(nh_);
00035         }
00036 }
00037 
00038 NeighborhoodGraph::NeighborhoodGraph(ros::NodeHandle& nh, std::vector<SurfacePatch> patches,
00039                 octomap::OctomapROS<octomap::OcTree>* octomap, double dist_above_surface, int max_neigborhood,
00040                 double max_neigborhood_radius, int n_ik_samples, bool coll_check) :
00041                 nh_(nh), dist_above_surface_(dist_above_surface), max_neigborhood_(max_neigborhood), max_neigborhood_radius_(
00042                                 max_neigborhood_radius), octomap_(0), coll_checker_(0), n_ik_samples_(n_ik_samples), coll_check_(
00043                                 coll_check) {
00044         surface_ = patches;
00045         octomap_ = octomap;
00046         if (coll_check_) {
00047                 coll_checker_ = new CollisionCheck(nh_);
00048         }
00049 }
00050 
00051 NeighborhoodGraph::~NeighborhoodGraph() {
00052         if (coll_check_) {
00053                 delete coll_checker_;
00054         }
00055         //      delete octomap_;
00056 }
00057 void NeighborhoodGraph::setPatches(std::vector<SurfacePatch> patches) {
00058         surface_ = patches;
00059 }
00060 void NeighborhoodGraph::setSurfaceDist(double dist) {
00061         dist_above_surface_ = dist;
00062 }
00063 
00064 void NeighborhoodGraph::setOctomap(octomap::OctomapROS<octomap::OcTree>* octomap) {
00065         octomap_ = octomap;
00066 }
00067 
00068 void NeighborhoodGraph::getReachableVector(std::vector<bool>& reachable) {
00069         reachable = reachable_surface_;
00070 }
00071 void NeighborhoodGraph::sampleSurfacePoints(const std::vector<SurfacePatch>& surface,
00072                 std::vector<pcl::PointXYZ>& samples) const {
00073 
00074         samples.clear();
00075         float dist = dist_above_surface_;
00076 
00077         for (unsigned int i = 0; i < surface.size(); ++i) {
00078                 //compute point above surface
00079                 SurfacePatch patch = surface[i];
00080                 Eigen::Vector3f tmp = patch.getVector3fMap() + (dist * patch.getNormalVector3fMap().normalized());
00081                 tmp = tmp + ((patch.scale_z / 2.0) * patch.getNormalVector3fMap().normalized());
00082                 samples.push_back(VectorEigen2PointXYZ(tmp));
00083         }
00084 }
00085 void NeighborhoodGraph::sampleSurfacePoints(const std::vector<SurfacePatch>& surface,
00086                 pcl::PointCloud<pcl::PointXYZ>& samples) const {
00087 
00088         samples.clear();
00089         float dist = dist_above_surface_;
00090 
00091         for (unsigned int i = 0; i < surface.size(); ++i) {
00092                 //compute point above surface
00093                 SurfacePatch patch = surface[i];
00094                 Eigen::Vector3f tmp = patch.getVector3fMap() + (dist * patch.getNormalVector3fMap().normalized());
00095                 tmp = tmp + ((patch.scale_z / 2.0) * patch.getNormalVector3fMap().normalized());
00096                 samples.push_back(VectorEigen2PointXYZ(tmp));
00097         }
00098 }
00099 void NeighborhoodGraph::buildAdjacencyMatrixUsingOctomap() {
00100 
00101         //build the graph
00102         ROS_INFO_STREAM("NeighborhoodGraph Computing Adjacency Matrix from " << surface_.size() << "patches");
00103         
00104         pcl::PointCloud<pcl::PointXYZ> samples;
00105         sampleSurfacePoints(surface_, samples);
00106         octomap::Pointcloud octocloud;
00107         octomap::pointcloudPCLToOctomap(samples, octocloud);
00108 
00109         pcl::KdTreeFLANN<pcl::PointXYZ> tree;
00110         tree.setInputCloud(samples.makeShared());
00111 
00112         adjacency_ = Eigen::MatrixXi::Zero(octocloud.size(), octocloud.size());
00113         ROS_DEBUG_STREAM("NeighborhoodGraph::buildAdjacencyMatrixUsingOctomap " << octocloud.size() << " " << samples.size());
00114         ROS_DEBUG_STREAM("NeighborhoodGraph::buildAdjacencyMatrixUsingOctomap max neighborhood " << max_neigborhood_ << " " << max_neigborhood_radius_);
00115         omp_set_num_threads(6);
00116         for (unsigned int i = 0; i < octocloud.size(); ++i) {
00117                 std::vector<int> inlier;
00118                 std::vector<float> dist;
00119                 tree.radiusSearch(samples[i], max_neigborhood_radius_, inlier, dist);
00120 
00121                 //use a maximum of inliers
00122                 unsigned int n_inliers = max_neigborhood_;
00123                 if (inlier.size() < n_inliers) {
00124                         n_inliers = inlier.size();
00125                 }
00126 #pragma omp parallel for
00127                 for (unsigned int j = 0; j < n_inliers; ++j) {
00128                         octomap::point3d origin = octocloud.getPoint(i);
00129                         octomap::point3d end = octocloud.getPoint(inlier[j]);
00130                         octomap::point3d dir = end - origin;
00131                         if (i != (unsigned int) inlier[j]) {
00132                                 float dist = dir.norm();
00133                                 //                              if (dist != 0) {
00134 
00135                                 if (!octomap_->octree.castRay(origin, dir, end, false, dist)) {
00136                                         if (octomap_->octree.search(end)) { //if search did not end in an unknown cell
00137                                                 adjacency_(i, inlier[j]) = 1;
00138                                                 adjacency_(inlier[j], i) = 1;
00139                                         }
00140                                 }
00141                                 //                              }
00142                         }
00143                 }
00144         }
00145         std::cout << "size Surface Adjacency Matrix " << surface_.size() << " " << adjacency_.rows() << " "
00146                         << adjacency_.cols() << std::endl;
00147 }
00148 
00149 void NeighborhoodGraph::buildAdjacencyMatrixUsingVoronoi() {
00150 
00151         //build the graph
00152         std::cout << "Computing Adjacency Matrix using Voronoi Graph" << surface_.size() << std::endl;
00153 
00154         pcl::PointCloud<pcl::PointXYZ> samples;
00155         sampleSurfacePoints(surface_, samples);
00156         octomap::Pointcloud octocloud;
00157         octomap::pointcloudPCLToOctomap(samples, octocloud);
00158 
00159         Eigen::MatrixXf e_samples = samples.getMatrixXfMap();
00160         adjacency_ = Eigen::MatrixXi::Zero(surface_.size(), surface_.size());
00161 
00162         //get the size of the box holding the voronoi graph
00163         //make the box a little larger so that it also contains the points at the edge of the box
00164         double x_min = e_samples.row(0).array().minCoeff() - 0.001;
00165         double x_max = e_samples.row(0).array().maxCoeff() + 0.001;
00166         double y_min = e_samples.row(1).array().minCoeff() - 0.001;
00167         double y_max = e_samples.row(1).array().maxCoeff() + 0.001;
00168         double z_min = e_samples.row(2).array().minCoeff() - 0.001;
00169         double z_max = e_samples.row(2).array().maxCoeff() + 0.001;
00170 
00171         //set the number of computational units along x,y and z axis
00172         int n_x = 1, n_y = 1, n_z = 1;
00173 
00174         //construct the voro++ container
00175         voro::container con(x_min, x_max, y_min, y_max, z_min, z_max, n_x, n_y, n_z, false, false, false, 10000);
00176 
00177         //insert the surface points in the container
00178         for (unsigned int i = 0; i < e_samples.cols(); i++) {
00179                 con.put(i, e_samples(0, i), e_samples(1, i), e_samples(2, i));
00180         }
00181 
00182         //loop over all voronoi cells while computing the voronoi cells and their neighbors
00183         voro::c_loop_all vl(con); //weird looping construct
00184         voro::voronoicell_neighbor c;
00185         if (vl.start())
00186                 do
00187                         if (con.compute_cell(c, vl)) {
00188                                 int idx1 = con.id[vl.ijk][vl.q]; // getting the id of the previously inserted point --> a bit tricky
00189                                 int idx2 = 0;
00190                                 std::vector<int> local_neighbors;
00191                                 c.neighbors(local_neighbors);
00192                                 for (unsigned int j = 0; j < local_neighbors.size(); ++j) {
00193 
00194                                         // in case local_neighbors[j]<0 the neighbor is a side of the container
00195                                         if (local_neighbors[j] >= 0) {
00196                                                 idx2 = local_neighbors[j];
00197                                                 octomap::point3d origin = octocloud.getPoint(idx1);
00198                                                 octomap::point3d end = octocloud.getPoint(idx2);
00199                                                 octomap::point3d dir = end - origin;
00200                                                 float dist = dir.norm();
00201                                                 //check if we can cast a ray between the corressponding nodes in the octomap
00202                                                 if (!octomap_->octree.castRay(origin, dir, end, false, dist)) {
00203                                                         //if search did not end in an unknown cell
00204                                                         if (octomap_->octree.search(end)) {
00205                                                                 if (dist < 0.5) {
00206                                                                         adjacency_(idx1, idx2) = 1;
00207                                                                         adjacency_(idx2, idx1) = 1;
00208                                                                 }
00209                                                         }
00210                                                 }
00211                                         }
00212                                 }
00213                         } while (vl.inc());
00214 
00215 //    // Sum up the volumes, and check that this matches the container volume
00216 //    const double cvol = (x_max - x_min) * (y_max - y_min) * (z_max * z_min);
00217 //    double vvol = con.sum_cell_volumes();
00218 //    printf("Container volume : %g\n"
00219 //        "Voronoi volume   : %g\n"
00220 //        "Difference       : %g\n", cvol, vvol, vvol - cvol);
00221 //    // Output the particle positions in gnuplot format
00222 //    con.draw_particles("random_points_p.gnu");
00223 //    // Output the Voronoi cells in gnuplot format
00224 //    con.draw_cells_gnuplot("random_points_v.gnu");
00225 
00226 }
00227 bool NeighborhoodGraph::isPoseValid(const tf::Pose pose, const bool check_collision,
00228                 std::vector<std::vector<double> >& ik_solutions) {
00229 
00230 
00231         ik_solutions.clear();
00232         std::vector<std::vector<double> > solutions;
00233         getIKSolutions(pose, solutions);
00234 
00235         if (solutions.size() > 0) {
00236 
00237                 //if we shall check for collision also
00238                 for (unsigned int j = 0; j < solutions.size(); ++j) {
00239                         if (check_collision) {
00240                                 if (coll_checker_->checkJointStateRight(solutions[j])) {
00241                                         ik_solutions.push_back(solutions[j]);
00242                                 }
00243                         } else {
00244                                 ik_solutions.push_back(solutions[j]);
00245                         }
00246                 }
00247         }
00248         if (ik_solutions.size() > 0) {
00249                 return true;
00250         } else {
00251                 return false;
00252         }
00253 }
00254 
00255 void NeighborhoodGraph::getValidIKSolutions(const std::vector<tf::Pose>& poses, const bool check_collision,
00256                 std::vector<bool>& valid, std::vector<std::vector<std::vector<double> > >& ik_solutions) {
00257 
00258         valid.resize(poses.size(), false);
00259         ik_solutions.resize(poses.size());
00260 
00261         for (unsigned int i = 0; i < poses.size(); ++i) {
00262                 std::vector<std::vector<double> > tmp_solutions;
00263                 if (isPoseValid(poses[i], check_collision, tmp_solutions)) {
00264                         valid[i] = true;
00265                         ik_solutions[i] = tmp_solutions;
00266                 }
00267         }
00268 }
00269 
00270 void NeighborhoodGraph::depthFirstConnectedComponentSearch(const int node, Eigen::MatrixXi& adjacency,
00271                 std::set<int>& graph) {
00272 
00273         graph.insert(node);
00274         for (int i = 0; i < adjacency.cols(); ++i) {
00275                 if (adjacency(node, i) == 1) {
00276                         adjacency(node, i) = 0;
00277                         depthFirstConnectedComponentSearch(i, adjacency, graph);
00278                 }
00279         }
00280 }
00281 void NeighborhoodGraph::computeConnectedComponents() {
00282         subgraphs_.clear();
00283 
00284         std::set<int> usable_indexes;
00285         for (unsigned int i = 0; i < adjacency_.rows(); i++) {
00286                 usable_indexes.insert(i);
00287         }
00288         Eigen::MatrixXi tmp = adjacency_;
00289 
00290         std::set<int> tmp_set;
00291         while (usable_indexes.size() > 0) {
00292 
00293                 //sample point from set
00294                 std::set<int>::iterator it = usable_indexes.begin();
00295                 std::advance(it, rand() % usable_indexes.size());
00296                 int index = *it;
00297 
00298                 depthFirstConnectedComponentSearch(index, tmp, tmp_set);
00299 
00300                 //check connectivity for the index
00301                 BOOST_FOREACH(int i, tmp_set)
00302                                 {
00303                                         //remove from set
00304                                         it = usable_indexes.find(i);
00305                                         if (!(it == usable_indexes.end()))
00306                                                 usable_indexes.erase(it);
00307                                 }
00308                 if (tmp_set.size() > 1) {
00309                         subgraphs_.push_back(tmp_set);
00310                 }
00311         }
00312 }
00313 
00314 void NeighborhoodGraph::getSubgraphAdjacency(const std::set<int>& subgraph, std::map<int, int>& index_map,
00315 Eigen::MatrixXi& subgraph_adj, const std::vector<SurfacePatch>& patches,
00316 std::vector<SurfacePatch>& subgraph_patches) {
00317 
00318         index_map.clear();
00319         subgraph_patches.clear();
00320         subgraph_adj = Eigen::MatrixXi::Zero(subgraph.size(), subgraph.size());
00321         int k = 0, l = 0;
00322         BOOST_FOREACH(int i, subgraph)
00323                         {
00324                                 l = 0;
00325                                 index_map.insert(std::pair<int, int>(k, i));
00326                                 BOOST_FOREACH(int j, subgraph)
00327                                                 {
00328                                                         subgraph_adj(k, l) = adjacency_(i, j);
00329 
00330                                                         l++;
00331                                                 }
00332                                 subgraph_patches.push_back(patches[i]);
00333                                 k++;
00334                         }
00335 }
00336 
00337 void NeighborhoodGraph::getIKSolutions(const tf::Pose p, std::vector<std::vector<double> >& ik_solutions) const {
00338         ik_solutions.clear();
00339         int n_free_joints = 1;
00340         int n_joints = 7;
00341 
00342         double vfree[n_free_joints]; //we have one free parameter
00343         double eerot[9], eetrans[3];
00344 
00345         tf::Matrix3x3 rot = p.getBasis();
00346         tf::Vector3 trans = p.getOrigin();
00347 
00348         eerot[0] = rot[0][0];
00349         eerot[1] = rot[0][1];
00350         eerot[2] = rot[0][2];
00351         eerot[3] = rot[1][0];
00352         eerot[4] = rot[1][1];
00353         eerot[5] = rot[1][2];
00354         eerot[6] = rot[2][0];
00355         eerot[7] = rot[2][1];
00356         eerot[8] = rot[2][2];
00357 
00358         eetrans[0] = trans[0];
00359         eetrans[1] = trans[1];
00360         eetrans[2] = trans[2];
00361 
00362         //set the free parameters -- in range -pi -- pi: for right now use the middle: 0
00363         //free joint limits of r_upper_arm_roll_joint (29) in openrave are -3.9 and 0.79
00364         //good setting: vfree[0] =-1.51;
00365 
00366         std::vector<float> vfree_samples;
00367         if (n_ik_samples_ == 1) {
00368                 vfree_samples.push_back(-1.51);
00369         } else if (n_ik_samples_ == 2) {
00370                 vfree_samples.push_back(-1.75);
00371                 vfree_samples.push_back(-1.27);
00372         } else if (n_ik_samples_ == 3) {
00373                 vfree_samples.push_back(-1.51);
00374                 vfree_samples.push_back(-1.75);
00375                 vfree_samples.push_back(-1.27);
00376         } else if (n_ik_samples_ == 5) {
00377                 vfree_samples.push_back(-1.51);
00378                 vfree_samples.push_back(-1.75);
00379                 vfree_samples.push_back(-1.27);
00380                 vfree_samples.push_back(-1.03);
00381                 vfree_samples.push_back(-1.99);
00382         } else if (n_ik_samples_ == 9) {
00383                 vfree_samples.push_back(-1.51);
00384                 vfree_samples.push_back(-1.75);
00385                 vfree_samples.push_back(-1.27);
00386                 vfree_samples.push_back(-1.03);
00387                 vfree_samples.push_back(-1.99);
00388                 vfree_samples.push_back(-2.23);
00389                 vfree_samples.push_back(-0.79);
00390                 vfree_samples.push_back(-2.46);
00391                 vfree_samples.push_back(-0.55);
00392         } else if (n_ik_samples_ == 10) {
00393                 float min = -3.7; //-3.9 but we want to stay away from limits
00394                 float max = 0.6;
00395                 float max_samples = 20;
00396                 float dist = (max - min) / max_samples;
00397                 for (float i = -3.7; i < 0.6001; i = i + dist) {
00398                         vfree_samples.push_back(i);
00399                 }
00400         } else if (n_ik_samples_ == 11) {
00401                 float min = -3.7; //-3.9 but we want to stay away from limits
00402                 float max = 0.6;
00403                 float max_samples = 50;
00404                 float dist = (max - min) / max_samples;
00405                 for (float i = -3.7; i < 0.6001; i = i + dist) {
00406                         vfree_samples.push_back(i);
00407                 }
00408         } else if (n_ik_samples_ == 12) {
00409                 float min = -3.7; //-3.9 but we want to stay away from limits
00410                 float max = 0.6;
00411                 float max_samples = 100;
00412                 float dist = (max - min) / max_samples;
00413                 for (float i = -3.7; i < 0.6001; i = i + dist) {
00414                         vfree_samples.push_back(i);
00415                 }
00416         } else {
00417                 ROS_ERROR("not supported sample number");
00418         }
00419 
00420         for (unsigned int i = 0; i < vfree_samples.size(); ++i) {
00421 
00422                 vfree[0] = vfree_samples[i];
00423                 std::vector<IKSolution> vsolutions;
00424                 ik(eetrans, eerot, vfree, vsolutions); //get the ik solutions
00425 
00426                 //    ROS_INFO("Found %d ik solutions:\n", (int) vsolutions.size());
00427                 std::vector<double> sol(n_joints);
00428                 for (std::size_t i = 0; i < vsolutions.size(); ++i) {
00429                         std::vector<double> vsolfree(vsolutions[i].GetFree().size());
00430                         vsolutions[i].GetSolution(&sol[0], vsolfree.size() > 0 ? &vsolfree[0] : NULL);
00431                         ik_solutions.push_back(sol);
00432                 }
00433         }
00434 
00435 }
00436 
00437 // for a single pose we sample end-effector rotations
00438 void NeighborhoodGraph::computeEndEffectorPose(const SurfacePatch p1, const double dist_above_surface,
00439                 std::vector<tf::Pose>& poses, bool single_pose) const {
00440 
00441         poses.clear();
00442         //compute point above surface
00443         Eigen::Vector3f origin = p1.getVector3fMap() + (dist_above_surface * p1.getNormalVector3fMap().normalized())
00444                         + ((p1.scale_z / 2.0) * p1.getNormalVector3fMap().normalized());
00445 
00446         //set x_axis to point to surface
00447         Eigen::Vector3f z_axis = p1.getVector3fMap() - origin;
00448         z_axis.normalize();
00449 
00450         //compute angle-axis representation
00451         //compute cross product of normal and z-axis and get the rotation with smallest angle
00452         //cross product is the rotation axis with smallest angle
00453         Eigen::Vector3f cross_product = Eigen::Vector3f(0, 0, 1).cross(z_axis);
00454         Eigen::Matrix3f rot_matrix;
00455         cross_product.normalize();
00456         float angle = 0;
00457         if (cross_product.norm() > 0.000000001) { //everything ok
00458                 angle = acos(z_axis.dot(Eigen::Vector3f(0, 0, 1)));
00459                 rot_matrix = Eigen::AngleAxis<float>(angle, cross_product).toRotationMatrix();
00460         } else { //cross product 0 - normal either in or exactly opposite of z-axis
00461                 double tmp = z_axis.dot(Eigen::Vector3f(0, 0, 1));
00462                 if (tmp > 0) {
00463                         rot_matrix = Eigen::Matrix3f::Identity();
00464                 } else {
00465                         angle = M_PI;
00466                         rot_matrix = Eigen::AngleAxis<float>(angle, cross_product).toRotationMatrix();
00467                 }
00468         }
00469 
00470         //set everything into the pose
00471         tf::Pose pose;
00472         pose.setOrigin(tf::Point(origin[0], origin[1], origin[2]));
00473         Eigen::Quaternion<float> quat(rot_matrix);
00474         tf::Quaternion tf_quat(quat.x(), quat.y(), quat.z(), quat.w());
00475         pose.setRotation(tf_quat);
00476         poses.push_back(pose);
00477 
00478         if (!single_pose) {
00479 
00480                 angle = M_PI / 8.0;
00481                 rot_matrix = Eigen::AngleAxis<float>(angle, Eigen::Vector3f(0, 0, 1)).toRotationMatrix();
00482                 quat = Eigen::Quaternion<float>(rot_matrix);
00483                 tf_quat = tf::Quaternion(quat.x(), quat.y(), quat.z(), quat.w());
00484                 pose.setRotation(tf_quat);
00485                 poses.push_back(pose);
00486 
00487                 angle = M_PI / 4.0;
00488                 rot_matrix = Eigen::AngleAxis<float>(angle, Eigen::Vector3f(0, 0, 1)).toRotationMatrix();
00489                 quat = Eigen::Quaternion<float>(rot_matrix);
00490                 tf_quat = tf::Quaternion(quat.x(), quat.y(), quat.z(), quat.w());
00491                 pose.setRotation(tf_quat);
00492                 poses.push_back(pose);
00493         }
00494 }
00495 
00496 void NeighborhoodGraph::computeEndEffectorPose(const SurfacePatch p1, const SurfacePatch p2,
00497                 const double dist_above_surface, tf::Pose& pose) const {
00498 
00499         //compute point above surface
00500         Eigen::Vector3f origin = p1.getVector3fMap() + (dist_above_surface * p1.getNormalVector3fMap().normalized())
00501                         + ((p1.scale_z / 2.0) * p1.getNormalVector3fMap().normalized());
00502 
00503         //set x_axis to point to surface
00504         Eigen::Vector3f z_axis = p1.getVector3fMap() - origin;
00505         z_axis.normalize();
00506 
00507         //compute angle-axis representation
00508         //compute cross product of normal and z-axis and get the rotation with smallest angle
00509         //cross product is the rotation axis with smallest angle
00510         Eigen::Vector3f cross_product = Eigen::Vector3f(0, 0, 1).cross(z_axis);
00511         Eigen::Matrix3f rot_matrix;
00512         cross_product.normalize();
00513         float angle = 0;
00514         if (cross_product.norm() > 0.000000001) { //everything ok
00515                 angle = acos(z_axis.dot(Eigen::Vector3f(0, 0, 1)));
00516                 rot_matrix = Eigen::AngleAxis<float>(angle, cross_product).toRotationMatrix();
00517         } else { //cross product 0 - normal either in or exactly opposite of z-axis
00518                 double tmp = z_axis.dot(Eigen::Vector3f(0, 0, 1));
00519                 if (tmp > 0) {
00520                         rot_matrix = Eigen::Matrix3f::Identity();
00521                 } else {
00522                         angle = M_PI;
00523                         rot_matrix = Eigen::AngleAxis<float>(angle, cross_product).toRotationMatrix();
00524                 }
00525         }
00526 
00527         //apply transform to next patch
00528         Eigen::Vector3f origin_next = p2.getVector3fMap() + (dist_above_surface * p2.getNormalVector3fMap().normalized())
00529                         + ((p2.scale_z / 2.0) * p2.getNormalVector3fMap().normalized());
00530 
00531         origin_next = rot_matrix.transpose() * (origin_next - origin);
00532         origin_next[2] = 0;
00533         origin_next.normalize();
00534         Eigen::Vector3f align_axis = (origin_next);
00535         Eigen::Vector3f x_axis = Eigen::Vector3f(0, 1, 0);
00536         cross_product = x_axis.cross(align_axis);
00537         cross_product.normalize();
00538 
00539         Eigen::Matrix3f rot_matrix2;
00540         angle = 0;
00541         if (cross_product.norm() > 0.000000001) { //everything ok
00542                 angle = acos(align_axis.dot(x_axis));
00543 
00544                 rot_matrix2 = Eigen::AngleAxis<float>(angle, cross_product).toRotationMatrix();
00545         } else { //cross product 0 - normal either in or exactly opposite of z-axis
00546                 double tmp = align_axis.dot(x_axis);
00547                 if (tmp > 0) {
00548                         rot_matrix2 = Eigen::Matrix3f::Identity();
00549                 } else {
00550                         angle = M_PI;
00551                         rot_matrix2 = Eigen::AngleAxis<float>(angle, cross_product).toRotationMatrix();
00552                 }
00553         }
00554 
00555         //set everything into the pose
00556         pose.setOrigin(tf::Point(origin[0], origin[1], origin[2]));
00557         Eigen::Quaternion<float> quat(rot_matrix * rot_matrix2);
00558         tf::Quaternion tf_quat(quat.x(), quat.y(), quat.z(), quat.w());
00559         pose.setRotation(tf_quat);
00560         
00561         //check if quaternion is normalized
00562         if (fabs(tf_quat.length2() - 1) > tf::QUATERNION_TOLERANCE) {
00563                 ROS_WARN_STREAM(
00564                                 "TF to MSG: Quaternion Not Properly Normalized" << tf_quat.x() << " "<< tf_quat.y() <<" " << tf_quat.z() << " "<<tf_quat.w());
00565                 ROS_WARN_STREAM("MATRIX " << rot_matrix << std::endl << rot_matrix2);
00566         }
00567 }
00568 
00569 void NeighborhoodGraph::getGraph(std::vector<SurfacePatch>& patches, std::vector<pcl::PointXYZ>&surface_points,
00570                 Eigen::MatrixXi& adjacency, std::vector<std::vector<tf::Pose> >&coll_free_poses,
00571                 std::vector<std::vector<std::vector<std::vector<double> > > >& coll_free_ik) {
00572 
00573         patches.clear();
00574         surface_points.clear();
00575         coll_free_poses.clear();
00576         coll_free_ik.clear();
00577 
00578         reachable_surface_.resize(surface_.size(), false);
00579 
00580         std::vector<pcl::PointXYZ> samples;
00581         sampleSurfacePoints(surface_, samples);
00582 
00583         //build the adjacency matrix by checking for octomap freeness
00584         buildAdjacencyMatrixUsingOctomap();
00585 
00586         std::map<int, int> old_to_new_indexes;
00587         std::vector<std::pair<int, int> > new_adj_pairs_old_index;
00588 
00589         //revise adjacency matrix using reachability
00590         for (unsigned int i = 0; i < adjacency_.rows(); ++i) {
00591 
00592                 //get possible Cartesian poses for each patch
00593 
00594                 int n_edges = adjacency_.row(i).array().sum(); //the current number of edges
00595 
00596                 if (n_edges == 0) {
00597                         //                      std::vector<tf::Pose> patch_poses;
00598                         //                      computeEndEffectorPose(surface_[i], dist_above_surface_, patch_poses);
00599                         //
00600                         //                      //get inverse kinematic solutions and check for collisions
00601                         //                      std::vector<bool> valid;
00602                         //                      std::vector<std::vector<std::vector<double> > > ik_solutions;
00603                         //                      getValidIKSolutions(patch_poses, true, valid, ik_solutions);
00604                         //
00605                         //                      std::vector<tf::Pose> valid_poses;
00606                         //                      std::vector<std::vector<std::vector<double> > > valid_ik_solutions;
00607                         //                      for (unsigned int j = 0; j < patch_poses.size(); ++j) {
00608                         //
00609                         //                              //if the pose is valid fill in all the stuff we need
00610                         //                              if (valid[j]) {
00611                         //                                      valid_poses.push_back(patch_poses[j]);
00612                         //                                      valid_ik_solutions.push_back(ik_solutions[j]); // get all solutions for a single pose
00613                         //                              }
00614                         //                      }
00615                         //                      //if
00616                         //                      if (valid_poses.size() > 0) {
00617                         //                              reachable_surface_[i] = true;
00618                         //                              patches.push_back(surface_[i]);
00619                         //                              surface_points.push_back(samples[i]);
00620                         //                              coll_free_poses.push_back(valid_poses);
00621                         //                              coll_free_ik.push_back(valid_ik_solutions);
00622                         //                              old_to_new_indexes.insert(std::pair<int, int>(i, patches.size() - 1));
00623                         //                      }
00624                 } else {
00625 
00626                         std::vector<tf::Pose> valid_poses;
00627                         std::vector<std::vector<std::vector<double> > > valid_ik_solutions;
00628 
00629                         for (int j = 0; j < adjacency_.cols(); ++j) {
00630                                 if (adjacency_(i, j) == 1) { // if the nodes are adjacent
00631                                         if (adjacency_(i, j) != 1) {
00632                                                 std::cout << "error 2" << std::endl;
00633                                         }
00634                                         tf::Pose tmp_pose;
00635                                         computeEndEffectorPose(surface_[i], surface_[j], dist_above_surface_, tmp_pose);
00636                                         std::vector<tf::Pose> patch_poses;
00637                                         patch_poses.push_back(tmp_pose);
00638                                         geometry_msgs::Pose geom_pose;
00639                                         tf::poseTFToMsg(tmp_pose, geom_pose);
00640                                         //get inverse kinematic solutions and check for collisions
00641                                         std::vector<bool> valid;
00642                                         std::vector<std::vector<std::vector<double> > > ik_solutions;
00643                                         getValidIKSolutions(patch_poses, true, valid, ik_solutions);
00644 
00645                                         tf::Pose tmp_pose2;
00646                                         computeEndEffectorPose(surface_[j], surface_[i], dist_above_surface_, tmp_pose2);
00647                                         std::vector<tf::Pose> patch_poses2;
00648                                         patch_poses2.push_back(tmp_pose2);
00649 
00650                                         //get inverse kinematic solutions and check for collisions
00651                                         std::vector<bool> valid2;
00652                                         std::vector<std::vector<std::vector<double> > > ik_solutions2;
00653                                         getValidIKSolutions(patch_poses2, true, valid2, ik_solutions2);
00654 
00655                                         if (valid[0] && valid2[0]) {
00656                                                 valid_poses.push_back(tmp_pose);
00657                                                 valid_ik_solutions.push_back(ik_solutions[0]); // get all solutions for a single pose
00658                                                 new_adj_pairs_old_index.push_back(std::pair<int, int>(i, j));
00659                                         }
00660                                 }
00661                         }
00662                         if (valid_poses.size() > 0) {
00663                                 reachable_surface_[i] = true;
00664                                 patches.push_back(surface_[i]);
00665                                 surface_points.push_back(samples[i]);
00666                                 coll_free_poses.push_back(valid_poses);
00667                                 coll_free_ik.push_back(valid_ik_solutions);
00668                                 old_to_new_indexes.insert(std::pair<int, int>(i, patches.size() - 1));
00669 
00670                         }
00671 
00672                 }
00673 
00674         }
00675 
00676         //construct new adjacency matrix
00677         adjacency = Eigen::MatrixXi::Zero(patches.size(), patches.size());
00678         int errors = 0;
00679         for (unsigned int i = 0; i < new_adj_pairs_old_index.size(); ++i) {
00680                 std::pair<int, int> tmp = new_adj_pairs_old_index[i];
00681                 //find new index to old ones
00682                 std::map<int, int>::iterator it_ind1 = old_to_new_indexes.find(tmp.first);
00683                 std::map<int, int>::iterator it_ind2 = old_to_new_indexes.find(tmp.second);
00684 
00685                 //if new indexes for both old ones the edge exists
00686 
00687                 if (!(it_ind1 == old_to_new_indexes.end() || it_ind2 == old_to_new_indexes.end())) {
00688                         adjacency((*it_ind1).second, (*it_ind2).second) = 1;
00689                 } else {
00690                         errors++;
00691                         std::cout << "error" << " " << errors << " " << tmp.first << " " << tmp.second << " " << (*it_ind1).second
00692                                         << " " << (*it_ind2).second << std::endl;
00693                 }
00694         }
00695 
00696 }
00697 
00698 void NeighborhoodGraph::constructGraphMarker(const std::vector<pcl::PointXYZ>& surface_samples,
00699                 const Eigen::MatrixXi& adjacency, const std::string frame_id, visualization_msgs::Marker& marker) const {
00700 
00701         marker.points.clear();
00702 
00703         // Set the frame ID and timestamp.  See the TF tutorials for information on these.
00704         marker.header.frame_id = frame_id;
00705         marker.header.stamp = ros::Time::now();
00706 
00707         // Set the namespace and id for this marker.  This serves to create a unique ID
00708         // Any marker sent with the same namespace and id will overwrite the old one
00709         marker.ns = "coverage";
00710 
00711         // Set the marker type.  Initially this is CUBE, and cycles between that and SPHERE, ARROW, and CYLINDER
00712         marker.type = visualization_msgs::Marker::LINE_LIST;
00713 
00714         // Set the marker action.  Options are ADD and DELETE
00715         marker.action = visualization_msgs::Marker::MODIFY;
00716 
00717         // Set the scale of the marker -- 1x1x1 here means 1m on a side
00718         marker.scale.x = 0.005;
00719         marker.scale.y = 0.005;
00720         marker.scale.z = 0.005;
00721 
00722         // Set the color -- be sure to set alpha to something non-zero!
00723         marker.color.a = 1.0;
00724         marker.color.g = 1.0;
00725 
00726         geometry_msgs::Point start;
00727         geometry_msgs::Point end;
00728         marker.points.clear();
00729 
00730         for (unsigned int i = 0; i < surface_samples.size(); ++i) {
00731 
00732                 for (unsigned int j = 0; j < surface_samples.size(); ++j) {
00733                         if (!(i == j) && (adjacency(i, j) == 1)) {
00734                                 start.x = surface_samples[i].x;
00735                                 start.y = surface_samples[i].y;
00736                                 start.z = surface_samples[i].z;
00737                                 end.x = surface_samples[j].x;
00738                                 end.y = surface_samples[j].y;
00739                                 end.z = surface_samples[j].z;
00740 
00741                                 marker.points.push_back(start);
00742                                 marker.points.push_back(end);
00743                         }
00744                 }
00745         }
00746 
00747 }
00748 void NeighborhoodGraph::constructGraphMarker(const std::vector<SurfacePatch>& surface, const Eigen::MatrixXi& adjacency,
00749                 const std::string frame_id, visualization_msgs::Marker& marker) const {
00750 
00751         std::vector<pcl::PointXYZ> samples;
00752         sampleSurfacePoints(surface, samples);
00753         constructGraphMarker(samples, adjacency, frame_id, marker);
00754 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Properties Friends


coverage_3d_planning
Author(s): Juergen Hess
autogenerated on Wed Dec 26 2012 15:26:11