Point Cloud Library (PCL)  1.5.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines
grid_projection.hpp
Go to the documentation of this file.
00001 /*
00002  * Software License Agreement (BSD License)
00003  *
00004  *  Copyright (c) 2010, Willow Garage, Inc.
00005  *  All rights reserved.
00006  *
00007  *  Redistribution and use in source and binary forms, with or without
00008  *  modification, are permitted provided that the following conditions
00009  *  are met:
00010  *
00011  *   * Redistributions of source code must retain the above copyright
00012  *     notice, this list of conditions and the following disclaimer.
00013  *   * Redistributions in binary form must reproduce the above
00014  *     copyright notice, this list of conditions and the following
00015  *     disclaimer in the documentation and/or other materials provided
00016  *     with the distribution.
00017  *   * Neither the name of Willow Garage, Inc. nor the names of its
00018  *     contributors may be used to endorse or promote products derived
00019  *     from this software without specific prior written permission.
00020  *
00021  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00022  *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00023  *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00024  *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
00025  *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00026  *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00027  *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00028  *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00029  *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00030  *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
00031  *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00032  *  POSSIBILITY OF SUCH DAMAGE.
00033  *
00034  * $Id: grid_projection.hpp 4702 2012-02-23 09:39:33Z gedikli $
00035  *
00036  */
00037 
00038 #ifndef PCL_SURFACE_IMPL_GRID_PROJECTION_H_
00039 #define PCL_SURFACE_IMPL_GRID_PROJECTION_H_
00040 
00041 #include "pcl/surface/grid_projection.h"
00042 #include <pcl/common/common.h>
00043 #include <pcl/common/centroid.h>
00044 #include <pcl/common/vector_average.h>
00045 #include <pcl/Vertices.h>
00046 
00048 template <typename PointNT>
00049 pcl::GridProjection<PointNT>::GridProjection () :
00050   leaf_size_(0.001), data_size_(0), max_binary_search_level_(10), k_(50), padding_size_(3), data_()
00051 {}
00052 
00054 template <typename PointNT>
00055 pcl::GridProjection<PointNT>::GridProjection (double resolution) :
00056   leaf_size_(resolution), data_size_(0), max_binary_search_level_(10), k_(50), padding_size_(3), data_()
00057 {}
00058 
00060 template <typename PointNT>
00061 pcl::GridProjection<PointNT>::~GridProjection ()
00062 {
00063   vector_at_data_point_.clear ();
00064   surface_.clear ();;
00065   cell_hash_map_.clear ();
00066   occupied_cell_list_.clear ();
00067   data_.reset ();
00068 }
00069 
00071 template <typename PointNT> void
00072 pcl::GridProjection<PointNT>::scaleInputDataPoint (double scale_factor)
00073 {
00074   for (size_t i = 0; i < data_->points.size(); ++i)
00075     data_->points[i].getVector4fMap () /= scale_factor;
00076   max_p_ /=  scale_factor;
00077   min_p_ /= scale_factor;
00078 }
00079 
00081 template <typename PointNT> void
00082 pcl::GridProjection<PointNT>::getBoundingBox ()
00083 {
00084   pcl::getMinMax3D (*data_, min_p_, max_p_);
00085 
00086   Eigen::Vector4f bounding_box_size = max_p_ - min_p_;
00087   double scale_factor = (std::max)((std::max)(bounding_box_size.x (),
00088                                               bounding_box_size.y ()),
00089                                               bounding_box_size.z ());
00090   if (scale_factor > 1)
00091     scaleInputDataPoint (scale_factor);
00092 
00093   // Round the max_p_, min_p_ so that they are aligned with the cells vertices
00094   int upper_right_index[3];
00095   int lower_left_index[3];
00096   for (size_t i = 0; i < 3; ++i)
00097   {
00098     upper_right_index[i] = max_p_(i) / leaf_size_ + 5;
00099     lower_left_index[i] = min_p_(i) / leaf_size_ - 5;
00100     max_p_(i) = upper_right_index[i] * leaf_size_;
00101     min_p_(i) = lower_left_index[i] * leaf_size_;
00102   }
00103   bounding_box_size = max_p_ - min_p_;
00104   PCL_DEBUG ("[pcl::GridProjection::getBoundingBox] Size of Bounding Box is [%f, %f, %f]\n",
00105       bounding_box_size.x (), bounding_box_size.y (), bounding_box_size.z ());
00106   double max_size =
00107     (std::max) ((std::max)(bounding_box_size.x (), bounding_box_size.y ()),
00108                 bounding_box_size.z ());
00109 
00110   data_size_ = max_size / leaf_size_;
00111   PCL_DEBUG ("[pcl::GridProjection::getBoundingBox] Lower left point is [%f, %f, %f]\n",
00112       min_p_.x (), min_p_.y (), min_p_.z ());
00113   PCL_DEBUG ("[pcl::GridProjection::getBoundingBox] Upper left point is [%f, %f, %f]\n",
00114       max_p_.x (), max_p_.y (), max_p_.z ());
00115   PCL_DEBUG ("[pcl::GridProjection::getBoundingBox] Padding size: %d\n", padding_size_);
00116   PCL_DEBUG ("[pcl::GridProjection::getBoundingBox] Leaf size: %f\n", leaf_size_);
00117   occupied_cell_list_.resize (data_size_ * data_size_ * data_size_);
00118   gaussian_scale_ = pow ((padding_size_+1) * leaf_size_ / 2.0, 2.0);
00119 }
00120 
00122 template <typename PointNT> void
00123 pcl::GridProjection<PointNT>::getVertexFromCellCenter (
00124     const Eigen::Vector4f &cell_center,
00125     std::vector<Eigen::Vector4f, Eigen::aligned_allocator<Eigen::Vector4f> > &pts) const
00126 {
00127   assert (pts.size () == 8);
00128 
00129   float sz = leaf_size_ / 2.0;
00130 
00131   pts[0] = cell_center + Eigen::Vector4f (-sz,  sz, -sz, 0);
00132   pts[1] = cell_center + Eigen::Vector4f (-sz, -sz, -sz, 0);
00133   pts[2] = cell_center + Eigen::Vector4f (sz,  -sz, -sz, 0);
00134   pts[3] = cell_center + Eigen::Vector4f (sz,   sz, -sz, 0);
00135   pts[4] = cell_center + Eigen::Vector4f (-sz,  sz,  sz, 0);
00136   pts[5] = cell_center + Eigen::Vector4f (-sz, -sz,  sz, 0);
00137   pts[6] = cell_center + Eigen::Vector4f (sz,  -sz,  sz, 0);
00138   pts[7] = cell_center + Eigen::Vector4f (sz,   sz,  sz, 0);
00139 }
00140 
00142 template <typename PointNT> void
00143 pcl::GridProjection<PointNT>::getDataPtsUnion (const Eigen::Vector3i &index,
00144                                                std::vector <int> &pt_union_indices)
00145 {
00146   for (int i = index[0] - padding_size_; i <= index[0] + padding_size_; ++i)
00147   {
00148     for (int j = index[1] - padding_size_; j <= index[1] + padding_size_; ++j)
00149     {
00150       for (int k = index[2] - padding_size_; k <= index[2] + padding_size_; ++k)
00151       {
00152         Eigen::Vector3i cell_index_3d (i, j, k);
00153         int cell_index_1d = getIndexIn1D (cell_index_3d);
00154         if (cell_hash_map_.find (cell_index_1d) != cell_hash_map_.end ())
00155         {
00156           // Get the indices of the input points within the cell(i,j,k), which
00157           // is stored in the hash map
00158           pt_union_indices.insert (pt_union_indices.end (),
00159                                    cell_hash_map_.at (cell_index_1d).data_indices.begin (),
00160                                    cell_hash_map_.at (cell_index_1d).data_indices.end ());
00161         }
00162       }
00163     }
00164   }
00165 }
00166 
00168 template <typename PointNT> void
00169 pcl::GridProjection<PointNT>::createSurfaceForCell (const Eigen::Vector3i &index,
00170                                                     std::vector <int> &pt_union_indices)
00171 {
00172   // 8 vertices of the cell
00173   std::vector<Eigen::Vector4f, Eigen::aligned_allocator<Eigen::Vector4f> > vertices (8);
00174 
00175   // 4 end points that shared by 3 edges connecting the upper left front points
00176   Eigen::Vector4f pts[4];
00177   Eigen::Vector3f vector_at_pts[4];
00178 
00179   // Given the index of cell, caluate the coordinates of the eight vertices of the cell
00180   // index the index of the cell in (x,y,z) 3d format
00181   Eigen::Vector4f cell_center = Eigen::Vector4f::Zero ();
00182   getCellCenterFromIndex (index, cell_center);
00183   getVertexFromCellCenter (cell_center, vertices);
00184 
00185   // Get the indices of the cells which stores the 4 end points.
00186   Eigen::Vector3i indices[4];
00187   indices[0] = Eigen::Vector3i (index[0], index[1], index[2] - 1);
00188   indices[1] = Eigen::Vector3i (index[0], index[1], index[2]);
00189   indices[2] = Eigen::Vector3i (index[0], index[1] - 1, index[2]);
00190   indices[3] = Eigen::Vector3i (index[0] + 1, index[1], index[2]);
00191 
00192   // Get the coordinate of the 4 end points, and the corresponding vectors
00193   for (size_t i = 0; i < 4; ++i)
00194   {
00195     pts[i] = vertices[I_SHIFT_PT[i]];
00196     unsigned int index_1d = getIndexIn1D (indices[i]);
00197     if (cell_hash_map_.find (index_1d) == cell_hash_map_.end () ||
00198         occupied_cell_list_[index_1d] == 0)
00199       return;
00200     else
00201       vector_at_pts[i] = cell_hash_map_.at (index_1d).vect_at_grid_pt;
00202   }
00203 
00204   // Go through the 3 edges, test whether they are intersected by the surface
00205   for (size_t i = 0; i < 3; ++i)
00206   {
00207     std::vector<Eigen::Vector4f, Eigen::aligned_allocator<Eigen::Vector4f> > end_pts (2);
00208     std::vector<Eigen::Vector3f, Eigen::aligned_allocator<Eigen::Vector3f> > vect_at_end_pts (2);
00209     for (size_t j = 0; j < 2; ++j)
00210     {
00211       end_pts[j] = pts[I_SHIFT_EDGE[i][j]];
00212       vect_at_end_pts[j] = vector_at_pts[I_SHIFT_EDGE[i][j]];
00213     }
00214     if (isIntersected (end_pts, vect_at_end_pts, pt_union_indices))
00215     {
00216       // Indices of cells that contains points which will be connected to
00217       // create a polygon
00218       Eigen::Vector3i polygon[4];
00219       Eigen::Vector4f polygon_pts[4];
00220       int polygon_indices_1d[4];
00221       bool is_all_in_hash_map = true;
00222       switch (i)
00223       {
00224         case 0:
00225           polygon[0] = Eigen::Vector3i (index[0] - 1, index[1] + 1, index[2]);
00226           polygon[1] = Eigen::Vector3i (index[0] - 1, index[1], index[2]);
00227           polygon[2] = Eigen::Vector3i (index[0], index[1], index[2]);
00228           polygon[3] = Eigen::Vector3i (index[0], index[1] + 1, index[2]);
00229           break;
00230         case 1:
00231           polygon[0] = Eigen::Vector3i (index[0], index[1] + 1, index[2] + 1);
00232           polygon[1] = Eigen::Vector3i (index[0], index[1] + 1, index[2]);
00233           polygon[2] = Eigen::Vector3i (index[0], index[1], index[2]);
00234           polygon[3] = Eigen::Vector3i (index[0], index[1], index[2] + 1);
00235           break;
00236         case 2:
00237           polygon[0] = Eigen::Vector3i (index[0] - 1, index[1], index[2] + 1);
00238           polygon[1] = Eigen::Vector3i (index[0] - 1, index[1], index[2]);
00239           polygon[2] = Eigen::Vector3i (index[0], index[1], index[2]);
00240           polygon[3] = Eigen::Vector3i (index[0], index[1], index[2] + 1);
00241           break;
00242         default:
00243           break;
00244       }
00245       for (size_t k = 0; k < 4; k++)
00246       {
00247         polygon_indices_1d[k] = getIndexIn1D (polygon[k]);
00248         if (!occupied_cell_list_[polygon_indices_1d[k]])
00249         {
00250           is_all_in_hash_map = false;
00251           break;
00252         }
00253       }
00254       if (is_all_in_hash_map)
00255       {
00256         for (size_t k = 0; k < 4; k++)
00257         {
00258           polygon_pts[k] = cell_hash_map_.at (polygon_indices_1d[k]).pt_on_surface;
00259           surface_.push_back (polygon_pts[k]);
00260         }
00261       }
00262     }
00263   }
00264 }
00265 
00267 template <typename PointNT> void
00268 pcl::GridProjection<PointNT>::getProjection (const Eigen::Vector4f &p,
00269                                              std::vector <int> &pt_union_indices, Eigen::Vector4f &projection)
00270 {
00271   const double projection_distance = leaf_size_ * 3;
00272   std::vector<Eigen::Vector4f, Eigen::aligned_allocator<Eigen::Vector4f> > end_pt (2);
00273   std::vector<Eigen::Vector3f, Eigen::aligned_allocator<Eigen::Vector3f> > end_pt_vect (2);
00274   end_pt[0] = p;
00275   getVectorAtPoint (end_pt[0], pt_union_indices, end_pt_vect[0]);
00276   end_pt_vect[0].normalize();
00277 
00278   double dSecond = getD2AtPoint (end_pt[0], end_pt_vect[0], pt_union_indices);
00279 
00280   // Find another point which is projection_distance away from the p, do a
00281   // binary search between these two points, to find the projected point on the
00282   // surface
00283   if (dSecond > 0)
00284     end_pt[1] = end_pt[0] + Eigen::Vector4f (end_pt_vect[0][0] * projection_distance,
00285                                              end_pt_vect[0][1] * projection_distance,
00286                                              end_pt_vect[0][2] * projection_distance, 0);
00287   else
00288     end_pt[1] = end_pt[0] - Eigen::Vector4f (end_pt_vect[0][0] * projection_distance,
00289                                              end_pt_vect[0][1] * projection_distance,
00290                                              end_pt_vect[0][2] * projection_distance, 0);
00291   getVectorAtPoint (end_pt[1], pt_union_indices, end_pt_vect[1]);
00292   if (end_pt_vect[1].dot (end_pt_vect[0]) < 0)
00293   {
00294     Eigen::Vector4f mid_pt = end_pt[0] + (end_pt[1] - end_pt[0]) * 0.5;
00295     findIntersection (0, end_pt, end_pt_vect, mid_pt, pt_union_indices, projection);
00296   }
00297   else
00298     projection = p;
00299 }
00300 
00302 template <typename PointNT> void
00303 pcl::GridProjection<PointNT>::getProjectionWithPlaneFit (const Eigen::Vector4f &p,
00304                                                          std::vector<int> (&pt_union_indices),
00305                                                          Eigen::Vector4f &projection)
00306 {
00307   // Compute the plane coefficients
00308   Eigen::Vector4f model_coefficients;
00310   Eigen::Matrix3f covariance_matrix;
00311   Eigen::Vector4f xyz_centroid;
00312 
00313   computeMeanAndCovarianceMatrix (*data_, pt_union_indices, covariance_matrix, xyz_centroid);
00314 
00315   // Get the plane normal
00316   EIGEN_ALIGN16 Eigen::Vector3f::Scalar eigen_value;
00317   EIGEN_ALIGN16 Eigen::Vector3f eigen_vector;
00318   pcl::eigen33 (covariance_matrix, eigen_value, eigen_vector);
00319 
00320   // The normalization is not necessary, since the eigenvectors from libeigen are already normalized
00321   model_coefficients[0] = eigen_vector [0];
00322   model_coefficients[1] = eigen_vector [1];
00323   model_coefficients[2] = eigen_vector [2];
00324   model_coefficients[3] = 0;
00325   // Hessian form (D = nc . p_plane (centroid here) + p)
00326   model_coefficients[3] = -1 * model_coefficients.dot (xyz_centroid);
00327 
00328   // Projected point
00329   Eigen::Vector3f point (p.x (), p.y (), p.z ());     //= Eigen::Vector3f::MapAligned (&output.points[cp].x, 3);
00330   float distance = point.dot (model_coefficients.head <3> ()) + model_coefficients[3];
00331   point -= distance * model_coefficients.head < 3 > ();
00332 
00333   projection = Eigen::Vector4f (point[0], point[1], point[2], 0);
00334 }
00335 
00337 template <typename PointNT> void
00338 pcl::GridProjection<PointNT>::getVectorAtPoint (const Eigen::Vector4f &p,
00339                                                 std::vector <int> &pt_union_indices,
00340                                                 Eigen::Vector3f &vo)
00341 {
00342   std::vector <double> pt_union_dist (pt_union_indices.size ());
00343   std::vector <double> pt_union_weight (pt_union_indices.size ());
00344   Eigen::Vector3f out_vector (0, 0, 0);
00345   double sum = 0.0;
00346   double mag = 0.0;
00347 
00348   for (size_t i = 0; i < pt_union_indices.size (); ++i)
00349   {
00350     pt_union_dist[i] = (data_->points[pt_union_indices[i]].getVector4fMap () - p).squaredNorm ();
00351     pt_union_weight[i] = pow (M_E, -pow (pt_union_dist[i], 2.0) / gaussian_scale_);
00352     mag += pow (M_E, -pow (sqrt (pt_union_dist[i]), 2.0) / gaussian_scale_);
00353     sum += pt_union_weight[i];
00354   }
00355 
00356   pcl::VectorAverage3f vector_average;
00357 
00358   Eigen::Vector3f v (data_->points[pt_union_indices[0]].normal[0],
00359               data_->points[pt_union_indices[0]].normal[1],
00360               data_->points[pt_union_indices[0]].normal[2]);
00361 
00362   for (size_t i = 0; i < pt_union_weight.size (); ++i)
00363   {
00364     pt_union_weight[i] /= sum;
00365     Eigen::Vector3f vec (data_->points[pt_union_indices[i]].normal[0],
00366                   data_->points[pt_union_indices[i]].normal[1],
00367                   data_->points[pt_union_indices[i]].normal[2]);
00368     if (vec.dot (v) < 0)
00369       vec = -vec;
00370     vector_average.add (vec, pt_union_weight[i]);
00371   }
00372   out_vector = vector_average.getMean ();
00373   // vector_average.getEigenVector1(out_vector);
00374 
00375   out_vector.normalize ();
00376   double d1 = getD1AtPoint (p, out_vector, pt_union_indices);
00377   out_vector = out_vector * sum;
00378   vo = ((d1 > 0) ? -1 : 1) * out_vector;
00379 }
00380 
00382 template <typename PointNT> void
00383 pcl::GridProjection<PointNT>::getVectorAtPointKNN (const Eigen::Vector4f &p,
00384                                                    std::vector <int> &k_indices,
00385                                                    std::vector <float> &k_squared_distances,
00386                                                    Eigen::Vector3f &vo)
00387 {
00388   Eigen::Vector3f out_vector (0, 0, 0);
00389   std::vector <float> k_weight;
00390   k_weight.resize (k_);
00391   float sum = 0.0;
00392   for (int i = 0; i < k_; i++)
00393   {
00394     //k_weight[i] = pow (M_E, -pow (k_squared_distances[i], 2.0) / gaussian_scale_);
00395     k_weight[i] = std::pow (static_cast<float>(M_E), static_cast<float>(-pow (static_cast<float>(k_squared_distances[i]), 2.0f) / gaussian_scale_));
00396     sum += k_weight[i];
00397   }
00398   pcl::VectorAverage3f vector_average;
00399   for (int i = 0; i < k_; i++)
00400   {
00401     k_weight[i] /= sum;
00402     Eigen::Vector3f vec (data_->points[k_indices[i]].normal[0],
00403                          data_->points[k_indices[i]].normal[1],
00404                          data_->points[k_indices[i]].normal[2]);
00405     vector_average.add (vec, k_weight[i]);
00406   }
00407   vector_average.getEigenVector1 (out_vector);
00408   out_vector.normalize ();
00409   double d1 = getD1AtPoint (p, out_vector, k_indices);
00410   out_vector = out_vector * sum;
00411   vo = ((d1 > 0) ? -1 : 1) * out_vector;
00412 
00413 }
00414 
00416 template <typename PointNT> double
00417 pcl::GridProjection<PointNT>::getMagAtPoint (const Eigen::Vector4f &p,
00418                                              const std::vector <int> &pt_union_indices)
00419 {
00420   std::vector <double> pt_union_dist (pt_union_indices.size ());
00421   std::vector <double> pt_union_weight (pt_union_indices.size ());
00422   double sum = 0.0;
00423   for (size_t i = 0; i < pt_union_indices.size (); ++i)
00424   {
00425     pt_union_dist[i] = (data_->points[pt_union_indices[i]].getVector4fMap () - p).norm ();
00426     sum += pow (M_E, -pow (pt_union_dist[i], 2.0) / gaussian_scale_);
00427   }
00428   return (sum);
00429 }
00430 
00432 template <typename PointNT> double
00433 pcl::GridProjection<PointNT>::getD1AtPoint (const Eigen::Vector4f &p, const Eigen::Vector3f &vec,
00434                                             const std::vector <int> &pt_union_indices)
00435 {
00436   double sz = 0.01 * leaf_size_;
00437   Eigen::Vector3f v = vec * sz;
00438 
00439   double forward  = getMagAtPoint (p + Eigen::Vector4f (v[0], v[1], v[2], 0), pt_union_indices);
00440   double backward = getMagAtPoint (p - Eigen::Vector4f (v[0], v[1], v[2], 0), pt_union_indices);
00441   return ((forward - backward) / (0.02 * leaf_size_));
00442 }
00443 
00445 template <typename PointNT> double
00446 pcl::GridProjection<PointNT>::getD2AtPoint (const Eigen::Vector4f &p, const Eigen::Vector3f &vec,
00447                                             const std::vector <int> &pt_union_indices)
00448 {
00449   double sz = 0.01 * leaf_size_;
00450   Eigen::Vector3f v = vec * sz;
00451 
00452   double forward = getD1AtPoint (p + Eigen::Vector4f (v[0], v[1], v[2], 0), vec, pt_union_indices);
00453   double backward = getD1AtPoint (p - Eigen::Vector4f (v[0], v[1], v[2], 0), vec, pt_union_indices);
00454   return ((forward - backward) / (0.02 * leaf_size_));
00455 }
00456 
00458 template <typename PointNT> bool
00459 pcl::GridProjection<PointNT>::isIntersected (const std::vector<Eigen::Vector4f, Eigen::aligned_allocator<Eigen::Vector4f> > &end_pts,
00460                                              std::vector<Eigen::Vector3f, Eigen::aligned_allocator<Eigen::Vector3f> > &vect_at_end_pts,
00461                                              std::vector <int> &pt_union_indices)
00462 {
00463   assert (end_pts.size () == 2);
00464   assert (vect_at_end_pts.size () == 2);
00465 
00466   double length[2];
00467   for (size_t i = 0; i < 2; ++i)
00468   {
00469     length[i] = vect_at_end_pts[i].norm ();
00470     vect_at_end_pts[i].normalize ();
00471   }
00472   double dot_prod = vect_at_end_pts[0].dot (vect_at_end_pts[1]);
00473   if (dot_prod < 0)
00474   {
00475     double ratio = length[0] / (length[0] + length[1]);
00476     Eigen::Vector4f start_pt = end_pts[0] + (end_pts[1] - end_pts[0]) * ratio;
00477     Eigen::Vector4f intersection_pt = Eigen::Vector4f::Zero ();
00478     findIntersection (0, end_pts, vect_at_end_pts, start_pt, pt_union_indices, intersection_pt);
00479 
00480     Eigen::Vector3f vec;
00481     getVectorAtPoint (intersection_pt, pt_union_indices, vec);
00482     vec.normalize ();
00483 
00484     double d2 = getD2AtPoint (intersection_pt, vec, pt_union_indices);
00485     if (d2 < 0)
00486       return (true);
00487   }
00488   return (false);
00489 }
00490 
00492 template <typename PointNT> void
00493 pcl::GridProjection<PointNT>::findIntersection (int level,
00494                                                 const std::vector<Eigen::Vector4f, Eigen::aligned_allocator<Eigen::Vector4f> > &end_pts,
00495                                                 const std::vector<Eigen::Vector3f, Eigen::aligned_allocator<Eigen::Vector3f> > &vect_at_end_pts,
00496                                                 const Eigen::Vector4f &start_pt,
00497                                                 std::vector <int> &pt_union_indices,
00498                                                 Eigen::Vector4f &intersection)
00499 {
00500   assert (end_pts.size () == 2);
00501   assert (vect_at_end_pts.size () == 2);
00502 
00503   Eigen::Vector3f vec;
00504   getVectorAtPoint (start_pt, pt_union_indices, vec);
00505   double d1 = getD1AtPoint (start_pt, vec, pt_union_indices);
00506   std::vector<Eigen::Vector4f, Eigen::aligned_allocator<Eigen::Vector4f> > new_end_pts (2);
00507   std::vector<Eigen::Vector3f, Eigen::aligned_allocator<Eigen::Vector3f> > new_vect_at_end_pts (2);
00508   if ((abs (d1) < 10e-3) || (level == max_binary_search_level_))
00509   {
00510     intersection = start_pt;
00511     return;
00512   }
00513   else
00514   {
00515     vec.normalize ();
00516     if (vec.dot (vect_at_end_pts[0]) < 0)
00517     {
00518       Eigen::Vector4f new_start_pt = end_pts[0] + (start_pt - end_pts[0]) * 0.5;
00519       new_end_pts[0] = end_pts[0];
00520       new_end_pts[1] = start_pt;
00521       new_vect_at_end_pts[0] = vect_at_end_pts[0];
00522       new_vect_at_end_pts[1] = vec;
00523       findIntersection (level + 1, new_end_pts, new_vect_at_end_pts, new_start_pt, pt_union_indices, intersection);
00524       return;
00525     }
00526     if (vec.dot (vect_at_end_pts[1]) < 0)
00527     {
00528       Eigen::Vector4f new_start_pt = start_pt + (end_pts[1] - start_pt) * 0.5;
00529       new_end_pts[0] = start_pt;
00530       new_end_pts[1] = end_pts[1];
00531       new_vect_at_end_pts[0] = vec;
00532       new_vect_at_end_pts[1] = vect_at_end_pts[1];
00533       findIntersection (level + 1, new_end_pts, new_vect_at_end_pts, new_start_pt, pt_union_indices, intersection);
00534       return;
00535     }
00536     intersection = start_pt;
00537     return;
00538   }
00539 }
00540 
00541 
00543 template <typename PointNT> void
00544 pcl::GridProjection<PointNT>::fillPad (const Eigen::Vector3i &index)
00545 {
00546   for (int i = index[0] - padding_size_; i < index[0] + padding_size_; ++i)
00547   {
00548     for (int j = index[1] - padding_size_; j < index[1] + padding_size_; ++j)
00549     {
00550       for (int k = index[2] - padding_size_; k < index[2] + padding_size_; ++k)
00551       {
00552         Eigen::Vector3i cell_index_3d (i, j, k);
00553         unsigned int cell_index_1d = getIndexIn1D (cell_index_3d);
00554         if (cell_hash_map_.find (cell_index_1d) == cell_hash_map_.end ())
00555         {
00556           cell_hash_map_[cell_index_1d].data_indices.resize (0);
00557           getCellCenterFromIndex (cell_index_3d, cell_hash_map_[cell_index_1d].pt_on_surface);
00558         }
00559       }
00560     }
00561   }
00562 }
00563 
00564 
00566 template <typename PointNT> void
00567 pcl::GridProjection<PointNT>::storeVectAndSurfacePoint (int index_1d,
00568                                                         const Eigen::Vector3i &index_3d,
00569                                                         std::vector <int> &pt_union_indices,
00570                                                         const Leaf &cell_data)
00571 {
00572   // Get point on grid
00573   Eigen::Vector4f grid_pt (cell_data.pt_on_surface.x () - leaf_size_ / 2.0,
00574                            cell_data.pt_on_surface.y () + leaf_size_ / 2.0,
00575                            cell_data.pt_on_surface.z () + leaf_size_ / 2.0, 0);
00576 
00577   // Save the vector and the point on the surface
00578   getVectorAtPoint (grid_pt, pt_union_indices, cell_hash_map_[index_1d].vect_at_grid_pt);
00579   getProjection (cell_data.pt_on_surface, pt_union_indices, cell_hash_map_[index_1d].pt_on_surface);
00580 }
00581 
00583 template <typename PointNT> void
00584 pcl::GridProjection<PointNT>::storeVectAndSurfacePointKNN (int index_1d, const Eigen::Vector3i &index_3d,
00585                                                            const Leaf &cell_data)
00586 {
00587   Eigen::Vector4f cell_center = cell_data.pt_on_surface;
00588   Eigen::Vector4f grid_pt (cell_center.x () - leaf_size_ / 2,
00589                            cell_center.y () + leaf_size_ / 2,
00590                            cell_center.z () + leaf_size_ / 2, 0);
00591 
00592   std::vector <int> k_indices;
00593   k_indices.resize (k_);
00594   std::vector <float> k_squared_distances;
00595   k_squared_distances.resize (k_);
00596 
00597   PointNT pt; pt.x = grid_pt.x (); pt.y = grid_pt.y (); pt.z = grid_pt.z ();
00598   tree_->nearestKSearch (pt, k_, k_indices, k_squared_distances);
00599 
00600   getVectorAtPointKNN (grid_pt, k_indices, k_squared_distances, cell_hash_map_[index_1d].vect_at_grid_pt);
00601   getProjectionWithPlaneFit (cell_center, k_indices, cell_hash_map_[index_1d].pt_on_surface);
00602 }
00603 
00605 template <typename PointNT> bool
00606 pcl::GridProjection<PointNT>::reconstructPolygons (std::vector<pcl::Vertices> &polygons)
00607 {
00608   data_.reset (new pcl::PointCloud<PointNT> (*input_));
00609   getBoundingBox ();
00610 
00611   // Store the point cloud data into the voxel grid, and at the same time
00612   // create a hash map to store the information for each cell
00613   cell_hash_map_.max_load_factor (2.0);
00614   cell_hash_map_.rehash (data_->points.size () / cell_hash_map_.max_load_factor ());
00615 
00616   // Go over all points and insert them into the right leaf
00617   for (size_t cp = 0; cp < data_->points.size (); ++cp)
00618   {
00619     // Check if the point is invalid
00620     if (!pcl_isfinite (data_->points[cp].x) ||
00621         !pcl_isfinite (data_->points[cp].y) ||
00622         !pcl_isfinite (data_->points[cp].z))
00623       continue;
00624 
00625     Eigen::Vector3i index_3d;
00626     getCellIndex (data_->points[cp].getVector4fMap (), index_3d);
00627     int index_1d = getIndexIn1D (index_3d);
00628     if (cell_hash_map_.find (index_1d) == cell_hash_map_.end ())
00629     {
00630       Leaf cell_data;
00631       cell_data.data_indices.push_back (cp);
00632       getCellCenterFromIndex (index_3d, cell_data.pt_on_surface);
00633       cell_hash_map_[index_1d] = cell_data;
00634       occupied_cell_list_[index_1d] = 1;
00635     }
00636     else
00637     {
00638       Leaf cell_data = cell_hash_map_.at (index_1d);
00639       cell_data.data_indices.push_back (cp);
00640       cell_hash_map_[index_1d] = cell_data;
00641     }
00642   }
00643 
00644   Eigen::Vector3i index;
00645   int numOfFilledPad = 0;
00646 
00647   for (int i = 0; i < data_size_; ++i)
00648   {
00649     for (int j = 0; j < data_size_; ++j)
00650     {
00651       for (int k = 0; k < data_size_; ++k)
00652       {
00653         index[0] = i;
00654         index[1] = j;
00655         index[2] = k;
00656         if (occupied_cell_list_[getIndexIn1D (index)])
00657         {
00658           fillPad (index);
00659           numOfFilledPad++;
00660         }
00661       }
00662     }
00663   }
00664 
00665   // Update the hashtable and store the vector and point
00666   BOOST_FOREACH (typename HashMap::value_type entry, cell_hash_map_)
00667   {
00668     getIndexIn3D (entry.first, index);
00669     std::vector <int> pt_union_indices;
00670     getDataPtsUnion (index, pt_union_indices);
00671 
00672     // Needs at least 10 points (?)
00673     // NOTE: set as parameter later
00674     if (pt_union_indices.size () > 10)
00675     {
00676       storeVectAndSurfacePoint (entry.first, index, pt_union_indices, entry.second);
00677       //storeVectAndSurfacePointKNN(entry.first, index, entry.second);
00678       occupied_cell_list_[entry.first] = 1;
00679     }
00680   }
00681 
00682   // Go through the hash table another time to extract surface
00683   BOOST_FOREACH (typename HashMap::value_type entry, cell_hash_map_)
00684   {
00685     getIndexIn3D (entry.first, index);
00686     std::vector <int> pt_union_indices;
00687     getDataPtsUnion (index, pt_union_indices);
00688 
00689     // Needs at least 10 points (?)
00690     // NOTE: set as parameter later
00691     if (pt_union_indices.size () > 10)
00692       createSurfaceForCell (index, pt_union_indices);
00693   }
00694 
00695   polygons.resize (surface_.size () / 4);
00696   // Copy the data from surface_ to polygons
00697   for (size_t i = 0; i < polygons.size (); ++i)
00698   {
00699     pcl::Vertices v;
00700     v.vertices.resize (4);
00701     for (int j = 0; j < 4; ++j)
00702       v.vertices[j] = i*4+j;
00703      polygons[i] = v;
00704   }
00705   return (true);
00706 }
00707 
00709 template <typename PointNT> void
00710 pcl::GridProjection<PointNT>::performReconstruction (pcl::PolygonMesh &output)
00711 {
00712   if (!reconstructPolygons (output.polygons))
00713     return;
00714 
00715   // The mesh surface is held in surface_. Copy it to the output format
00716   output.header = input_->header;
00717 
00718   pcl::PointCloud<pcl::PointXYZ> cloud;
00719   cloud.width = surface_.size ();
00720   cloud.height = 1;
00721   cloud.is_dense = true;
00722 
00723   cloud.points.resize (surface_.size ());
00724   // Copy the data from surface_ to cloud
00725   for (size_t i = 0; i < cloud.points.size (); ++i)
00726   {
00727     cloud.points[i].x = surface_[i].x ();
00728     cloud.points[i].y = surface_[i].y ();
00729     cloud.points[i].z = surface_[i].z ();
00730   }
00731   pcl::toROSMsg (cloud, output.cloud);
00732 }
00733 
00735 template <typename PointNT> void
00736 pcl::GridProjection<PointNT>::performReconstruction (pcl::PointCloud<PointNT> &points,
00737                                                      std::vector<pcl::Vertices> &polygons)
00738 {
00739   if (!reconstructPolygons (polygons))
00740     return;
00741 
00742   // The mesh surface is held in surface_. Copy it to the output format
00743   points.header = input_->header;
00744   points.width = surface_.size ();
00745   points.height = 1;
00746   points.is_dense = true;
00747 
00748   points.resize (surface_.size ());
00749   // Copy the data from surface_ to cloud
00750   for (size_t i = 0; i < points.size (); ++i)
00751   {
00752     points[i].x = surface_[i].x ();
00753     points[i].y = surface_[i].y ();
00754     points[i].z = surface_[i].z ();
00755   }
00756 }
00757 
00758 #define PCL_INSTANTIATE_GridProjection(T) template class PCL_EXPORTS pcl::GridProjection<T>;
00759 
00760 #endif    // PCL_SURFACE_IMPL_GRID_PROJECTION_H_
00761