opensurgsim
Grid-inl.h
1 // This file is a part of the OpenSurgSim project.
2 // Copyright 2013, SimQuest Solutions Inc.
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 // http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 
16 #ifndef SURGSIM_DATASTRUCTURES_GRID_INL_H
17 #define SURGSIM_DATASTRUCTURES_GRID_INL_H
18 
19 #include <boost/functional/hash.hpp>
20 
21 namespace SurgSim
22 {
23 namespace DataStructures
24 {
25 
26 namespace
27 {
28 
45 template <typename T, size_t B, size_t N>
46 class Number : public Eigen::Matrix<T, N, 1>
47 {
48 public:
49  static_assert(B > 1 && B < 10, "B (the base) needs to be within [2..9]");
50 
52  Number()
53  {
54  this->setZero();
55  }
56 
58  size_t toDecimal() const
59  {
60  size_t value = 0;
61  size_t BexponentDigit = 1;
62  for (size_t digit = 0; digit < N; ++digit)
63  {
64  value += (*this)[digit] * BexponentDigit;
65  BexponentDigit *= B;
66  }
67  return value;
68  }
69 
72  bool next()
73  {
74  size_t digit = 0;
75  do
76  {
77  (*this)[digit]++;
78  if ((*this)[digit] == B)
79  {
80  (*this)[digit] = 0;
81  }
82  else
83  {
84  return true;
85  }
86  digit++;
87  }
88  while (digit < N);
89 
90  return false;
91  }
92 };
93 }; // namespace
94 
95 
96 template <typename T, size_t N>
97 size_t Grid<T, N>::NDIdHash::operator()(const NDId& nd) const
98 {
99  return boost::hash_range(nd.data(), nd.data() + N);
100 }
101 
102 template <typename T, size_t N>
103 Grid<T, N>::Grid(const Eigen::Matrix<double, N, 1>& cellSize, const Eigen::AlignedBox<double, N>& bounds)
104  : m_size(cellSize),
105  m_aabb(bounds),
106  m_neighborsDirtyFlag(false)
107 {
108  static_assert(N >= 1, "A grid must have a positive non null dimension");
109 }
110 
111 template <typename T, size_t N>
113 {
114 }
115 
116 template <typename T, size_t N>
118 {
119  // Clear the mapping element -> cellId
120  m_cellIds.clear();
121 
122  // Clear the active cells
123  m_activeCells.clear();
124 
125  // Nothing in the grid (no elements, no neighbors)...so it is up to date
126  m_neighborsDirtyFlag = false;
127 }
128 
129 template <typename T, size_t N>
130 template <class Derived>
131 void Grid<T, N>::addElement(const T element, const Eigen::MatrixBase<Derived>& position)
132 {
133  // Only add element that are located in the grid
134  if (!m_aabb.contains(position))
135  {
136  return;
137  }
138 
139  // Find the dimension-N cell id from the location
140  // Example in 3D: cell (i, j, k) has 3D min/max coordinates
141  // min[axis] = (size[axis] * (-numCellPerDim[axis] / 2 + i)
142  // max[axis] = (size[axis] * (-numCellPerDim[axis] / 2 + i + 1)
143  NDId cellId = ((position - m_aabb.min()).cwiseQuotient(m_size)).template cast<int>();
144 
145  // Register the element into its corresponding cell if it exists, or creates it.
146  m_activeCells[cellId].elements.push_back(element);
147 
148  // Add this element in the map [element -> cellID]
149  m_cellIds[element] = cellId;
150 
152  m_neighborsDirtyFlag = true;
153 }
154 
155 template <typename T, size_t N>
156 void Grid<T, N>::update()
157 {
158  std::array<NDId, powerOf3<N>::value> cellsIds;
159 
160  // Start by clearing up all the neighbor's list
161  for (typename std::unordered_map<NDId, typename Grid<T, N>::CellContent, NDIdHash>::reference cell : m_activeCells)
162  {
163  cell.second.neighbors.clear();
164  }
165 
166  // Compute each cell's neighbors list
167  for (typename std::unordered_map<NDId, typename Grid<T, N>::CellContent, NDIdHash>::reference cell : m_activeCells)
168  {
169  getNeighborsCellIds(cell.first, &cellsIds);
170 
171  for (size_t index = 0; index < powerOf3<N>::value; ++index)
172  {
173  // Use symmetry between pair of cells to only treat neighbors with a larger or equal id.
174  if (isNdGreaterOrEqual(cellsIds[index], cell.first))
175  {
176  auto neighborCell = m_activeCells.find(cellsIds[index]);
177  if (neighborCell != m_activeCells.end())
178  {
179  cell.second.neighbors.insert(cell.second.neighbors.end(),
180  neighborCell->second.elements.cbegin(),
181  neighborCell->second.elements.cend());
182 
183  // Treat symmetry if the cells are different
184  if (cellsIds[index] != cell.first)
185  {
186  neighborCell->second.neighbors.insert(neighborCell->second.neighbors.end(),
187  cell.second.elements.cbegin(),
188  cell.second.elements.cend());
189  }
190  }
191  }
192  }
193  }
194  m_neighborsDirtyFlag = false;
195 }
196 
197 template <typename T, size_t N>
198 const std::vector<T>& Grid<T, N>::getNeighbors(const T& element)
199 {
200  static std::vector<T> empty;
201 
203  {
204  update();
205  }
206 
207  auto const foundCell = m_cellIds.find(element);
208  if (foundCell != m_cellIds.cend())
209  {
210  return m_activeCells[foundCell->second].neighbors;
211  }
212 
213  return empty;
214 }
215 
216 template <typename T, size_t N>
217 template <class Derived>
218 const std::vector<T>& Grid<T, N>::getNeighbors(const Eigen::MatrixBase<Derived>& position)
219 {
220  static const std::vector<T> empty;
221 
222  // If outside the bounding box, can't find any neighbors
223  if (m_aabb.contains(position))
224  {
226  {
227  update();
228  }
229 
230  NDId cellId = ((position - m_aabb.min()).cwiseQuotient(m_size)).template cast<int>();
231 
232  auto foundCell = m_activeCells.find(cellId);
233  if (foundCell == m_activeCells.end())
234  {
235  // If the cell doesn't exist, collect all the neighbors
236  std::array<NDId, powerOf3<N>::value> cellsIds;
237  getNeighborsCellIds(cellId, &cellsIds);
238  std::vector<T> neighbors;
239  for (const auto& neighborId : cellsIds)
240  {
241  auto neighborCell = m_activeCells.find(neighborId);
242  if (neighborCell != m_activeCells.end())
243  {
244  neighbors.insert(neighbors.end(),
245  neighborCell->second.elements.cbegin(),
246  neighborCell->second.elements.cend());
247  }
248  }
249  m_activeCells[cellId].neighbors = std::move(neighbors);
250  }
251  return m_activeCells[cellId].neighbors;
252  }
253  return empty;
254 }
255 
256 template <typename T, size_t N>
258  std::array<NDId, powerOf3<N>::value>* cellsIds)
259 {
260  // Now build up all the 3^N neighbors cell around this n-d cell
261  // It corresponds to all possible permutation in dimension-N of the indices
262  // {(cellIdnD[0] - 1, cellIdnD[0], cellIdnD[0] + 1) x ... x
263  // (cellIdnD[N - 1] - 1, cellIdnD[N - 1], cellIdnD[N - 1] + 1)}
264  // It is (cellIdnD[0] - 1, ... , cellIdnD[N - 1] - 1) + all possible number in base 3 with N digit
265  // For example in 2D, the NumberInBase3<2> are in order: 00 01 02 10 11 12 20 21 22
266  // For example in 3D, the NumberInBase3<3> are in order:
267  // 000 001 002 010 011 012 020 021 022
268  // 100 101 102 110 111 112 120 121 122
269  // 200 201 202 210 211 212 220 221 222
270  cellId -= NDId::Ones();
271 
272  Number<int, 3, N> currentNumberNDigitBase3;
273  for (size_t i = 0; i < powerOf3<N>::value; ++i)
274  {
275  (*cellsIds)[i] = cellId + currentNumberNDigitBase3;
276  currentNumberNDigitBase3.next();
277  }
278 }
279 
280 template <typename T, size_t N>
281 bool Grid<T, N>::isNdGreaterOrEqual(const NDId& a, const NDId& b)
282 {
283  for (size_t i = 0; i < N; ++i)
284  {
285  if (a[i] > b[i])
286  {
287  return true;
288  }
289 
290  if (a[i] < b[i])
291  {
292  return false;
293  }
294  }
295  return true;
296 }
297 
298 }; // namespace DataStructures
299 }; // namespace SurgSim
300 
301 #endif // SURGSIM_DATASTRUCTURES_GRID_INL_H
Wraps glewInit() to separate the glew opengl definitions from the osg opengl definitions only imgui n...
Definition: AddRandomSphereBehavior.cpp:36
const std::vector< T > & getNeighbors(const T &element)
Retrieve an elements&#39; neighbors.
Definition: Grid-inl.h:198
Templated function to compute a power of 3 at compile time (useful for template parameter) ...
Definition: Grid.h:32
Eigen::AlignedBox< double, N > m_aabb
Grid min and max.
Definition: Grid.h:107
Eigen::Matrix< double, N, 1 > m_size
Size of each cell (same on all dimension)
Definition: Grid.h:104
virtual ~Grid()
Destructor.
Definition: Grid-inl.h:112
bool m_neighborsDirtyFlag
Does the neighbors needs to be recomputed ?
Definition: Grid.h:110
Data structure for a cell&#39;s content (the list of elements and the list of all the neighbors) ...
Definition: Grid.h:81
Enable the NDId to be used as a key in an unordered map.
Definition: Grid.h:91
std::unordered_map< T, NDId > m_cellIds
Mapping from element to cell id containing the element.
Definition: Grid.h:101
Grid(const Eigen::Matrix< double, N, 1 > &cellSize, const Eigen::AlignedBox< double, N > &bounds)
Constructor.
Definition: Grid-inl.h:103
void reset()
Reset the grid content and the neighbors&#39; mapping.
Definition: Grid-inl.h:117
n-dimensional grid structure with uniform non-cubic cells This data structure is useful to search for...
Definition: Grid.h:47
Eigen::Matrix< int, N, 1 > NDId
The type of the n-dimensional cell Id.
Definition: Grid.h:88
void addElement(const T element, const Eigen::MatrixBase< Derived > &position)
Add an element in the grid.
Definition: Grid-inl.h:131
std::unordered_map< NDId, CellContent, NDIdHash > m_activeCells
Active cells (referenced by their ids (spatial hashing)) with their content.
Definition: Grid.h:98