shortest_path.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 
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; // No path exists
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); // Can take this out eventually
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  * A*
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); // Default initialized to all false
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       // Todo fill in path
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  * Ros message conversion
00316  ************************************************************/
00317 
00319 ResultPtr shortestPathResultFromMessage (const NavigationFunction& msg)
00320 {
00321   ShortestPathResult* res = new ShortestPathResult();
00322   ResultPtr retval(res); // retval is a pointer to const, so we modify via 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       // Sanity check
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       // Sanity check
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 } // namespace occupancy_grid_utils


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