00001 #include <occupancy_grid_utils/ray_tracer.h>
00002 #include <occupancy_grid_utils/exceptions.h>
00003 #include <tf/transform_datatypes.h>
00004 #include <boost/bind.hpp>
00005 #include <boost/ref.hpp>
00006 #include <boost/foreach.hpp>
00007 #include <boost/optional.hpp>
00008 #include <algorithm>
00009 #include <ros/assert.h>
00010
00011 namespace occupancy_grid_utils
00012 {
00013
00014 namespace nm=nav_msgs;
00015 namespace gm=geometry_msgs;
00016 namespace sm=sensor_msgs;
00017
00018 using boost::bind;
00019 using boost::ref;
00020 using boost::optional;
00021
00022 RayTraceIterRange rayTrace (const Cell& c1, const Cell& c2)
00023 {
00024 return RayTraceIterRange(RayTraceIterator(c1,c2), RayTraceIterator(c2,c2,true));
00025 }
00026
00027 inline
00028 bool cellWithinBounds (const nm::MapMetaData& info, const Cell& c)
00029 {
00030 return withinBounds(info, c);
00031 }
00032
00033 optional<Cell> rayTraceOntoGrid (const nm::MapMetaData& info, const Cell& c1, const Cell& c2)
00034 {
00035 RayTraceIterRange r = rayTrace(c2, c1);
00036 RayTraceIterator pos = std::find_if (r.first, r.second, bind(cellWithinBounds, ref(info), _1));
00037 optional<Cell> c;
00038 if (pos!=r.second)
00039 c = *pos;
00040 return c;
00041 }
00042
00043 RayTraceIterRange rayTrace (const nm::MapMetaData& info, const gm::Point& p1, const gm::Point& p2,
00044 bool project_onto_grid, bool project_source_onto_grid)
00045 {
00046 Cell c1 = pointCell(info, p1);
00047 Cell c2 = pointCell(info, p2);
00048 ROS_DEBUG_STREAM_NAMED ("ray_trace", "Ray tracing between " << c1.x <<
00049 ", " << c1.y << " and " << c2.x << ", " << c2.y);
00050 const RayTraceIterator done(c1, c1, true);
00051 const RayTraceIterRange empty_range(done, done);
00052 if (!withinBounds(info, c1)) {
00053 if (project_source_onto_grid) {
00054 const optional<Cell> c = rayTraceOntoGrid(info, c2, c1);
00055 if (c)
00056 c1 = *c;
00057 else
00058 return empty_range;
00059 }
00060 else
00061 throw PointOutOfBoundsException(p1);
00062 }
00063
00064 if (!withinBounds(info, p2)) {
00065 if (project_onto_grid) {
00066 const optional<Cell> c = rayTraceOntoGrid(info, c1, c2);
00067 if (c)
00068 c2 = *c;
00069 else
00070 return empty_range;
00071 }
00072 else {
00073 throw PointOutOfBoundsException(p2);
00074 }
00075 }
00076
00077 ROS_DEBUG_STREAM_NAMED ("ray_trace", "Projected ray trace endpoints to " << c1.x <<
00078 ", " << c1.y << " and " << c2.x << ", " << c2.y);
00079 return rayTrace(c1, c2);
00080 }
00081
00082
00083 gm::Point rayEndPoint (const gm::Point& p0, const double theta, const double d)
00084 {
00085 gm::Point p;
00086 p.x = p0.x + cos(theta)*d;
00087 p.y = p0.y + sin(theta)*d;
00088 return p;
00089 }
00090
00091 sm::LaserScan::Ptr
00092 simulateRangeScan (const nm::OccupancyGrid& grid, const gm::Pose& sensor_pose,
00093 const sm::LaserScan& scanner_info, const bool unknown_obstacles)
00094 {
00095 sm::LaserScan::Ptr result(new sm::LaserScan(scanner_info));
00096
00097 const double angle_range = scanner_info.angle_max - scanner_info.angle_min;
00098 const unsigned n =
00099 (unsigned) round(1+angle_range/scanner_info.angle_increment);
00100 const gm::Point& p0 = sensor_pose.position;
00101 const Cell c0 = pointCell(grid.info, p0);
00102 const double theta0 = tf::getYaw(sensor_pose.orientation);
00103 result->ranges.resize(n);
00104
00105 for (unsigned i=0; i<n; i++)
00106 {
00107 const double theta = scanner_info.angle_min+i*scanner_info.angle_increment;
00108 const gm::Point scan_max =
00109 rayEndPoint(p0, theta0 + theta, scanner_info.range_max+1);
00110
00111 result->ranges[i] = scanner_info.range_max+1;
00112 BOOST_FOREACH (const Cell& c, rayTrace(grid.info, p0, scan_max, true))
00113 {
00114 const gm::Point p = cellCenter(grid.info, c);
00115 const double d = sqrt(pow(p.x-p0.x, 2) + pow(p.y-p0.y, 2));
00116 char data = grid.data[cellIndex(grid.info, c)];
00117 if (d > scanner_info.range_max)
00118 break;
00119 else if (data == OCCUPIED && !(c==c0))
00120 {
00121 result->ranges[i] = d;
00122 break;
00123 }
00124 else if (data == UNKNOWN && !(c==c0))
00125 {
00126 result->ranges[i] = unknown_obstacles ? d : scanner_info.range_max+1;
00127 break;
00128 }
00129 }
00130 }
00131
00132 return result;
00133 }
00134
00135
00136 }