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 "shortest_path_result.h"
00040 #include <occupancy_grid_utils/shortest_path.h>
00041 #include <ros/assert.h>
00042 #include <queue>
00043
00044 namespace occupancy_grid_utils
00045 {
00046
00047 namespace nm=nav_msgs;
00048 namespace gm=geometry_msgs;
00049
00050 using std::vector;
00051 using boost::optional;
00052 using std::max;
00053
00054 TerminationCondition::TerminationCondition ()
00055 {}
00056
00057 TerminationCondition::TerminationCondition (const double max_distance,
00058 const bool use_cells) :
00059 max_distance_(max_distance), use_cells_(use_cells)
00060 {
00061 if (use_cells_)
00062 ROS_WARN ("Deprecated usage of version of TerminationCondition that uses"
00063 " distance in cells rather than meters. This API will change"
00064 " in a hard-to-debug way in future!");
00065 }
00066
00067 TerminationCondition::TerminationCondition (const Cells& goals) :
00068 goals_(goals)
00069 {
00070 }
00071
00072 TerminationCondition::TerminationCondition (const Cells& goals, const double max_distance,
00073 const bool use_cells) :
00074 max_distance_(max_distance), goals_(goals), use_cells_(use_cells)
00075 {
00076 if (use_cells_)
00077 ROS_WARN ("Deprecated usage of version of TerminationCondition that uses"
00078 " distance in cells rather than meters. This API will change"
00079 " in a hard-to-debug way in future!");
00080 }
00081
00082
00083 typedef vector<Cell> Path;
00084 typedef boost::shared_ptr<nm::OccupancyGrid> GridPtr;
00085
00086 boost::optional<double> distance(ResultPtr res, const Cell& dest)
00087 {
00088 ROS_WARN ("Using deprecated function distance. Use distanceTo instead.");
00089 return res->potential[cellIndex(res->info, dest)];
00090 }
00091
00092 boost::optional<double> distanceTo(ResultPtr res, const Cell& dest)
00093 {
00094 boost::optional<double> d = res->potential[cellIndex(res->info, dest)];
00095 if (d)
00096 return *d * res->info.resolution;
00097 else
00098 return d;
00099 }
00100
00101
00102 boost::optional<Path> extractPath(ResultPtr res, const Cell& dest)
00103 {
00104 boost::optional<Path> p;
00105 index_t current=cellIndex(res->info, dest);
00106 if (!res->back_pointers[current])
00107 return p;
00108
00109 index_t max=res->back_pointers.size();
00110 index_t n=0;
00111 p = Path();
00112
00113 do {
00114 if (n++ > max) {
00115 ROS_FATAL("Cycle in extractPath");
00116 ROS_BREAK();
00117 }
00118 p->push_back(indexCell(res->info, current));
00119 ROS_ASSERT_MSG(res->back_pointers[current], "Back pointer not found for %u", current);
00120 current=*(res->back_pointers[current]);
00121 } while (current!=res->src_ind);
00122 p->push_back(indexCell(res->info, current));
00123 reverse(p->begin(), p->end());
00124 return p;
00125 }
00126
00127
00128
00129 struct QueueItem
00130 {
00131 index_t ind;
00132 double potential;
00133 QueueItem (const index_t ind, const double potential) :
00134 ind(ind), potential(potential) {}
00135 };
00136
00137 bool operator< (const QueueItem& i1, const QueueItem& i2)
00138 {
00139 return i1.potential > i2.potential;
00140 }
00141
00142
00143 ResultPtr singleSourceShortestPaths (const nm::OccupancyGrid& g, const Cell& src,
00144 const bool manhattan)
00145 {
00146 return singleSourceShortestPaths(g, src, TerminationCondition(), manhattan);
00147 }
00148
00149 ResultPtr singleSourceShortestPaths (const nm::OccupancyGrid& g, const Cell& src,
00150 const TerminationCondition& t,
00151 const bool manhattan)
00152 {
00153 verifyDataSize(g);
00154 ShortestPathResult* res = new ShortestPathResult();
00155 ResultPtr result(res);
00156 res->info = g.info;
00157 res->src_ind = cellIndex(g.info, src);
00158 res->back_pointers.resize(g.data.size());
00159 res->potential.resize(g.data.size());
00160
00161 std::priority_queue<QueueItem> q;
00162 q.push(QueueItem(res->src_ind, 0.0));
00163 res->potential[res->src_ind] = 0.0;
00164 ROS_DEBUG_NAMED ("shortest_path", "Computing single source shortest paths from %d, %d", src.x, src.y);
00165
00166 Cells remaining_goals;
00167 if (t.goals_)
00168 remaining_goals = *t.goals_;
00169
00170 while (!q.empty()) {
00171 const QueueItem i=q.top();
00172 q.pop();
00173
00174 const Cell cell = indexCell(g.info, i.ind);
00175 const double dist = i.potential;
00176 const double dist_in_meters = dist*g.info.resolution;
00177 if (t.max_distance_ &&
00178 (*t.max_distance_ < (t.use_cells_ ? dist : dist_in_meters)))
00179 break;
00180 if (t.goals_) {
00181 remaining_goals.erase(cell);
00182 if (remaining_goals.empty())
00183 break;
00184 }
00185
00186 for (int dx=-1; dx<=1; dx++) {
00187 for (int dy=-1; dy<=1; dy++) {
00188 if ((dx==0) && (dy==0))
00189 continue;
00190 if ((dx!=0) && (dy!=0) && manhattan)
00191 continue;
00192 const double d = ((dx==0) || (dy==0)) ? 1 : sqrt(2);
00193 const Cell neighbor(cell.x+dx, cell.y+dy);
00194 if (withinBounds(g.info, neighbor)) {
00195 const index_t ind=cellIndex(g.info, neighbor);
00196 const double new_dist = dist+d;
00197 if (g.data[ind]==UNOCCUPIED &&
00198 (!res->potential[ind] || *(res->potential[ind]) > new_dist) &&
00199 (!t.max_distance_ ||
00200 (t.use_cells_ && *t.max_distance_ >= new_dist) ||
00201 (!t.use_cells_ && *t.max_distance_ >= new_dist*g.info.resolution)))
00202 {
00203 ROS_DEBUG_NAMED ("shortest_path_propagation", "Adding cell %d, %d, at distance %.2f",
00204 neighbor.x, neighbor.y, new_dist);
00205 res->potential[ind] = new_dist;
00206 res->back_pointers[ind] = i.ind;
00207 q.push(QueueItem(ind, new_dist));
00208 }
00209 }
00210 }
00211 }
00212 }
00213 ROS_DEBUG_NAMED ("shortest_path", "Done computing single source shortest paths from %d, %d", src.x, src.y);
00214 return result;
00215 }
00216
00217
00218 inline
00219 bool myGt (const signed char x, const signed char y)
00220 {
00221 return (x==-1 && y==0) || x>y;
00222 }
00223
00224 struct InflationQueueItem
00225 {
00226 InflationQueueItem (const Cell& cell, const signed char cost) :
00227 cell(cell), cost(cost)
00228 {}
00229 Cell cell;
00230 signed char cost;
00231 };
00232
00233 GridPtr inflateObstacles (const nm::OccupancyGrid& g, const double r,
00234 const bool allow_unknown)
00235 {
00236
00237 ROS_ASSERT (r>0);
00238 const int radius = 1+ceil(r/g.info.resolution);
00239 typedef vector<InflationQueueItem> QueueVec;
00240 vector<QueueVec> queues(radius);
00241 GridPtr g2(new nm::OccupancyGrid(g));
00242 const nm::MapMetaData& geom=g.info;
00243
00244
00245 for (coord_t x=0; x<(int)geom.width; x++) {
00246 for (coord_t y=0; y<(int)geom.height; y++) {
00247 const Cell cell(x, y);
00248 const signed char val=g.data[cellIndex(geom, cell)];
00249 if ((allow_unknown && val>=1) || (!allow_unknown && val!=0))
00250 queues[0].push_back(InflationQueueItem(cell, val));
00251 }
00252 }
00253
00254 while (true)
00255 {
00256 int ind=-1;
00257 for (int i=0; i<radius; i++)
00258 {
00259 if (queues[i].size()>0)
00260 {
00261 ind=i;
00262 break;
00263 }
00264 }
00265 if (ind<0)
00266 break;
00267
00268 const InflationQueueItem& q=queues[ind].back();
00269 const index_t index = cellIndex(geom, q.cell);
00270 if (myGt(q.cost, g2->data[index]) || ind==0)
00271 {
00272 g2->data[index] = q.cost;
00273 if (ind<radius-1)
00274 {
00275 for (int vert=0; vert<2; vert ++)
00276 {
00277 for (int d=-1; d<=1; d += 2)
00278 {
00279 const int dx = vert ? 0 : d;
00280 const int dy = vert ? d : 0;
00281 const Cell c2(q.cell.x+dx, q.cell.y+dy);
00282 if (withinBounds(geom, c2))
00283 {
00284 queues[ind+1].push_back(InflationQueueItem(c2, q.cost));
00285 }
00286 }
00287 }
00288 }
00289 }
00290
00291 queues[ind].pop_back();
00292 }
00293 return g2;
00294 }
00295
00296
00297
00298
00299
00300 typedef std::pair<Path, double> AStarResult;
00301 struct PQItem
00302 {
00303 index_t ind;
00304 double g_cost;
00305 double h_cost;
00306 index_t parent_ind;
00307 PQItem (index_t ind, double g_cost, double h_cost, index_t parent_ind) :
00308 ind(ind), g_cost(g_cost), h_cost(h_cost), parent_ind(parent_ind) {}
00309
00310 bool operator< (const PQItem& i2) const
00311 {
00312 return ((g_cost + h_cost) > (i2.g_cost + i2.h_cost));
00313 }
00314 };
00315
00316
00317 inline double manhattanHeuristic (const Cell& c1, const Cell& c2)
00318 {
00319 return fabs(c1.x-c2.x) + fabs(c1.y-c2.y);
00320 }
00321
00322
00323 optional<AStarResult> shortestPathAStar(const nm::OccupancyGrid& g, const Cell& src, const Cell& dest)
00324 {
00325 typedef std::map<index_t, index_t> ParentMap;
00326
00327 const double resolution = g.info.resolution;
00328 std::priority_queue<PQItem> open_list;
00329 const unsigned num_cells = g.info.height*g.info.width;
00330 std::vector<bool> seen(num_cells);
00331 const index_t dest_ind = cellIndex(g.info, dest);
00332 const index_t src_ind = cellIndex(g.info, src);
00333 open_list.push(PQItem(src_ind, 0, resolution*manhattanHeuristic(src, dest), src_ind));
00334 ParentMap parent;
00335
00336 optional<AStarResult> res;
00337 ROS_DEBUG_STREAM_NAMED ("shortest_path", "Computing shortest path from " << src << " to " << dest);
00338
00339 while (!open_list.empty()) {
00340 const PQItem current = open_list.top();
00341 open_list.pop();
00342 const Cell c = indexCell(g.info, current.ind);
00343 if (seen[current.ind])
00344 continue;
00345 parent[current.ind] = current.parent_ind;
00346 seen[current.ind] = true;
00347 ROS_DEBUG_STREAM_NAMED ("shortest_path_internal", " Considering " << c << " with cost " <<
00348 current.g_cost << " + " << current.h_cost);
00349 if (current.ind == dest_ind) {
00350 res = AStarResult();
00351 res->second = current.g_cost;
00352 break;
00353 }
00354
00355 for (int d=-1; d<=1; d+=2) {
00356 for (int vertical=0; vertical<2; vertical++) {
00357 const int cx = c.x + d*(1-vertical);
00358 const int cy = c.y + d*vertical;
00359 if (cx>=0 && cy>=0) {
00360 const Cell c2((coord_t) cx, (coord_t) cy);
00361 if (withinBounds(g.info, c2)) {
00362 const index_t ind = cellIndex(g.info, c2);
00363 if (g.data[ind]==UNOCCUPIED && !seen[ind]) {
00364 open_list.push(PQItem(ind, current.g_cost + resolution,
00365 resolution*manhattanHeuristic(c2, dest),
00366 current.ind));
00367 }
00368 ROS_DEBUG_STREAM_COND_NAMED (g.data[ind]!=UNOCCUPIED, "shortest_path_internal",
00369 " Skipping cell " << indexCell(g.info, ind) <<
00370 " with cost " << (unsigned) g.data[ind]);
00371 }
00372 }
00373 }
00374 }
00375 }
00376
00377
00378 if (res)
00379 {
00380 vector<index_t> path;
00381 path.push_back(dest_ind);
00382 const index_t src_ind = cellIndex(g.info, src);
00383 while (true)
00384 {
00385 index_t last = *(--path.end());
00386 if (last == src_ind)
00387 break;
00388 ParentMap::const_iterator it = parent.find(last);
00389 ROS_ASSERT (it!=parent.end());
00390 index_t parent = it->second;
00391 ROS_ASSERT (parent!=last);
00392 path.push_back(parent);
00393 }
00394 for (int i=path.size()-1; i>=0; i--)
00395 res->first.push_back(indexCell(g.info, path[i]));
00396 }
00397
00398 ROS_DEBUG_STREAM_NAMED ("shortest_path", "Computed shortest path. Found = " << (bool) res.is_initialized());
00399 return res;
00400 }
00401
00402
00403 optional<AStarResult> shortestPath(const nm::OccupancyGrid& g, const Cell& src, const Cell& dest)
00404 {
00405 ROS_WARN ("Using deprecated function shortestPath (use shortestPathAStar)");
00406 std::priority_queue<PQItem> open_list;
00407 const unsigned num_cells = g.info.height*g.info.width;
00408 std::vector<bool> seen(num_cells);
00409 index_t src_ind = cellIndex(g.info, src);
00410 open_list.push(PQItem(src_ind, 0, manhattanHeuristic(src, dest), src_ind));
00411 std::vector<index_t> parent(num_cells);
00412 const index_t dest_ind = cellIndex(g.info, dest);
00413
00414 optional<AStarResult> res;
00415 ROS_DEBUG_STREAM_NAMED ("shortest_path", "Computing shortest path from " << src << " to " << dest);
00416
00417 while (!open_list.empty()) {
00418 const PQItem current = open_list.top();
00419 open_list.pop();
00420 const Cell c = indexCell(g.info, current.ind);
00421 if (seen[current.ind])
00422 continue;
00423 seen[current.ind] = true;
00424 ROS_DEBUG_STREAM_NAMED ("shortest_path_internal", " Considering " << c << " with cost " <<
00425 current.g_cost << " + " << current.h_cost);
00426 if (current.ind == dest_ind) {
00427 res = AStarResult();
00428 res->second = current.g_cost;
00429
00430 break;
00431 }
00432
00433 for (int d=-1; d<=1; d+=2) {
00434 for (int vertical=0; vertical<2; vertical++) {
00435 const int cx = c.x + d*(1-vertical);
00436 const int cy = c.y + d*vertical;
00437 if (cx>=0 && cy>=0) {
00438 const Cell c2((coord_t) cx, (coord_t) cy);
00439 if (withinBounds(g.info, c2)) {
00440 const index_t ind = cellIndex(g.info, c2);
00441 if (g.data[ind]==UNOCCUPIED && !seen[ind]) {
00442 open_list.push(PQItem(ind, current.g_cost + 1, manhattanHeuristic(c2, dest),
00443 current.ind));
00444 parent[ind] = current.ind;
00445 }
00446 ROS_DEBUG_STREAM_COND_NAMED (g.data[ind]!=UNOCCUPIED, "shortest_path_internal",
00447 " Skipping cell " << indexCell(g.info, ind) <<
00448 " with cost " << (unsigned) g.data[ind]);
00449 }
00450 }
00451 }
00452 }
00453 }
00454
00455 ROS_DEBUG_STREAM_NAMED ("shortest_path", "Computed shortest path. Found = " << (bool) res.is_initialized());
00456 return res;
00457 }
00458
00459
00460
00461
00462
00463
00464
00465
00466
00468 ResultPtr shortestPathResultFromMessage (const NavigationFunction& msg)
00469 {
00470 ShortestPathResult* res = new ShortestPathResult();
00471 ResultPtr retval(res);
00472 res->info = msg.info;
00473 res->src_ind = msg.source;
00474
00475 const index_t num_cells = msg.valid.size();
00476 ROS_ASSERT (num_cells == msg.back_pointers.size());
00477 ROS_ASSERT (num_cells == msg.potential.size());
00478 res->back_pointers.resize(num_cells);
00479 res->potential.resize(num_cells);
00480
00481 for (index_t i=0; i<num_cells; i++) {
00482 if (i==msg.source) {
00483
00484 ROS_ASSERT (msg.back_pointers[i] == 123456);
00485 ROS_ASSERT (msg.potential[i] == -1.0);
00486 res->potential[i] = 0.0;
00487 }
00488 else if (msg.valid[i]) {
00489 res->back_pointers[i] = msg.back_pointers[i];
00490 res->potential[i] = msg.potential[i];
00491 }
00492 else {
00493
00494 ROS_ASSERT (msg.back_pointers[i] == 234567);
00495 ROS_ASSERT (msg.potential[i] == -2.0);
00496 }
00497 }
00498
00499 return retval;
00500 }
00501
00503 NavigationFunction shortestPathResultToMessage (ResultPtr res)
00504 {
00505 NavigationFunction msg;
00506 msg.info = res->info;
00507 msg.source = res->src_ind;
00508
00509 const index_t num_cells=res->back_pointers.size();
00510 ROS_ASSERT (num_cells == res->potential.size());
00511 msg.valid.resize(num_cells);
00512 msg.back_pointers.resize(num_cells);
00513 msg.potential.resize(num_cells);
00514
00515 for (index_t i=0; i<num_cells; i++) {
00516 if (i==msg.source) {
00517 msg.valid[i] = false;
00518 msg.potential[i] = -1.0;
00519 msg.back_pointers[i] = 123456;
00520 }
00521 else if (res->potential[i]) {
00522 msg.valid[i] = true;
00523 msg.potential[i] = *res->potential[i];
00524 msg.back_pointers[i] = *res->back_pointers[i];
00525 }
00526 else {
00527 msg.valid[i] = false;
00528 msg.potential[i] = -2.0;
00529 msg.back_pointers[i] = 234567;
00530 }
00531 }
00532
00533 return msg;
00534 }
00535
00536
00537
00538 }