00001 #include <iostream>
00002 #include <fstream>
00003 #include <algorithm>
00004 #include <queue>
00005 #include "properties.hpp"
00006 #include "occupancy_grid.hpp"
00007 #include "cone_tracing.hpp"
00008
00009 using namespace Arak;
00010
00011 OccupancyGrid::OccupancyGrid(const Arak::Util::PropertyMap& props) {
00012 using namespace Arak::Util;
00013
00014 int n = 1;
00015 if (hasp(props, "arak.occupancy_grid.grid_size")) {
00016 parse(getp(props, "arak.occupancy_grid.grid_size"), n);
00017 assert(n > 0);
00018 }
00019 double x, y, width, height;
00020 assert(parse(getp(props, "arak.occupancy_grid.xmin"), x));
00021 assert(parse(getp(props, "arak.occupancy_grid.ymin"), y));
00022 assert(parse(getp(props, "arak.occupancy_grid.width"), width));
00023 assert(parse(getp(props, "arak.occupancy_grid.height"), height));
00024 Geometry::Rectangle r(x, y, x + width, y + height);
00025 double aspect_ratio = width / height;
00026 int rows = std::max(1, int(sqrt(double(n) / aspect_ratio)));
00027 int cols = n / rows;
00028 grid = new EstimatorGrid(r, rows, cols);
00029 for (int i = 0; i < rows; i++)
00030 for (int j = 0; j < cols; j++) {
00031 EstimatorGrid::Cell& cell = grid->getCell(i, j);
00032 OccupancyEstimator* est = new OccupancyEstimator();
00033 cell.add(est);
00034 }
00035
00036 if (hasp(props, "arak.obs_type")) {
00037 const std::string& obs_type = getp(props, "arak.obs_type");
00038 if (obs_type == "range") {
00039
00040 double maxRange, obstacleWidth, p_given_occ, p_given_free;
00041 assert(parse(getp(props, "arak.range_obs.max_range"), maxRange));
00042 assert(parse(getp(props, "arak.occupancy_grid.obstacle_width"), obstacleWidth));
00043 assert(parse(getp(props, "arak.occupancy_grid.p_given_occ"), p_given_occ));
00044 assert(parse(getp(props, "arak.occupancy_grid.p_given_free"), p_given_free));
00045
00046 const std::string& datafile_path =
00047 getp(props, "arak.range_obs.data_file");
00048 std::ifstream in(datafile_path.data());
00049 assert(in.good());
00050 int n;
00051 in >> n;
00052 std::vector<Geometry::Point> impacts;
00053 Geometry::Point source, impact;
00054 in >> source >> impact;
00055 impacts.push_back(impact);
00056 for (int i = 1; i < n; i++) {
00057 Geometry::Point new_source;
00058 in >> new_source >> impact;
00059 if (new_source == source)
00060 impacts.push_back(impact);
00061 else {
00062 laser_scan(source, impacts, maxRange,
00063 obstacleWidth, p_given_occ, p_given_free);
00064 source = new_source;
00065 impacts.clear();
00066 impacts.push_back(impact);
00067 }
00068 }
00069 laser_scan(source, impacts, maxRange, obstacleWidth, p_given_occ, p_given_free);
00070
00071
00072
00073
00074
00075
00076
00077 } else if (obs_type == "sonar") {
00078
00079 double width, maxRange, obstacleWidth;
00080 assert(parse(getp(props, "arak.sonar_obs.width"), width));
00081 assert(parse(getp(props, "arak.sonar_obs.max_range"), maxRange));
00082 assert(parse(getp(props, "arak.occupancy_grid.obstacle_width"), obstacleWidth));
00083 double p_given_occ, p_given_free;
00084 assert(parse(getp(props, "arak.occupancy_grid.p_given_occ"), p_given_occ));
00085 assert(parse(getp(props, "arak.occupancy_grid.p_given_free"), p_given_free));
00086
00087 const std::string& datafile_path =
00088 getp(props, "arak.range_obs.data_file");
00089 std::ifstream in(datafile_path.data());
00090 assert(in.good());
00091 int n;
00092 in >> n;
00093 for (int i = 0; i < n; i++) {
00094 Geometry::Point source;
00095 double angle, range;
00096 in >> source >> angle >> range;
00097 sonar(source, angle, range, maxRange, obstacleWidth, width,
00098 p_given_occ, p_given_free);
00099 }
00100 } else {
00101 std::cerr << "Unrecognized observation type: "
00102 << obs_type << std::endl;
00103 }
00104 }
00105 }
00106
00107 OccupancyGrid::~OccupancyGrid() {
00108 for (int i = grid->numRows() - 1; i >= 0; i--) {
00109 for (int j = 0; j < grid->numCols(); j++) {
00110 EstimatorGrid::Cell& cell = grid->getCell(i, j);
00111 delete *(cell.getItemList().begin());
00112 }
00113 }
00114 delete grid;
00115 }
00116
00117 void OccupancyGrid::laser(const Geometry::Point& source,
00118 const Geometry::Point& impact,
00119 double maxRange,
00120 double obstacleWidth,
00121 double p_given_occ,
00122 double p_given_free) {
00123
00124 if (CGAL::to_double(CGAL::squared_distance(source, impact)) >
00125 maxRange * maxRange)
00126 return;
00127
00128 const Geometry::Vector v = impact - source;
00129 double range = sqrt(CGAL::to_double(v.squared_length()));
00130 const Geometry::Point max = source + v * (maxRange / range);
00131
00132 Geometry::Segment obstacle(impact, impact + v * (obstacleWidth / range));
00133
00134 typedef EstimatorGrid::LineCellIterator Iterator;
00135 Iterator it(*grid, source, obstacle.target(), Iterator::SEGMENT()), end;
00136 bool free = true;
00137 do {
00138 EstimatorGrid::Cell& cell = *it;
00139 OccupancyEstimator* est = *(cell.getItemList().begin());
00140
00141 if (free && !cell.has_on_unbounded_side(impact)) free = false;
00142 if (free) {
00143 est->condition(p_given_free);
00144 } else
00145 est->condition(p_given_occ);
00146 } while (++it != end);
00147 }
00148
00149 void OccupancyGrid::laser_scan(const Geometry::Point& source,
00150 const std::vector<Geometry::Point>& impacts,
00151 double maxRange,
00152 double obstacleWidth,
00153 double p_given_occ,
00154 double p_given_free) {
00155
00156
00157
00158 double xmin = source.x(), xmax = source.x(),
00159 ymin = source.y(), ymax = source.y();
00160 for (unsigned int i = 0; i < impacts.size(); i++) {
00161 xmin = std::min(xmin, impacts[i].x() - obstacleWidth);
00162 xmax = std::max(xmax, impacts[i].x() + obstacleWidth);
00163 ymin = std::min(ymin, impacts[i].y() - obstacleWidth);
00164 ymax = std::max(ymax, impacts[i].y() + obstacleWidth);
00165 }
00166
00167 typedef EstimatorGrid::RectangleCellIterator Iterator;
00168 Iterator it(*grid, Geometry::Rectangle(xmin, ymin, xmax, ymax)), end;
00169 while (it != end) {
00170 EstimatorGrid::Cell& cell = *it;
00171 OccupancyEstimator* est = *(cell.getItemList().begin());
00172
00173 Geometry::Point center = CGAL::midpoint(cell[0], cell[2]);
00174
00175 unsigned int closest = 0;
00176 double dist = std::numeric_limits<double>::infinity();
00177 for (unsigned int i = 0; i < impacts.size(); i++) {
00178 Geometry::Line line(source, impacts[i]);
00179 Geometry::Point projection = line.projection(center);
00180 double d = sqrt(CGAL::to_double(CGAL::squared_distance(center, projection)));
00181 if (d < dist) {
00182 closest = i;
00183 dist = d;
00184 }
00185 }
00186
00187 double angle_to_center = atan2(center.y() - source.y(),
00188 center.x() - source.x());
00189 double beam_angle = atan2(impacts[closest].y() - source.y(),
00190 impacts[closest].x() - source.x());
00191
00192 if ((fabs(angle_to_center - beam_angle) < M_PI / 180.0)
00193 &&
00194 (CGAL::to_double(CGAL::squared_distance(source, impacts[closest])) <
00195 maxRange * maxRange)) {
00196
00197 double obs_range =
00198 sqrt(CGAL::to_double(CGAL::squared_distance(impacts[closest], source)));
00199 double center_range =
00200 sqrt(CGAL::to_double(CGAL::squared_distance(center, source)));
00201 if (fabs(obs_range - center_range) < obstacleWidth / 2.0)
00202 est->condition(p_given_occ);
00203 else if (obs_range > center_range)
00204 est->condition(p_given_free);
00205 }
00206 ++it;
00207 }
00208 }
00209
00210 void OccupancyGrid::sonar(const Geometry::Point& source,
00211 double angle,
00212 double range,
00213 double maxRange,
00214 double obstacleWidth,
00215 double width,
00216 double p_given_occ,
00217 double p_given_free) {
00218 double minAngle = angle - width / 2.0;
00219 double maxAngle = angle + width / 2.0;
00220 Geometry::Direction min(cos(minAngle), sin(minAngle));
00221 Geometry::Direction max(cos(maxAngle), sin(maxAngle));
00222 range = std::min(range, maxRange);
00223 Geometry::Triangle t =
00224 outerApprox(source, min, max, Geometry::Kernel::FT(range));
00225 typedef EstimatorGrid::TriangleCellIterator Iterator;
00226 for (Iterator it = Iterator(*grid, t); it != Iterator(); ++it) {
00227 EstimatorGrid::Cell& cell = *it;
00228 OccupancyEstimator* est = *(cell.getItemList().begin());
00229
00230 Geometry::Point p = CGAL::midpoint(cell.min(), cell.max());
00231
00232 double r = sqrt(CGAL::to_double(CGAL::squared_distance(source, p)));
00233 Geometry::Direction d = (p - source).direction();
00234
00235 if (d.counterclockwise_in_between(min, max)) {
00236
00237
00238 if (r < (range - (obstacleWidth / 2.0))) {
00239
00240 est->condition(p_given_free);
00241 } else if ((range < maxRange) &&
00242 (r <= (range + (obstacleWidth / 2.0)))) {
00243
00244 est->condition(p_given_occ);
00245 }
00246 }
00247 }
00248 }
00249