grid_map.h
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; // width & height in meters
00017 };
00018 
00022 class GridMap {
00023 public: // typedefs
00024   using Cell = std::shared_ptr<GridCell>;
00025 private: // typedefs
00026   using Row = std::vector<Cell>;
00027   using Map = std::vector<Row>;
00028 
00029 public:
00030   // TODO: cp, mv ctors, dtor
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     // TODO: bounds check
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: // methods
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     //find if it needs to resize map
00155     int new_bound = calc_sufficient_bound(container_coord, bound);
00156     if (new_bound == bound)
00157       return;
00158     //expands map with the exponential rule
00159     // states are +100%, +300%, +700% etc ( -100% + [2^n*100%] )
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   /* Finds the nearest upper bound value of degree of 2 to the input integer
00173    * NOTE: 2-3  are bounded by 4,
00174    *       4-7  are bounded by 8,
00175    *       8-15 are bounded by 16 etc.
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: //flag constants
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: // fields
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


tiny_slam
Author(s):
autogenerated on Thu Jun 6 2019 17:44:57