Go to the documentation of this file.00001
00005 #ifndef _GRID_MAP_H
00006 #define _GRID_MAP_H
00007
00008 #include <memory>
00009 #include <cmath>
00010
00011 #include "cell_occupancy_estimator.h"
00012 #include "grid_cell_factory.h"
00013 #include "../geometry_utils.h"
00014
00015 struct GridMapParams {
00016 double width, height, meters_per_cell;
00017 };
00018
00022 class GridMap {
00023 public:
00024 using Cell = std::shared_ptr<GridCell>;
00025 private:
00026 using Row = std::vector<Cell>;
00027 using Map = std::vector<Row>;
00028
00029 public:
00030
00035 GridMap(std::shared_ptr<GridCellFactory> cell_factory,
00036 const GridMapParams &init_params) :
00037 _width(std::floor(init_params.width/init_params.meters_per_cell)),
00038 _height(std::floor(init_params.height/init_params.meters_per_cell)),
00039 _m_per_cell(init_params.meters_per_cell),
00040 _cell_factory(cell_factory), _cells(_height) {
00041
00042 _map_center_x = std::floor((float)_width /2);
00043 _map_center_y = std::floor((float)_height/2);
00044
00045 for (auto &row : _cells) {
00046 for (int i = 0; i < _width; i++) {
00047 row.push_back(cell_factory->create_cell());
00048 }
00049 }
00050 _unvisited_cell = cell_factory->create_cell();
00051 }
00052
00054 int width() const { return _width; }
00055
00057 int height() const { return _height; }
00058
00060 double scale() const { return _m_per_cell; }
00061
00063 const std::vector<std::vector<Cell>> cells() const { return _cells; }
00064
00065 #define COL_IND(cell_coord) \
00066 ((cell_coord).x + _map_center_x)
00067 #define ROW_IND(cell_coord) \
00068 ((cell_coord).y + _map_center_y)
00069
00076 void update_cell(const DiscretePoint2D& cell_coord,
00077 const Occupancy &new_value, double quality = 1.0) {
00078
00079 update_size(cell_coord);
00080
00081 int row = ROW_IND(cell_coord);
00082 int col = COL_IND(cell_coord);
00083 _cells[row][col]->set_value(new_value, quality);
00084 }
00085
00090 double cell_value(const DiscretePoint2D& cell_coord) const {
00091 if (!has_cell(cell_coord))
00092 return _unvisited_cell->value();
00093
00094 return _cells[ROW_IND(cell_coord)][COL_IND(cell_coord)]->value();
00095 }
00096
00101 DiscretePoint2D world_to_cell(double x, double y) const {
00102 #define METERS_TO_CELLS(var) \
00103 std::floor((var)/_m_per_cell)
00104
00105 return DiscretePoint2D(METERS_TO_CELLS(x), METERS_TO_CELLS(y));
00106 #undef METERS_TO_CELLS
00107 }
00108
00110 double cell_scale() const { return _m_per_cell; }
00111
00117 Rectangle world_cell_bounds(const DiscretePoint2D &cell_coord) {
00118 Rectangle bounds;
00119 bounds.bot = cell_coord.y * _m_per_cell;
00120 bounds.top = bounds.bot + _m_per_cell;
00121 bounds.left = cell_coord.x * _m_per_cell;
00122 bounds.right = bounds.left + _m_per_cell;
00123 return bounds;
00124 }
00125
00129 int map_center_x() const { return _map_center_x; }
00133 int map_center_y() const { return _map_center_y; }
00134
00135 private:
00136 bool has_cell(const DiscretePoint2D& cell_coord) const {
00137 return 0 <= COL_IND(cell_coord) && COL_IND(cell_coord) < _width &&
00138 0 <= ROW_IND(cell_coord) && ROW_IND(cell_coord) < _height;
00139 }
00140
00141 void update_size(const DiscretePoint2D& cell_coord) {
00142 resize_bound(RESIZE_HORZ, COL_IND(cell_coord));
00143 resize_bound(RESIZE_VERT, ROW_IND(cell_coord));
00144 }
00145
00146 #define RESIZE_DIR(DIM,DIR) \
00147 (((DIM) << RESIZE_DIM_BIT) | ((DIR) << RESIZE_DIR_BIT))
00148
00149 void resize_bound(const int dim, const int container_coord) {
00150 if (dim != RESIZE_HORZ && dim != RESIZE_VERT)
00151 return;
00152
00153 int bound = (dim == RESIZE_HORZ ? width() : height());
00154
00155 int new_bound = calc_sufficient_bound(container_coord, bound);
00156 if (new_bound == bound)
00157 return;
00158
00159
00160 int expand_rate = closest_bounded_power_two(new_bound/bound) - 1;
00161 resize_in_direction(expand_rate*bound, RESIZE_DIR(dim, container_coord<0));
00162 }
00163
00164 int calc_sufficient_bound(const int container_coord, const int map_bound) {
00165 if (container_coord < 0)
00166 return (-container_coord)+map_bound;
00167 if (map_bound <= container_coord)
00168 return container_coord + 1;
00169 return map_bound;
00170 }
00171
00172
00173
00174
00175
00176
00177 long closest_bounded_power_two(long x) {
00178 long p2 = 1;
00179 while (p2 <= x) {
00180 p2 <<= 1;
00181 }
00182 return p2;
00183 }
00184
00185 void resize_in_direction(const int delta, const int direction_flag) {
00186 if (delta <= 0)
00187 return;
00188
00189 if (direction_flag == RESIZE_DOWN) {
00190 add_rows(delta, _cells.begin());
00191 _map_center_y += delta;
00192 } else if (direction_flag == RESIZE_UP) {
00193 add_rows(delta, _cells.end());
00194 } else if (direction_flag == RESIZE_LEFT) {
00195 add_cols(delta, [](Row& vector) { return vector.begin(); });
00196 _map_center_x += delta;
00197 } else if (direction_flag == RESIZE_RIGHT) {
00198 add_cols(delta, [](Row& vector) { return vector.end(); });
00199 }
00200 }
00201
00202 void add_rows(const int rows_count, Map::iterator it) {
00203 Map new_rows(rows_count, Row(width()));
00204 for (auto& row : new_rows) {
00205 for (auto& cell : row) {
00206 cell = _cell_factory->create_cell();
00207 }
00208 }
00209 _cells.insert(it, new_rows.begin(), new_rows.end());
00210 _height += rows_count;
00211 }
00212
00213 void add_cols(const int cols_count, std::function<Row::iterator(Row&)> it) {
00214 Map new_cols(height(), Row(cols_count));
00215 for (auto& row : new_cols) {
00216 for (auto& cell : row) {
00217 cell = _cell_factory->create_cell();
00218 }
00219 }
00220 for (size_t i = 0; i < new_cols.size(); i++) {
00221 _cells[i].insert(it(_cells[i]), new_cols[i].begin(), new_cols[i].end());
00222 }
00223 _width += cols_count;
00224 }
00225 #undef INDEX_I
00226 #undef INDEX_J
00227
00228 private:
00229 const int RESIZE_VERT = 0;
00230 const int RESIZE_HORZ = 1;
00231 const int RESIZE_DIM_BIT = 1;
00232
00233 const int RESIZE_FWD = 0;
00234 const int RESIZE_BWD = 1;
00235 const int RESIZE_DIR_BIT = 0;
00236
00237 const int RESIZE_UP = RESIZE_DIR(RESIZE_VERT, RESIZE_FWD);
00238 const int RESIZE_DOWN = RESIZE_DIR(RESIZE_VERT, RESIZE_BWD);
00239 const int RESIZE_RIGHT = RESIZE_DIR(RESIZE_HORZ, RESIZE_FWD);
00240 const int RESIZE_LEFT = RESIZE_DIR(RESIZE_HORZ, RESIZE_BWD);
00241 #undef RESIZE_DIR
00242
00243 private:
00244 int _width, _height;
00245 int _map_center_x, _map_center_y;
00246 double _m_per_cell;
00247 Cell _unvisited_cell;
00248 std::shared_ptr<GridCellFactory> _cell_factory;
00249 Map _cells;
00250 };
00251
00252 #endif