Go to the documentation of this file.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
00039 #include <occupancy_grid_utils/geometry.h>
00040 #include <queue>
00041 #include <set>
00042 #include <boost/foreach.hpp>
00043
00044 namespace occupancy_grid_utils
00045 {
00046
00047 namespace gm=geometry_msgs;
00048 namespace nm=nav_msgs;
00049 using std::vector;
00050 typedef std::set<Cell> Cells;
00051
00052 struct Line
00053 {
00054 Line (const gm::Point32& p1, const gm::Point32& p2)
00055 {
00056 const float dx = p2.x-p1.x;
00057 const float dy = p2.y-p1.y;
00058 if (fabs(dx) < 1e-3 && fabs(dy) < 1e-3)
00059 {
00060 boost::format e("Points (%.2f, %.2f) and (%.2f, %.2f) are too close");
00061 throw GridUtilsException(e % p1.x % p1.y % p2.x % p2.y);
00062 }
00063 a = dy;
00064 b = -dx;
00065 c = p1.y*dx - p1.x*dy;
00066 }
00067
00068
00069 bool intersects (const gm::Polygon& poly) const
00070 {
00071 bool seen_nonnegative = false;
00072 bool seen_nonpositive = false;
00073 BOOST_FOREACH (const gm::Point32& p, poly.points)
00074 {
00075 const float d = a*p.x+b*p.y+c;
00076 if (d>=0)
00077 seen_nonnegative = true;
00078 if (d<=0)
00079 seen_nonpositive = true;
00080 if (seen_nonnegative && seen_nonpositive)
00081 return true;
00082 }
00083 return false;
00084 }
00085
00086
00087 float a;
00088 float b;
00089 float c;
00090 };
00091
00092
00093 struct CellsInPolygon
00094 {
00095 CellsInPolygon (const nm::MapMetaData& info, const gm::Polygon& poly) :
00096 info(info)
00097 {
00098 const size_t n = poly.points.size();
00099 for (size_t i=0; i<n; i++)
00100 {
00101 const size_t j = i>0 ? i-1 : n-1;
00102 sides.push_back(Line(poly.points[i], poly.points[j]));
00103 }
00104 }
00105
00106
00107
00108 bool operator() (const Cell& c)
00109 {
00110 cells.insert(c);
00111 const gm::Polygon cell_poly = cellPolygon(info, c);
00112 BOOST_FOREACH (const Line& s, sides)
00113 {
00114 if (s.intersects(cell_poly))
00115 return false;
00116 }
00117 return true;
00118 }
00119
00120 Cells cells;
00121 const nm::MapMetaData& info;
00122 std::vector<Line> sides;
00123 };
00124
00125
00126
00127
00128 template <class Visitor>
00129 void flood_fill (const nm::MapMetaData& info, const std::set<Cell>& start,
00130 Visitor& vis)
00131 {
00132 Cells seen;
00133 std::queue<Cell> q;
00134 BOOST_FOREACH (const Cell& c, start)
00135 q.push(c);
00136 while (!q.empty())
00137 {
00138 const Cell c = q.front();
00139 q.pop();
00140 ROS_DEBUG_STREAM_NAMED ("flood_fill", "Cell " << c);
00141 if (seen.find(c)==seen.end())
00142 {
00143 seen.insert(c);
00144 ROS_DEBUG_NAMED ("flood_fill", " Visiting");
00145 if (vis(c))
00146 {
00147 ROS_DEBUG_NAMED ("flood_fill", " Adding neighbors");
00148 for (int dy=-1; dy<=1; dy++)
00149 {
00150 for (int dx=-1; dx<=1; dx++)
00151 {
00152 if (dx!=0 || dy!=0)
00153 {
00154 const Cell c2(c.x+dx, c.y+dy);
00155 if (withinBounds(info, c2))
00156 {
00157 q.push(c2);
00158 ROS_DEBUG_STREAM_NAMED ("flood_fill", " Added " << c2);
00159 }
00160 }
00161 }
00162 }
00163 }
00164 }
00165 }
00166 }
00167
00168
00169 template <class Visitor>
00170 void flood_fill (const nm::MapMetaData& info, const Cell& start,
00171 Visitor& vis)
00172 {
00173 std::set<Cell> s;
00174 s.insert(start);
00175 flood_fill(info, s, vis);
00176 }
00177
00178
00179 Cell center(const nm::MapMetaData& info,
00180 const gm::Polygon& poly)
00181 {
00182 float sx=0;
00183 float sy=0;
00184 BOOST_FOREACH (const gm::Point32& p, poly.points)
00185 {
00186 sx += p.x;
00187 sy += p.y;
00188 }
00189 gm::Point p;
00190 p.x = sx/poly.points.size();
00191 p.y = sy/poly.points.size();
00192 return pointCell(info, p);
00193 }
00194
00195
00196
00197 Cells cellsInConvexPolygon (const nm::MapMetaData& info,
00198 const gm::Polygon& poly)
00199 {
00200 CellsInPolygon visitor(info, poly);
00201 flood_fill(info, center(info, poly), visitor);
00202 return visitor.cells;
00203 }
00204
00205 struct DistanceQueueItem
00206 {
00207 DistanceQueueItem (const Cell& c, const float distance) :
00208 c(c), distance(distance)
00209 {}
00210
00211 inline
00212 bool operator< (const DistanceQueueItem& other) const
00213 {
00214
00215 return (distance > other.distance);
00216 }
00217
00218 Cell c;
00219 float distance;
00220 };
00221
00222 DistanceField distanceField (const nav_msgs::OccupancyGrid& m,
00223 const float max_dist)
00224 {
00225
00226 vector<unsigned> dims;
00227 dims.push_back(m.info.width);
00228 dims.push_back(m.info.height);
00229 DistanceField::ArrayPtr distances(new DistanceField::Array(dims));
00230 for (unsigned x=0; x<m.info.width; x++)
00231 for (unsigned y=0; y<m.info.height; y++)
00232 (*distances)[x][y] = max_dist;
00233 std::set<Cell> seen;
00234 std::priority_queue<DistanceQueueItem> q;
00235
00236
00237 for (index_t i=0; i<m.info.width*m.info.height; i++)
00238 {
00239 if (m.data[i]!=UNOCCUPIED && m.data[i]!=UNKNOWN)
00240 {
00241 DistanceQueueItem item(indexCell(m.info, i), 0);
00242 q.push(item);
00243 }
00244 }
00245
00246
00247 while (!q.empty())
00248 {
00249 DistanceQueueItem item = q.top();
00250 ROS_DEBUG_THROTTLE_NAMED (1.0, "distance_field",
00251 "Distance %.4f, %zu seen",
00252 item.distance, seen.size());
00253 q.pop();
00254
00255
00256
00257 if (seen.find(item.c)==seen.end())
00258 {
00259 seen.insert(item.c);
00260 const Cell& c = item.c;
00261 (*distances)[c.x][c.y] = item.distance;
00262 if (max_dist>0 && item.distance>max_dist)
00263 continue;
00264 for (char vertical=0; vertical<2; vertical++)
00265 {
00266 for (char d=-1; d<=1; d+=2)
00267 {
00268 const char dx = vertical ? 0 : d;
00269 const char dy = vertical ? d : 0;
00270 const Cell neighbor(c.x+dx, c.y+dy);
00271 if (withinBounds(m.info, neighbor))
00272 {
00273 const float dist = item.distance+m.info.resolution;
00274 q.push(DistanceQueueItem(neighbor, dist));
00275 }
00276 }
00277 }
00278 }
00279 }
00280
00281 return DistanceField(distances);
00282 }
00283
00284
00285 }