00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
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
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
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
00119 set<Cell> intersectingCells (const nm::MapMetaData& info, const nm::MapMetaData& info2, const Cell& cell2)
00120 {
00121
00122 const gm::Polygon poly=expandPolygon(cellPolygon(info2, cell2), 1.0001);
00123
00124
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
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
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
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 }
00258
00259
00260
00261