combine_grids.cpp
Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2008, Willow Garage, Inc.
00003  * All rights reserved.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions are met:
00007  *
00008  *     * Redistributions of source code must retain the above copyright
00009  *       notice, this list of conditions and the following disclaimer.
00010  *     * Redistributions in binary form must reproduce the above copyright
00011  *       notice, this list of conditions and the following disclaimer in the
00012  *       documentation and/or other materials provided with the distribution.
00013  *     * Neither the name of the Willow Garage, Inc. nor the names of its
00014  *       contributors may be used to endorse or promote products derived from
00015  *       this software without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00018  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00019  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00020  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
00021  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00022  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
00023  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00024  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00025  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
00026  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00027  * POSSIBILITY OF SUCH DAMAGE.
00028  *
00029  */
00030 
00031 
00040 #include <occupancy_grid_utils/combine_grids.h>
00041 #include <occupancy_grid_utils/coordinate_conversions.h>
00042 #include <ros/assert.h>
00043 #include <boost/foreach.hpp>
00044 #include <boost/optional.hpp>
00045 #include <boost/bind.hpp>
00046 #include <boost/ref.hpp>
00047 #include <set>
00048 
00049 namespace occupancy_grid_utils
00050 {
00051 
00052 namespace nm=nav_msgs;
00053 namespace gm=geometry_msgs;
00054 
00055 using boost::bind;
00056 using boost::ref;
00057 using std::vector;
00058 using std::multiset;
00059 using std::set;
00060 using std::min;
00061 using std::max;
00062 
00063 typedef boost::shared_ptr<nm::OccupancyGrid> GridPtr;
00064 typedef boost::shared_ptr<nm::OccupancyGrid const> GridConstPtr;
00065 
00066 inline Cell point32Cell (const nm::MapMetaData& info, const gm::Point32& p)
00067 {
00068   gm::Point pt;
00069   pt.x = p.x;
00070   pt.y = p.y;
00071   pt.z = p.z;
00072   return pointCell(info, pt);
00073 }
00074 
00075 // Does this cell contain a vertex of this polygon?
00076 inline bool containsVertex (const nm::MapMetaData& info, const Cell& c, const gm::Polygon& poly)
00077 {
00078   BOOST_FOREACH (const gm::Point32& p, poly.points) {
00079     if (point32Cell(info, p)==c)
00080       return true;
00081   }
00082   return false;    
00083 }
00084 
00085 
00086 // Do the two cells (on different grids) intersect?
00087 inline bool cellsIntersect (const nm::MapMetaData& info1, const Cell& c1, const nm::MapMetaData& info2, const Cell& c2)
00088 {
00089   const gm::Polygon p1=cellPolygon(info1, c1);
00090   const gm::Polygon p2=cellPolygon(info2, c2);
00091   return containsVertex(info1, c1, p2) || containsVertex(info2, c2, p1);
00092 }
00093 
00094 inline gm::Polygon expandPolygon(const gm::Polygon& p, const double r)
00095 {
00096   double sx=0;
00097   double sy=0;
00098   double sz=0;
00099   const size_t n = p.points.size();
00100   for (unsigned i=0; i<n; i++) {
00101     sx += p.points[i].x;
00102     sy += p.points[i].y;
00103     sz += p.points[i].z;
00104   }
00105   sx /= n;
00106   sy /= n;
00107   sz /= n;
00108   gm::Polygon p2;
00109   p2.points.resize(n);
00110   for (unsigned i=0; i<n; i++) {
00111     p2.points[i].x = sx + r*(p.points[i].x-sx);
00112     p2.points[i].y = sy + r*(p.points[i].y-sy);
00113     p2.points[i].z = sz + r*(p.points[i].z-sz);
00114   }
00115   return p2;
00116 }
00117 
00118 // Return set of intersecting cells in grid info, of cell cell2 in info2
00119 set<Cell> intersectingCells (const nm::MapMetaData& info, const nm::MapMetaData& info2, const Cell& cell2)
00120 {
00121   // The expansion is to avoid weird effects due to rounding when intersecting parallel grids
00122   const gm::Polygon poly=expandPolygon(cellPolygon(info2, cell2), 1.0001);
00123 
00124   // Figure out the candidates
00125   vector<Cell> corners(4);
00126   transform(poly.points.begin(), poly.points.end(), corners.begin(), 
00127             bind(point32Cell, ref(info), _1));
00128   const coord_t min_x=min(corners[0].x, min(corners[1].x, min(corners[2].x, corners[3].x)));
00129   const coord_t min_y=min(corners[0].y, min(corners[1].y, min(corners[2].y, corners[3].y)));
00130   const coord_t max_x=max(corners[0].x, max(corners[1].x, max(corners[2].x, corners[3].x)));
00131   const coord_t max_y=max(corners[0].y, max(corners[1].y, max(corners[2].y, corners[3].y)));
00132   
00133   set<Cell> cells;
00134   for (coord_t x=min_x; x<=max_x; x++) {
00135     for (coord_t y=min_y; y<=max_y; y++) {
00136       const Cell candidate(x, y);
00137       if (withinBounds(info, candidate) &&
00138           cellsIntersect(info, candidate, info2, cell2))
00139         cells.insert(candidate);
00140     }
00141   }
00142 
00143   return cells;
00144 }
00145 
00146 double minX (const nm::MapMetaData& info)
00147 {
00148   const gm::Polygon p=gridPolygon(info);
00149   return min(p.points[0].x, min(p.points[1].x, min(p.points[2].x, p.points[3].x)));
00150 }
00151 
00152 double maxX (const nm::MapMetaData& info)
00153 {
00154   const gm::Polygon p=gridPolygon(info);
00155   return max(p.points[0].x, max(p.points[1].x, max(p.points[2].x, p.points[3].x)));
00156 }
00157 
00158 double minY (const nm::MapMetaData& info)
00159 {
00160   const gm::Polygon p=gridPolygon(info);
00161   return min(p.points[0].y, min(p.points[1].y, min(p.points[2].y, p.points[3].y)));
00162 }
00163 
00164 double maxY (const nm::MapMetaData& info)
00165 {
00166   const gm::Polygon p=gridPolygon(info);
00167   return max(p.points[0].y, max(p.points[1].y, max(p.points[2].y, p.points[3].y)));
00168 }
00169 
00170 gm::Pose transformPose (const btTransform trans, const gm::Pose p)
00171 {
00172   btTransform pose;
00173   tf::poseMsgToTF(p, pose);
00174   gm::Pose transformed;
00175   tf::poseTFToMsg(trans*pose, transformed);
00176   return transformed;
00177 }
00178 
00179 // Get the dimensions of a combined grid
00180 nm::MapMetaData getCombinedGridInfo (const vector<GridConstPtr>& grids, const double resolution)
00181 {
00182   ROS_ASSERT (grids.size() > 0);
00183   nm::MapMetaData info;
00184   info.resolution = resolution;
00185   btTransform trans;
00186   tf::poseMsgToTF(grids[0]->info.origin, trans);
00187 
00188   boost::optional<double> min_x, max_x, min_y, max_y;
00189   BOOST_FOREACH (const GridConstPtr& g, grids) {
00190     nm::MapMetaData grid_info = g->info;
00191     grid_info.origin = transformPose(trans.inverse(), g->info.origin);
00192     if (!(min_x && *min_x < minX(grid_info)))
00193       min_x = minX(grid_info);
00194     if (!(min_y && *min_y < minY(grid_info)))
00195       min_y = minY(grid_info);
00196     if (!(max_x && *max_x > maxX(grid_info)))
00197       max_x = maxX(grid_info);
00198     if (!(max_y && *max_y > maxY(grid_info)))
00199       max_y = maxY(grid_info);
00200   }
00201 
00202   const double dx = *max_x - *min_x;
00203   const double dy = *max_y - *min_y;
00204   ROS_ASSERT ((dx > 0) && (dy > 0));
00205 
00206   gm::Pose pose_in_grid_frame;
00207   pose_in_grid_frame.position.x = *min_x;
00208   pose_in_grid_frame.position.y = *min_y;
00209   pose_in_grid_frame.orientation.w = 1.0;
00210   info.origin = transformPose(trans, pose_in_grid_frame);
00211   info.height = ceil(dy/info.resolution);
00212   info.width = ceil(dx/info.resolution);
00213 
00214   return info;
00215 }
00216 
00217 
00218 // Main function
00219 GridPtr combineGrids (const vector<GridConstPtr>& grids, const double resolution)
00220 {
00221   GridPtr combined_grid(new nm::OccupancyGrid());
00222   combined_grid->info = getCombinedGridInfo(grids, resolution);
00223   combined_grid->data.resize(combined_grid->info.width*combined_grid->info.height);
00224   fill(combined_grid->data.begin(), combined_grid->data.end(), -1);
00225   ROS_DEBUG_NAMED ("combine_grids", "Combining %zu grids", grids.size());
00226 
00227   BOOST_FOREACH (const GridConstPtr& grid, grids) {
00228     for (coord_t x=0; x<(int)grid->info.width; x++) {
00229       for (coord_t y=0; y<(int)grid->info.height; y++) {
00230         const Cell cell(x, y);
00231         const signed char value=grid->data[cellIndex(grid->info, cell)];
00232 
00233         // Only proceed if the value is not unknown 
00234         if ((value>=0) && (value<=100)) {
00235           BOOST_FOREACH (const Cell& intersecting_cell, 
00236                          intersectingCells(combined_grid->info, grid->info, cell)) {
00237             const index_t ind = cellIndex(combined_grid->info, intersecting_cell);
00238             combined_grid->data[ind] = max(combined_grid->data[ind], value);
00239           }
00240         }
00241       }
00242     }
00243   }
00244 
00245   ROS_DEBUG_NAMED ("combine_grids", "Done combining grids");
00246   return combined_grid;
00247 }
00248 
00249 
00250 GridPtr combineGrids (const vector<GridConstPtr>& grids)
00251 {
00252   ROS_ASSERT (grids.size()>0);
00253   return combineGrids(grids, grids[0]->info.resolution);
00254 }
00255 
00256 
00257 } // namespace occupancy_grid_utils
00258 
00259 
00260 
00261 


occupancy_grid_utils
Author(s): Bhaskara Marthi
autogenerated on Tue Jan 7 2014 11:17:09