1 /********************************************************************* 2 * Software License Agreement (BSD License) 3 * 4 * Copyright (c) 2010, Rice University 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * * Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * * Redistributions in binary form must reproduce the above 14 * copyright notice, this list of conditions and the following 15 * disclaimer in the documentation and/or other materials provided 16 * with the distribution. 17 * * Neither the name of the Rice University nor the names of its 18 * contributors may be used to endorse or promote products derived 19 * from this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 25 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 29 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 31 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 32 * POSSIBILITY OF SUCH DAMAGE. 33 *********************************************************************/ 34 35 /* Author: Ioan Sucan */ 36 37 #ifndef OMPL_DATASTRUCTURES_GRID_ 38 #define OMPL_DATASTRUCTURES_GRID_ 39 40 #include <Eigen/Core> 41 #include <vector> 42 #include <iostream> 43 #include <cstdlib> 44 #include <unordered_map> 45 #include <algorithm> 46 47 namespace ompl 48 { 49 /** \brief Representation of a simple grid */ 50 template <typename _T> 51 class Grid 52 { 53 public: 54 /// Definition of a coordinate within this grid 55 using Coord = Eigen::VectorXi; 56 57 /// Definition of a cell in this grid 58 struct Cell 59 { 60 /// The data we store in the cell 61 _T data; 62 63 /// The coordinate of the cell 64 Coord coord; 65 66 Cell() = default; 67 68 virtual ~Cell() = default; 69 70 EIGEN_MAKE_ALIGNED_OPERATOR_NEW 71 }; 72 73 /// The datatype for arrays of cells 74 using CellArray = std::vector<Cell *>; 75 76 /// The constructor takes the dimension of the grid as argument Grid(unsigned int dimension)77 explicit Grid(unsigned int dimension) 78 { 79 setDimension(dimension); 80 } 81 82 /// Destructor ~Grid()83 virtual ~Grid() 84 { 85 freeMemory(); 86 } 87 88 /// Clear all cells in the grid clear()89 virtual void clear() 90 { 91 freeMemory(); 92 } 93 94 /// Return the dimension of the grid getDimension()95 unsigned int getDimension() const 96 { 97 return dimension_; 98 } 99 100 /// Update the dimension of the grid; this should not be done 101 /// unless the grid is empty setDimension(unsigned int dimension)102 void setDimension(unsigned int dimension) 103 { 104 if (!empty()) 105 throw; 106 dimension_ = dimension; 107 maxNeighbors_ = 2 * dimension_; 108 } 109 110 /// Check if a cell exists at the specified coordinate has(const Coord & coord)111 bool has(const Coord &coord) const 112 { 113 return getCell(coord) != nullptr; 114 } 115 116 /// Get the cell at a specified coordinate getCell(const Coord & coord)117 Cell *getCell(const Coord &coord) const 118 { 119 auto pos = hash_.find(const_cast<Coord *>(&coord)); 120 Cell *c = (pos != hash_.end()) ? pos->second : nullptr; 121 return c; 122 } 123 124 /// Get the list of neighbors for a given cell neighbors(const Cell * cell,CellArray & list)125 void neighbors(const Cell *cell, CellArray &list) const 126 { 127 Coord test = cell->coord; 128 neighbors(test, list); 129 } 130 131 /// Get the list of neighbors for a given coordinate neighbors(const Coord & coord,CellArray & list)132 void neighbors(const Coord &coord, CellArray &list) const 133 { 134 Coord test = coord; 135 neighbors(test, list); 136 } 137 138 /// Get the list of neighbors for a given coordinate neighbors(Coord & coord,CellArray & list)139 void neighbors(Coord &coord, CellArray &list) const 140 { 141 list.reserve(list.size() + maxNeighbors_); 142 143 for (int i = dimension_ - 1; i >= 0; --i) 144 { 145 coord[i]--; 146 147 auto pos = hash_.find(&coord); 148 Cell *cell = (pos != hash_.end()) ? pos->second : nullptr; 149 150 if (cell) 151 list.push_back(cell); 152 coord[i] += 2; 153 154 pos = hash_.find(&coord); 155 cell = (pos != hash_.end()) ? pos->second : nullptr; 156 157 if (cell) 158 list.push_back(cell); 159 coord[i]--; 160 } 161 } 162 163 /// Get the connected components formed by the cells in this grid (based on neighboring relation) components()164 std::vector<std::vector<Cell *>> components() const 165 { 166 using ComponentHash = std::unordered_map<Coord *, int, HashFunCoordPtr, EqualCoordPtr>; 167 168 int components = 0; 169 ComponentHash ch; 170 std::vector<std::vector<Cell *>> res; 171 172 for (auto & i: hash_) 173 { 174 Cell *c0 = i.second; 175 auto pos = ch.find(&c0->coord); 176 int comp = (pos != ch.end()) ? pos->second : -1; 177 178 if (comp < 0) 179 { 180 res.resize(res.size() + 1); 181 std::vector<Cell *> &q = res.back(); 182 q.push_back(c0); 183 std::size_t index = 0; 184 while (index < q.size()) 185 { 186 Cell *c = q[index++]; 187 pos = ch.find(&c->coord); 188 comp = (pos != ch.end()) ? pos->second : -1; 189 190 if (comp < 0) 191 { 192 ch.insert(std::make_pair(&c->coord, components)); 193 std::vector<Cell *> nbh; 194 neighbors(c, nbh); 195 for (const auto &n : nbh) 196 { 197 pos = ch.find(&n->coord); 198 comp = (pos != ch.end()) ? pos->second : -1; 199 if (comp < 0) 200 q.push_back(n); 201 } 202 } 203 else 204 { 205 --index; 206 q.erase(q.begin() + index); 207 } 208 } 209 ++components; 210 } 211 } 212 std::sort(res.begin(), res.end(), SortComponents()); 213 return res; 214 } 215 216 /// Instantiate a new cell at given coordinates; optionally 217 /// Return the list of future neighbors. 218 /// Note: this call only creates the cell, but does not add it to the grid. 219 /// It however updates the neighbor count for neighboring cells 220 virtual Cell *createCell(const Coord &coord, CellArray *nbh = nullptr) 221 { 222 auto *cell = new Cell(); 223 cell->coord = coord; 224 if (nbh) 225 neighbors(cell->coord, *nbh); 226 return cell; 227 } 228 229 /// Remove a cell from the grid. If the cell has not been 230 /// Added to the grid, only update the neighbor list remove(Cell * cell)231 virtual bool remove(Cell *cell) 232 { 233 if (cell) 234 { 235 auto pos = hash_.find(&cell->coord); 236 if (pos != hash_.end()) 237 { 238 hash_.erase(pos); 239 return true; 240 } 241 } 242 return false; 243 } 244 245 /// Add an instantiated cell to the grid add(Cell * cell)246 virtual void add(Cell *cell) 247 { 248 hash_.insert(std::make_pair(&cell->coord, cell)); 249 } 250 251 /// Clear the memory occupied by a cell; do not call this function unless remove() was called first destroyCell(Cell * cell)252 virtual void destroyCell(Cell *cell) const 253 { 254 delete cell; 255 } 256 257 /// Get the data stored in the cells we are aware of getContent(std::vector<_T> & content)258 void getContent(std::vector<_T> &content) const 259 { 260 for (const auto &h : hash_) 261 content.push_back(h.second->data); 262 } 263 264 /// Get the set of coordinates where there are cells getCoordinates(std::vector<Coord * > & coords)265 void getCoordinates(std::vector<Coord *> &coords) const 266 { 267 for (const auto &h : hash_) 268 coords.push_back(h.first); 269 } 270 271 /// Get the set of instantiated cells in the grid getCells(CellArray & cells)272 void getCells(CellArray &cells) const 273 { 274 for (const auto &h : hash_) 275 cells.push_back(h.second); 276 } 277 278 /// Print the value of a coordinate to a stream 279 void printCoord(Coord &coord, std::ostream &out = std::cout) const 280 { 281 out << "[ "; 282 for (unsigned int i = 0; i < dimension_; ++i) 283 out << coord[i] << " "; 284 out << "]" << std::endl; 285 } 286 287 /// Check if the grid is empty empty()288 bool empty() const 289 { 290 return hash_.empty(); 291 } 292 293 /// Check the size of the grid size()294 unsigned int size() const 295 { 296 return hash_.size(); 297 } 298 299 /// Print information about the data in this grid structure 300 virtual void status(std::ostream &out = std::cout) const 301 { 302 out << size() << " total cells " << std::endl; 303 const std::vector<std::vector<Cell *>> &comp = components(); 304 out << comp.size() << " connected components: "; 305 for (const auto &c : comp) 306 out << c.size() << " "; 307 out << std::endl; 308 } 309 310 protected: 311 /// Free the allocated memory freeMemory()312 void freeMemory() 313 { 314 CellArray content; 315 getCells(content); 316 hash_.clear(); 317 318 for (auto &c : content) 319 delete c; 320 } 321 322 /// Hash function for coordinates; see 323 /// http://www.cs.hmc.edu/~geoff/classes/hmc.cs070.200101/homework10/hashfuncs.html 324 struct HashFunCoordPtr 325 { 326 /// Hash function for coordinates operatorHashFunCoordPtr327 std::size_t operator()(const Coord *const s) const 328 { 329 unsigned long h = 0; 330 for (int i = s->size() - 1; i >= 0; --i) 331 { 332 int high = h & 0xf8000000; 333 h = h << 5; 334 h = h ^ (high >> 27); 335 h = h ^ (*s)[i]; 336 } 337 return (std::size_t)h; 338 } 339 }; 340 341 /// Equality operator for coordinate pointers 342 struct EqualCoordPtr 343 { 344 /// Equality operator for coordinate pointers operatorEqualCoordPtr345 bool operator()(const Coord *const c1, const Coord *const c2) const 346 { 347 return *c1 == *c2; 348 } 349 }; 350 351 /// Define the datatype for the used hash structure 352 using CoordHash = std::unordered_map<Coord *, Cell *, HashFunCoordPtr, EqualCoordPtr>; 353 354 /// Helper to sort components by size 355 struct SortComponents 356 { 357 /// Helper to sort components by size operatorSortComponents358 bool operator()(const std::vector<Cell *> &a, const std::vector<Cell *> &b) const 359 { 360 return a.size() > b.size(); 361 } 362 }; 363 364 public: 365 /// We only allow const iterators 366 using iterator = typename CoordHash::const_iterator; 367 368 /// Return the begin() iterator for the grid begin()369 iterator begin() const 370 { 371 return hash_.begin(); 372 } 373 374 /// Return the end() iterator for the grid end()375 iterator end() const 376 { 377 return hash_.end(); 378 } 379 380 protected: 381 /// The dimension of the grid 382 unsigned int dimension_; 383 384 /// The maximum number of neighbors a cell can have (2 * dimension) 385 unsigned int maxNeighbors_; 386 387 /// The hash holding the cells 388 CoordHash hash_; 389 }; 390 } // namespace ompl 391 392 #endif 393