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
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
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
00090 const double r = std::sqrt((double) nrow * nrow + ncol * ncol);
00091
00092
00093 int x0 = ncol / 2;
00094 int y0 = nrow / 2;
00095
00096 int x1 = (int) round(x0 + r * std::cos(angle));
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
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;
00123 int e = twoDy - 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
00145 raycast_lookup_[angle] = pts;
00146 return raycast_lookup_[angle];
00147 }
00148
00149 if (e > 0)
00150 {
00151 e += twoDyTwoDx;
00152 y = y + ystep;
00153 }
00154 else
00155 {
00156 e += twoDy;
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 }