Go to the documentation of this file.00001 #include <lama_common/place_profile_conversions.h>
00002
00003 #define OCCUPIED_THRESHOLD 60 // 0 = free, 100 = occupied.
00004 #define COSTMAP_DISCRETISATION_COUNT 360 // Number of points for the costmap discretisation to obtain a PlaceProfile.
00005
00006 namespace lama_common
00007 {
00008
00011 geometry_msgs::Polygon placeProfileToPolygon(const PlaceProfile& profile)
00012 {
00013 geometry_msgs::Polygon polygon;
00014
00015 polygon.points.reserve(profile.polygon.points.size());
00016
00017 for (size_t i = 0; i < polygon.points.size(); ++i)
00018 {
00019 polygon.points.push_back(polygon.points[i]);
00020 }
00021
00022 return polygon;
00023 }
00024
00027 sensor_msgs::PointCloud placeProfileToPointCloud(const PlaceProfile& profile)
00028 {
00029 sensor_msgs::PointCloud cloud;
00030 cloud.header = profile.header;
00031 for (size_t i = 0; i < profile.polygon.points.size(); ++i)
00032 {
00033 cloud.points.push_back(profile.polygon.points[i]);
00034 }
00035 return cloud;
00036 }
00037
00043 PlaceProfile laserScanToPlaceProfile(const sensor_msgs::LaserScan& scan, double range_cutoff)
00044 {
00045
00046 static laser_geometry::LaserProjection projector;
00047
00048 PlaceProfile profile;
00049 profile.header = scan.header;
00050 size_t size = scan.ranges.size();
00051 profile.polygon.points.reserve(size);
00052
00053 vector<bool> in_range(size, false);
00054 for (size_t i = 0; i < size; ++i)
00055 {
00056 if (scan.ranges[i] < range_cutoff)
00057 {
00058 in_range[i] = true;
00059 }
00060 }
00061
00062 const double greater_than_longest = *(std::max_element(scan.ranges.begin(), scan.ranges.end())) + 1;
00063 sensor_msgs::PointCloud cloud;
00064 projector.projectLaser(scan, cloud, greater_than_longest, laser_geometry::channel_option::None);
00065
00066 if (scan.ranges.size() != cloud.points.size())
00067 {
00068
00069
00070
00071 sensor_msgs::LaserScan copy_of_scan = scan;
00072 const double smaller_than_shortest = *(std::min_element(scan.ranges.begin(), scan.ranges.end())) - 1;
00073 copy_of_scan.range_min = smaller_than_shortest;
00074 projector.projectLaser(copy_of_scan, cloud, greater_than_longest, laser_geometry::channel_option::None);
00075 }
00076
00077 int idx_start;
00078 int idx_end;
00079 int idx_increment;
00080 if (scan.angle_increment > 0)
00081 {
00082 idx_start = 0;
00083 idx_end = size;
00084 idx_increment = 1;
00085 }
00086 else
00087 {
00088 idx_start = size - 1;
00089 idx_end = -1;
00090 idx_increment = -1;
00091 }
00092 for (int i = idx_start; i != idx_end; i += idx_increment)
00093 {
00094 if (in_range[i] && in_range[circular_index(i + idx_increment, size)])
00095 {
00096
00097 profile.polygon.points.push_back(cloud.points[i]);
00098 }
00099 else if (in_range[i] && !in_range[circular_index(i + idx_increment, size)])
00100 {
00101
00102
00103 profile.polygon.points.push_back(cloud.points[i]);
00104 profile.exclude_segments.push_back(profile.polygon.points.size() - 1);
00105 }
00106 }
00107
00108 if (!profile.exclude_segments.empty() && (profile.exclude_segments.front() == -1))
00109 {
00110
00111
00112 profile.exclude_segments[0] = profile.polygon.points.size() - 1;
00113 }
00114
00115 normalizePlaceProfile(profile);
00116 return profile;
00117 }
00118
00121 inline bool pointOccupied(const nav_msgs::OccupancyGrid& map, const int index)
00122 {
00123 return (map.data[index] > OCCUPIED_THRESHOLD);
00124 }
00125
00128 inline bool pointUnknown(const nav_msgs::OccupancyGrid& map, const int index)
00129 {
00130 return (map.data[index] == -1);
00131 }
00132
00150 bool firstNonFree(const nav_msgs::OccupancyGrid& map, double angle, double range_cutoff, geometry_msgs::Point32& point)
00151 {
00152 static map_ray_caster::MapRayCaster ray_caster;
00153 const vector<size_t>& ray = ray_caster.getRayCastToMapBorder(angle, map.info.height, map.info.width);
00154
00155
00156
00157
00158 size_t pixel_range = ray.size();
00159 double cos_angle;
00160 double sin_angle;
00161 if (std::abs(range_cutoff) > 1e-10)
00162 {
00163 cos_angle = std::cos(angle);
00164 sin_angle = std::sin(angle);
00165 pixel_range = lround(range_cutoff * std::max(std::abs(cos_angle), std::abs(sin_angle)) / map.info.resolution);
00166 }
00167
00168 for (size_t i = 0; i < ray.size(); ++i)
00169 {
00170 size_t idx = ray[i];
00171
00172 if (i >= pixel_range)
00173 {
00174 point.x = range_cutoff * cos_angle;
00175 point.y = range_cutoff * sin_angle;
00176 return false;
00177 }
00178 if (pointOccupied(map, idx))
00179 {
00180 map_ray_caster::indexToReal(map, idx, point);
00181 return true;
00182 }
00183 if (pointUnknown(map, idx))
00184 {
00185 map_ray_caster::indexToReal(map, idx, point);
00186 return false;
00187 }
00188 }
00189 map_ray_caster::indexToReal(map, ray.back(), point);
00190 return false;
00191 }
00192
00197 PlaceProfile costmapToPlaceProfile(const nav_msgs::OccupancyGrid& map, double range_cutoff)
00198 {
00199 PlaceProfile profile;
00200 profile.header = map.header;
00201 profile.polygon.points.reserve(COSTMAP_DISCRETISATION_COUNT);
00202
00203
00204
00205 const double angle_min = -M_PI + 1e-6;
00206 const double resolution = 2 * M_PI / COSTMAP_DISCRETISATION_COUNT;
00207 geometry_msgs::Point32 last_point;
00208
00209 last_point.x = map.info.width * map.info.resolution;
00210 geometry_msgs::Point32 this_point;
00211 geometry_msgs::Point32 next_point;
00212 bool this_in_range = firstNonFree(map, angle_min, range_cutoff, this_point);
00213 double next_angle = angle_min + resolution;
00214 for (size_t i = 0; i < COSTMAP_DISCRETISATION_COUNT; ++i)
00215 {
00216 bool next_in_range = firstNonFree(map, next_angle, range_cutoff, next_point);
00217 if (this_in_range)
00218 {
00219 if ((this_point.x != last_point.x) || (this_point.y != last_point.y))
00220 {
00221 profile.polygon.points.push_back(this_point);
00222 }
00223 }
00224 else if (next_in_range)
00225 {
00226 profile.exclude_segments.push_back(profile.polygon.points.size() - 1);
00227 }
00228 next_angle += resolution;
00229 last_point = this_point;
00230 this_point = next_point;
00231 this_in_range = next_in_range;
00232 }
00233 if (!profile.exclude_segments.empty() && (profile.exclude_segments.front() == -1))
00234 {
00235
00236
00237 profile.exclude_segments[0] = profile.polygon.points.size() - 1;
00238 }
00239
00240 return profile;
00241 }
00242
00243 }
00244