iMSTK
Interactive Medical Simulation Toolkit
imstkUniformSpatialGrid.h
1 /*
2 ** This file is part of the Interactive Medical Simulation Toolkit (iMSTK)
3 ** iMSTK is distributed under the Apache License, Version 2.0.
4 ** See accompanying NOTICE for details.
5 */
6 
7 #pragma once
8 
9 #include "imstkMath.h"
10 #include "imstkLogger.h"
11 
12 #include <array>
13 
14 namespace imstk
15 {
21 template<class CellData>
23 {
24 public:
28  UniformSpatialGrid() : UniformSpatialGrid(Vec3d::Zero(), Vec3d(1.0, 1.0, 1.0), double(1.0))
29  {}
30 
37  UniformSpatialGrid(const Vec3d& lowerCorner, const Vec3d& upperCorner, double cellSize)
38  {
39  initialize(lowerCorner, upperCorner, cellSize);
40  }
41 
48  void initialize(const Vec3d& lowerCorner, const Vec3d& upperCorner, const double cellSize)
49  {
50  CHECK(cellSize > 0) << "Invalid cell size";
51 
52  m_LowerCorner = lowerCorner;
53  m_UpperCorner = upperCorner;
54 
55  m_CellSize = cellSize;
56  m_InvCellSize = 1.0 / m_CellSize;
57 
58  m_NTotalCells = 1u;
59  for (int i = 0; i < 3; ++i)
60  {
61  m_Resolution[i] = static_cast<unsigned int>(std::ceil((m_UpperCorner[i] - m_LowerCorner[i]) / m_CellSize));
62  m_NTotalCells *= m_Resolution[i];
63  }
64 
65  CHECK(m_NTotalCells != 0) << "Invalid grid size: [" +
66  std::to_string(m_LowerCorner[0]) + ", " + std::to_string(m_LowerCorner[1]) + ", " + std::to_string(m_LowerCorner[2]) + "] => " +
67  std::to_string(m_UpperCorner[0]) + ", " + std::to_string(m_UpperCorner[1]) + ", " + std::to_string(m_UpperCorner[2]) + "], " +
68  "cellSize = " + std::to_string(m_CellSize);
69 
70  // cell data must be resized to match with the number of cells
71  m_CellData.resize(m_NTotalCells);
72  }
73 
77  std::array<unsigned int, 3> getResolution() const { return m_Resolution; }
78 
82  unsigned int getNumTotalCells() const { return m_NTotalCells; }
83 
87  template<int d>
88  bool isValidCellIndex(const int idx) const
89  { return idx >= 0 && static_cast<unsigned int>(idx) < m_Resolution[d]; }
90 
94  bool isValidCellIndices(const int i, const int j, const int k) const
95  { return isValidCellIndex<0>(i) && isValidCellIndex<1>(j) && isValidCellIndex<2>(k); }
96 
100  template<class IndexType>
101  std::array<IndexType, 3> getCell3DIndices(const Vec3d& ppos) const
102  {
103  std::array<IndexType, 3> cellIdx;
104  for (int d = 0; d < 3; ++d)
105  {
106  cellIdx[d] = static_cast<IndexType>((ppos[d] - m_LowerCorner[d]) * m_InvCellSize);
107  }
108  return cellIdx;
109  }
110 
114  std::vector<CellData>& getAllCellData() { return m_CellData; }
115 
119  const std::vector<CellData>& getAllCellData() const { return m_CellData; }
120 
125  CellData& getCellData(const Vec3d& ppos)
126  {
127  return m_CellData[getCellLinearizedIndex<unsigned int>(ppos)];
128  }
129 
134  const CellData& getCellData(const Vec3d& ppos) const
135  { return m_CellData[getCellLinearizedIndex<unsigned int>(ppos)]; }
136 
141  CellData& getCellData(size_t linearizedIdx)
142  {
143  assert(linearizedIdx < m_CellData.size());
144  return m_CellData[linearizedIdx];
145  }
146 
151  const CellData& getCellData(size_t linearizedIdx) const
152  {
153  assert(linearizedIdx < m_CellData.size());
154  return m_CellData[linearizedIdx];
155  }
156 
161  template<class IndexType>
162  CellData& getCellData(const std::array<IndexType, 3>& cellIdx)
163  {
164  return m_CellData[getCellLinearizedIndex(cellIdx[0], cellIdx[1], cellIdx[2])];
165  }
166 
171  template<class IndexType>
172  const CellData& getCellData(const std::array<IndexType, 3>& cellIdx) const
173  {
174  return m_CellData[getCellLinearizedIndex(cellIdx[0], cellIdx[1], cellIdx[2])];
175  }
176 
181  template<class IndexType>
182  CellData& getCellData(const IndexType i, const IndexType j, const IndexType k)
183  {
184  return m_CellData[getCellLinearizedIndex(i, j, k)];
185  }
186 
191  template<class IndexType>
192  const CellData& getCellData(const IndexType i, const IndexType j, const IndexType k) const
193  {
194  return m_CellData[getCellLinearizedIndex(i, j, k)];
195  }
196 
200  template<class Function>
201  void loopAllCellData(Function&& func)
202  {
203  for (auto& cellData: m_CellData)
204  {
205  func(cellData);
206  }
207  }
208 
213  template<class IndexType>
214  IndexType getCellLinearizedIndex(const IndexType i, const IndexType j, const IndexType k) const
215  {
216  auto flatIndex = (k * static_cast<IndexType>(m_Resolution[1]) + j) * static_cast<IndexType>(m_Resolution[0]) + i;
217  assert(flatIndex < static_cast<IndexType>(m_NTotalCells));
218  return flatIndex;
219  }
220 
225  template<class IndexType>
226  IndexType getCellLinearizedIndex(const Vec3d& ppos) const
227  {
228  auto cellIdx = getCell3DIndices<IndexType>(ppos);
229 #if defined(DEBUG) || defined(_DEBUG) || !defined(NDEBUG)
230  LOG_IF(FATAL, (!isValidCellIndices(cellIdx[0], cellIdx[1], cellIdx[2]))) <<
231  "Invalid cell indices: " +
232  std::to_string(cellIdx[0]) + "/" + std::to_string(m_Resolution[0]) + ", " +
233  std::to_string(cellIdx[1]) + "/" + std::to_string(m_Resolution[1]) + ", " +
234  std::to_string(cellIdx[2]) + "/" + std::to_string(m_Resolution[2]);
235 #endif
236  return getCellLinearizedIndex<IndexType>(cellIdx[0], cellIdx[1], cellIdx[2]);
237  }
238 
239 private:
240  Vec3d m_LowerCorner;
241  Vec3d m_UpperCorner;
242  double m_CellSize;
243  double m_InvCellSize;
244 
245  unsigned int m_NTotalCells;
246  std::array<unsigned int, 3> m_Resolution;
247 
248  std::vector<CellData> m_CellData;
249 };
250 } // namespace imstk
IndexType getCellLinearizedIndex(const IndexType i, const IndexType j, const IndexType k) const
Get linearized index from cell 3D indices: index in 3D (cell_x, cell_y, cell_z) => index in 1D...
void loopAllCellData(Function &&func)
Apply a function to all cell data.
std::vector< CellData > & getAllCellData()
Get all cell data.
IndexType getCellLinearizedIndex(const Vec3d &ppos) const
Get linearized index of cell containing the given position.
const std::vector< CellData > & getAllCellData() const
Get all cell data.
CellData & getCellData(const std::array< IndexType, 3 > &cellIdx)
Get data in a cell.
Compound Geometry.
CellData & getCellData(const Vec3d &ppos)
Get data in a cell.
UniformSpatialGrid(const Vec3d &lowerCorner, const Vec3d &upperCorner, double cellSize)
Construct a grid with given corners and cell size.
UniformSpatialGrid()
Construct a default grid ([0, 1]^3) with cell size of 1.
bool isValidCellIndices(const int i, const int j, const int k) const
Check if 3D cell indices are valid.
unsigned int getNumTotalCells() const
Get number of total cells in the grid.
const CellData & getCellData(const Vec3d &ppos) const
Get data in a cell.
bool isValidCellIndex(const int idx) const
Check if cell index in dimension d is valid (d = 0/1/2 => x/y/z dimension)
void initialize(const Vec3d &lowerCorner, const Vec3d &upperCorner, const double cellSize)
Initialize the grid data.
CellData & getCellData(size_t linearizedIdx)
Get data in a cell.
const CellData & getCellData(size_t linearizedIdx) const
Get data in a cell.
std::array< unsigned int, 3 > getResolution() const
Get number of grid cell in 3 dimensions: (num_cell_x, num_cell_y, num_cell_z)
std::array< IndexType, 3 > getCell3DIndices(const Vec3d &ppos) const
Get the 3D index (cell_x, cell_y, cell_z) of the cell containing the given positions.
Class for handling data in 3D grid.
const CellData & getCellData(const IndexType i, const IndexType j, const IndexType k) const
Get data in a cell.
const CellData & getCellData(const std::array< IndexType, 3 > &cellIdx) const
Get data in a cell.
CellData & getCellData(const IndexType i, const IndexType j, const IndexType k)
Get data in a cell.