map_ray_caster.cpp
Go to the documentation of this file.
00001 #include <map_ray_caster/map_ray_caster.h>
00002 
00003 namespace map_ray_caster
00004 {
00005 
00006 MapRayCaster::MapRayCaster(const int occupied_threshold) :
00007   occupied_threshold_(occupied_threshold)
00008 {
00009 }
00010 
00013 inline bool pointOccupied(const nav_msgs::OccupancyGrid& map, const int index, const int occupied_threshold)
00014 {
00015   return (map.data[index] > occupied_threshold) || (map.data[index] == -1);
00016 }
00017 
00029 void MapRayCaster::laserScanCast(const nav_msgs::OccupancyGrid& map, sensor_msgs::LaserScan& scan)
00030 {
00031   scan.ranges.clear();
00032   for (double angle = scan.angle_min; angle <= scan.angle_max + 1e-6; angle += scan.angle_increment)
00033   {
00034     // Max pixel count for scan.range_max if it were "bitmapped".
00035     const size_t pixel_range = lround(scan.range_max / map.info.resolution) + 1;
00036     const std::vector<size_t>& ray = getRayCastToMapBorder(angle,
00037         map.info.height, map.info.width, scan.angle_increment / 2);
00038     const size_t max_size = std::min(ray.size(), pixel_range);
00039     geometry_msgs::Point32 p;
00040     indexToReal(map, ray.back(), p);
00041     double range = std::min(0.99 * scan.range_max, (double)std::sqrt(p.x * p.x + p.y * p.y));
00042     for (size_t i = 0; i < max_size; ++i)
00043     {
00044       const size_t idx = ray[i];
00045       if (pointOccupied(map, idx, occupied_threshold_))
00046       {
00047         geometry_msgs::Point32 p;
00048         indexToReal(map, idx, p);
00049         range = std::sqrt(p.x * p.x + p.y * p.y);
00050         break;
00051       }
00052     }
00053     if (range > scan.range_max)
00054     {
00055       range = 0.99 * scan.range_max;
00056     }
00057     scan.ranges.push_back(range);
00058   }
00059 }
00060 
00071 const std::vector<size_t>& MapRayCaster::getRayCastToMapBorder(const double angle, const size_t nrow, const size_t ncol, const double tolerance)
00072 {
00073   // Check that parameters are compatible with the cache. If not, erase the cache.
00074   if (nrow != nrow_ || ncol != ncol_)
00075   {
00076     raycast_lookup_.clear();
00077     nrow_ = nrow;
00078     ncol_ = ncol;
00079   }
00080 
00081   RayLookup::const_iterator ray = angleLookup(angle, tolerance);
00082   if (ray != raycast_lookup_.end())
00083   {
00084     return ray->second;
00085   }
00086 
00087   std::vector<size_t> pts;
00088 
00089   // Twice the distance from map center to map corner.
00090   const double r = std::sqrt((double) nrow * nrow + ncol * ncol);
00091   // Start point, map center.
00092   // TODO: the sensor position (map origin)  may not be the map center
00093   int x0 = ncol / 2;
00094   int y0 = nrow / 2;
00095   // End point, outside the map.
00096   int x1 = (int) round(x0 + r * std::cos(angle)); // Can be negative
00097   int y1 = (int) round(y0 + r * std::sin(angle));
00098   int dx = x1 - x0;
00099   int dy = y1 - y0;
00100   bool steep = (std::abs(dy) >= std::abs(dx));
00101   if (steep)
00102   {
00103     std::swap(x0, y0);
00104     std::swap(x1, y1);
00105     // recompute Dx, Dy after swap
00106     dx = x1 - x0;
00107     dy = y1 - y0;
00108   }
00109   int xstep = 1;
00110   if (dx < 0)
00111   {
00112     xstep = -1;
00113     dx = -dx;
00114   }
00115   int ystep = 1;
00116   if (dy < 0)
00117   {
00118     ystep = -1;
00119     dy = -dy;
00120   }
00121   int twoDy = 2 * dy;
00122   int twoDyTwoDx = twoDy - 2 * dx; // 2*Dy - 2*Dx
00123   int e = twoDy - dx; //2*Dy - Dx
00124   int y = y0;
00125   int xDraw, yDraw;
00126   for (int x = x0; x != x1; x += xstep)
00127   {
00128     if (steep)
00129     {
00130       xDraw = y;
00131       yDraw = x;
00132     }
00133     else
00134     {
00135       xDraw = x;
00136       yDraw = y;
00137     }
00138     if (pointInMap(yDraw, xDraw, nrow, ncol))
00139     {
00140       pts.push_back(offsetFromRowCol(yDraw, xDraw, ncol));
00141     }
00142     else
00143     {
00144       // We exit when the first point outside the map is encountered.
00145       raycast_lookup_[angle] = pts;
00146       return raycast_lookup_[angle];
00147     }
00148     // next
00149     if (e > 0)
00150     {
00151       e += twoDyTwoDx; //E += 2*Dy - 2*Dx;
00152       y = y + ystep;
00153     }
00154     else
00155     {
00156       e += twoDy; //E += 2*Dy;
00157     }
00158   }
00159 }
00160 
00166 RayLookup::const_iterator MapRayCaster::angleLookup(const double angle, const double tolerance)
00167 {
00168   if (tolerance == 0)
00169   {
00170     return raycast_lookup_.find(angle);
00171   }
00172 
00173   double dangle_lower;
00174   double dangle_upper;
00175 
00176   RayLookup::const_iterator upper_bound = raycast_lookup_.upper_bound(angle);
00177   if (upper_bound == raycast_lookup_.begin())
00178   {
00179     if (std::abs(angles::shortest_angular_distance(angle, upper_bound->first)) <= tolerance)
00180     {
00181       return upper_bound;
00182     }
00183     return raycast_lookup_.end();
00184   }
00185   else if (upper_bound == raycast_lookup_.end())
00186   {
00187     dangle_upper = raycast_lookup_.begin()->first - angle + 2 * M_PI;
00188     upper_bound--;
00189     dangle_lower = upper_bound->first - angle;
00190     if (dangle_lower < dangle_upper)
00191     {
00192       if (std::abs(angles::shortest_angular_distance(angle, upper_bound->first)) <= tolerance)
00193       {
00194         return upper_bound;
00195       }
00196       return raycast_lookup_.end();
00197     }
00198     else
00199     {
00200       if (std::abs(angles::shortest_angular_distance(angle, raycast_lookup_.begin()->first)) <= tolerance)
00201       {
00202         return raycast_lookup_.begin();
00203       }
00204       return raycast_lookup_.end();
00205     }
00206   }
00207   else
00208   {
00209     dangle_upper = upper_bound->first - angle;
00210     RayLookup::const_iterator lower_bound = upper_bound;
00211     lower_bound--;
00212     dangle_lower = angle - lower_bound->first;
00213     if (dangle_lower < dangle_upper)
00214     {
00215       if (std::abs(angles::shortest_angular_distance(angle, lower_bound->first)) <= tolerance)
00216       {
00217         return lower_bound;
00218       }
00219       return raycast_lookup_.end();
00220     }
00221     else
00222     {
00223       if (std::abs(angles::shortest_angular_distance(angle, upper_bound->first)) <= tolerance)
00224       {
00225         return upper_bound;
00226       }
00227       return raycast_lookup_.end();
00228     }
00229   }
00230 }
00231 
00232 } // namespace map_ray_caster


map_ray_caster
Author(s): Gaƫl Ecorchard
autogenerated on Thu Jun 6 2019 22:02:02