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/shortest_path.h>
00040 #include <ros/assert.h>
00041 #include <queue>
00042
00043 namespace occupancy_grid_utils
00044 {
00045
00046 namespace nm=nav_msgs;
00047
00048 using std::vector;
00049 using boost::optional;
00050 using std::max;
00051
00052 struct ShortestPathResult
00053 {
00054 nm::MapMetaData info;
00055 index_t src_ind;
00056 vector<optional<index_t> > back_pointers;
00057 vector<optional<double> > potential;
00058 };
00059
00060 TerminationCondition::TerminationCondition ()
00061 {}
00062
00063 TerminationCondition::TerminationCondition (const double max_distance) :
00064 max_distance_(max_distance)
00065 {}
00066
00067 TerminationCondition::TerminationCondition (const Cells& goals) :
00068 goals_(goals)
00069 {}
00070
00071 TerminationCondition::TerminationCondition (const Cells& goals, const double max_distance) :
00072 max_distance_(max_distance), goals_(goals)
00073 {}
00074
00075
00076 typedef vector<Cell> Path;
00077 typedef boost::shared_ptr<nm::OccupancyGrid> GridPtr;
00078
00079 boost::optional<double> distance(ResultPtr res, const Cell& dest)
00080 {
00081 return res->potential[cellIndex(res->info, dest)];
00082 }
00083
00084
00085
00086 boost::optional<Path> extractPath(ResultPtr res, const Cell& dest)
00087 {
00088 boost::optional<Path> p;
00089 index_t current=cellIndex(res->info, dest);
00090 if (!res->back_pointers[current])
00091 return p;
00092
00093 index_t max=res->back_pointers.size();
00094 index_t n=0;
00095 p = Path();
00096
00097 do {
00098 if (n++ > max) {
00099 ROS_FATAL("Cycle in extractPath");
00100 ROS_BREAK();
00101 }
00102 p->push_back(indexCell(res->info, current));
00103 ROS_ASSERT_MSG(res->back_pointers[current], "Back pointer not found for %u", current);
00104 current=*(res->back_pointers[current]);
00105 } while (current!=res->src_ind);
00106 p->push_back(indexCell(res->info, current));
00107 reverse(p->begin(), p->end());
00108 return p;
00109 }
00110
00111
00112
00113 struct QueueItem
00114 {
00115 index_t ind;
00116 double potential;
00117 QueueItem (const index_t ind, const double potential) :
00118 ind(ind), potential(potential) {}
00119 };
00120
00121 bool operator< (const QueueItem& i1, const QueueItem& i2)
00122 {
00123 return i1.potential > i2.potential;
00124 }
00125
00126
00127 ResultPtr singleSourceShortestPaths (const nm::OccupancyGrid& g, const Cell& src)
00128 {
00129 return singleSourceShortestPaths(g, src, TerminationCondition());
00130 }
00131
00132 ResultPtr singleSourceShortestPaths (const nm::OccupancyGrid& g, const Cell& src, const TerminationCondition& t)
00133 {
00134 ShortestPathResult* res = new ShortestPathResult();
00135 ResultPtr result(res);
00136 res->info = g.info;
00137 res->src_ind = cellIndex(g.info, src);
00138 res->back_pointers.resize(g.data.size());
00139 res->potential.resize(g.data.size());
00140
00141 std::priority_queue<QueueItem> q;
00142 q.push(QueueItem(res->src_ind, 0.0));
00143 res->potential[res->src_ind] = 0.0;
00144 ROS_DEBUG_NAMED ("shortest_path", "Computing single source shortest paths from %d, %d", src.x, src.y);
00145
00146 Cells remaining_goals;
00147 if (t.goals_)
00148 remaining_goals = *t.goals_;
00149
00150 while (!q.empty()) {
00151 const QueueItem i=q.top();
00152 q.pop();
00153
00154 const Cell cell = indexCell(g.info, i.ind);
00155 const double dist = i.potential;
00156 if (t.max_distance_ && *t.max_distance_ < dist)
00157 break;
00158 if (t.goals_) {
00159 remaining_goals.erase(cell);
00160 if (remaining_goals.empty())
00161 break;
00162 }
00163
00164 for (int dx=-1; dx<=1; dx++) {
00165 for (int dy=-1; dy<=1; dy++) {
00166 if ((dx==0) && (dy==0))
00167 continue;
00168 const double d = ((dx==0) || (dy==0)) ? 1 : sqrt(2);
00169 const Cell neighbor(cell.x+dx, cell.y+dy);
00170 if (withinBounds(g.info, neighbor)) {
00171 const index_t ind=cellIndex(g.info, neighbor);
00172 const double new_dist = dist+d;
00173 if (g.data[ind]==UNOCCUPIED &&
00174 (!res->potential[ind] || *(res->potential[ind]) > new_dist) &&
00175 (!t.max_distance_ || *t.max_distance_ >= new_dist)) {
00176 ROS_DEBUG_NAMED ("shortest_path_propagation", "Adding cell %d, %d, at distance %.2f",
00177 neighbor.x, neighbor.y, new_dist);
00178 res->potential[ind] = new_dist;
00179 res->back_pointers[ind] = i.ind;
00180 q.push(QueueItem(ind, new_dist));
00181 }
00182 }
00183 }
00184 }
00185 }
00186 ROS_DEBUG_NAMED ("shortest_path", "Done computing single source shortest paths from %d, %d", src.x, src.y);
00187 return result;
00188 }
00189
00190
00191 void propagateValue (nm::OccupancyGrid* g, const coord_t x0, const coord_t y0,
00192 const signed char val, const int r)
00193 {
00194 for (int dx=-r; dx<=r; dx++) {
00195 for (int dy=-r; dy<=r; dy++) {
00196 if (dx*dx + dy*dy <= r*r) {
00197 const int x=x0+dx;
00198 const int y=y0+dy;
00199 const Cell cell(x, y);
00200 if ((x>=0) && (x<(int)g->info.width) && (y>=0) && (y<(int)g->info.height) &&
00201 withinBounds(g->info, cell)) {
00202 const int ind=cellIndex(g->info, cell);
00203 g->data[ind] = max(g->data[ind], val);
00204 ROS_ASSERT(g->data[ind]>=1 && g->data[ind]<=100);
00205 }
00206 }
00207 }
00208 }
00209 }
00210
00211
00212 GridPtr inflateObstacles (const nm::OccupancyGrid& g, const double r)
00213 {
00214 ROS_ASSERT (r>0);
00215 const int radius = ceil(r/g.info.resolution);
00216 GridPtr g2(new nm::OccupancyGrid(g));
00217
00218 for (coord_t x=0; x<(int)g.info.width; x++) {
00219 for (coord_t y=0; y<(int)g.info.height; y++) {
00220 const Cell cell(x, y);
00221 if (withinBounds(g.info, cell)) {
00222 const char val=g.data[cellIndex(g.info, cell)];
00223 if (val >= 1) {
00224 ROS_ASSERT_MSG (val <= 100, "Unexpected cell value %d", val);
00225 propagateValue(g2.get(), x, y, val, radius);
00226 }
00227 }
00228 }
00229 }
00230
00231 return g2;
00232 }
00233
00234
00235
00236
00237
00238 typedef std::pair<Path, double> AStarResult;
00239 struct PQItem
00240 {
00241 index_t ind;
00242 double g_cost;
00243 double h_cost;
00244 PQItem (index_t ind, double g_cost, double h_cost) :
00245 ind(ind), g_cost(g_cost), h_cost(h_cost) {}
00246
00247 bool operator< (const PQItem& i2) const
00248 {
00249 return ((g_cost + h_cost) > (i2.g_cost + i2.h_cost));
00250 }
00251 };
00252
00253
00254 inline double manhattanHeuristic (const Cell& c1, const Cell& c2)
00255 {
00256 return fabs(c1.x-c2.x) + fabs(c1.y-c2.y);
00257 }
00258
00259 optional<AStarResult> shortestPath(const nm::OccupancyGrid& g, const Cell& src, const Cell& dest)
00260 {
00261 std::priority_queue<PQItem> open_list;
00262 const unsigned num_cells = g.info.height*g.info.width;
00263 std::vector<bool> seen(num_cells);
00264 open_list.push(PQItem(cellIndex(g.info, src), 0, manhattanHeuristic(src, dest)));
00265 std::vector<index_t> parent(num_cells);
00266 const index_t dest_ind = cellIndex(g.info, dest);
00267
00268 optional<AStarResult> res;
00269 ROS_DEBUG_STREAM_NAMED ("shortest_path", "Computing shortest path from " << src << " to " << dest);
00270
00271 while (!open_list.empty()) {
00272 const PQItem current = open_list.top();
00273 open_list.pop();
00274 const Cell c = indexCell(g.info, current.ind);
00275 if (seen[current.ind])
00276 continue;
00277 seen[current.ind] = true;
00278 ROS_DEBUG_STREAM_NAMED ("shortest_path_internal", " Considering " << c << " with cost " <<
00279 current.g_cost << " + " << current.h_cost);
00280 if (current.ind == dest_ind) {
00281 res = AStarResult();
00282 res->second = current.g_cost;
00283
00284 break;
00285 }
00286
00287 for (int d=-1; d<=1; d+=2) {
00288 for (int vertical=0; vertical<2; vertical++) {
00289 const int cx = c.x + d*(1-vertical);
00290 const int cy = c.y + d*vertical;
00291 if (cx>=0 && cy>=0) {
00292 const Cell c2((coord_t) cx, (coord_t) cy);
00293 if (withinBounds(g.info, c2)) {
00294 const index_t ind = cellIndex(g.info, c2);
00295 if (g.data[ind]==UNOCCUPIED && !seen[ind]) {
00296 open_list.push(PQItem(ind, current.g_cost + 1, manhattanHeuristic(c2, dest)));
00297 parent[ind] = current.ind;
00298 }
00299 ROS_DEBUG_STREAM_COND_NAMED (g.data[ind]!=UNOCCUPIED, "shortest_path_internal",
00300 " Skipping cell " << indexCell(g.info, ind) <<
00301 " with cost " << (unsigned) g.data[ind]);
00302 }
00303 }
00304 }
00305 }
00306 }
00307
00308 ROS_DEBUG_STREAM_NAMED ("shortest_path", "Computed shortest path. Found = " << (bool) res.is_initialized());
00309 return res;
00310 }
00311
00312
00313
00314
00315
00316
00317
00319 ResultPtr shortestPathResultFromMessage (const NavigationFunction& msg)
00320 {
00321 ShortestPathResult* res = new ShortestPathResult();
00322 ResultPtr retval(res);
00323 res->info = msg.info;
00324 res->src_ind = msg.source;
00325
00326 const index_t num_cells = msg.valid.size();
00327 ROS_ASSERT (num_cells == msg.back_pointers.size());
00328 ROS_ASSERT (num_cells == msg.potential.size());
00329 res->back_pointers.resize(num_cells);
00330 res->potential.resize(num_cells);
00331
00332 for (index_t i=0; i<num_cells; i++) {
00333 if (i==msg.source) {
00334
00335 ROS_ASSERT (msg.back_pointers[i] == 123456);
00336 ROS_ASSERT (msg.potential[i] == -1.0);
00337 res->potential[i] = 0.0;
00338 }
00339 else if (msg.valid[i]) {
00340 res->back_pointers[i] = msg.back_pointers[i];
00341 res->potential[i] = msg.potential[i];
00342 }
00343 else {
00344
00345 ROS_ASSERT (msg.back_pointers[i] == 234567);
00346 ROS_ASSERT (msg.potential[i] == -2.0);
00347 }
00348 }
00349
00350 return retval;
00351 }
00352
00354 NavigationFunction shortestPathResultToMessage (ResultPtr res)
00355 {
00356 NavigationFunction msg;
00357 msg.info = res->info;
00358 msg.source = res->src_ind;
00359
00360 const index_t num_cells=res->back_pointers.size();
00361 ROS_ASSERT (num_cells == res->potential.size());
00362 msg.valid.resize(num_cells);
00363 msg.back_pointers.resize(num_cells);
00364 msg.potential.resize(num_cells);
00365
00366 for (index_t i=0; i<num_cells; i++) {
00367 if (i==msg.source) {
00368 msg.valid[i] = false;
00369 msg.potential[i] = -1.0;
00370 msg.back_pointers[i] = 123456;
00371 }
00372 else if (res->potential[i]) {
00373 msg.valid[i] = true;
00374 msg.potential[i] = *res->potential[i];
00375 msg.back_pointers[i] = *res->back_pointers[i];
00376 }
00377 else {
00378 msg.valid[i] = false;
00379 msg.potential[i] = -2.0;
00380 msg.back_pointers[i] = 234567;
00381 }
00382 }
00383
00384 return msg;
00385 }
00386
00387
00388
00389 }