ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
FastMarching.cpp
Go to the documentation of this file.
1 // ----------------------------------------------------------------------------
2 // - CloudViewer: www.cloudViewer.org -
3 // ----------------------------------------------------------------------------
4 // Copyright (c) 2018-2024 www.cloudViewer.org
5 // SPDX-License-Identifier: MIT
6 // ----------------------------------------------------------------------------
7 
8 #include "FastMarching.h"
9 
10 // local
11 #include "DgmOctree.h"
12 
13 using namespace cloudViewer;
14 
16  : m_initialized(false),
17  m_dx(0),
18  m_dy(0),
19  m_dz(0),
20  m_rowSize(0),
21  m_sliceSize(0),
22  m_indexShift(0),
23  m_gridSize(0),
24  m_theGrid(nullptr),
25  m_octree(nullptr),
26  m_gridLevel(0),
27  m_cellSize(1.0f),
28  m_minFillIndexes(0, 0, 0),
29  m_numberOfNeighbours(6) {
30  memset(m_neighboursIndexShift, 0,
31  sizeof(int) * CC_FM_MAX_NUMBER_OF_NEIGHBOURS);
32  memset(m_neighboursDistance, 0,
33  sizeof(float) * CC_FM_MAX_NUMBER_OF_NEIGHBOURS);
34 }
35 
37  if (m_theGrid) {
38  for (unsigned i = 0; i < m_gridSize; ++i) {
39  if (m_theGrid[i]) {
40  delete m_theGrid[i];
41  }
42  }
43 
44  delete[] m_theGrid;
45  m_theGrid = nullptr;
46  }
47 }
48 
49 float FastMarching::getTime(Tuple3i& pos, bool absoluteCoordinates) const {
50  unsigned index = 0;
51 
52  if (absoluteCoordinates) {
53  index = pos2index(pos);
54  } else {
55  index = static_cast<unsigned>(pos.x + 1) +
56  static_cast<unsigned>(pos.y + 1) * m_rowSize +
57  static_cast<unsigned>(pos.z + 1) * m_sliceSize;
58  }
59 
60  assert(m_theGrid[index]);
61 
62  return m_theGrid[index]->T;
63 }
64 
65 int FastMarching::initGrid(float step, unsigned dim[3]) {
66  m_octree = nullptr;
67  m_gridLevel = 0;
68  m_cellSize = step;
69  m_minFillIndexes = Tuple3i(0, 0, 0);
70 
71  m_dx = dim[0];
72  m_dy = dim[1];
73  m_dz = dim[2];
74 
75  return initOther();
76 }
77 
79  unsigned char gridLevel) {
80  if (!octree || gridLevel > DgmOctree::MAX_OCTREE_LEVEL) return -2;
81 
82  const int* minFillIndexes = octree->getMinFillIndexes(gridLevel);
83  const int* maxFillIndexes = octree->getMaxFillIndexes(gridLevel);
84 
85  m_octree = octree;
86  m_gridLevel = gridLevel;
87  m_cellSize = static_cast<float>(octree->getCellSize(gridLevel));
88  m_minFillIndexes.x = minFillIndexes[0];
89  m_minFillIndexes.y = minFillIndexes[1];
90  m_minFillIndexes.z = minFillIndexes[2];
91 
92  m_dx = static_cast<unsigned>(maxFillIndexes[0] - minFillIndexes[0] + 1);
93  m_dy = static_cast<unsigned>(maxFillIndexes[1] - minFillIndexes[1] + 1);
94  m_dz = static_cast<unsigned>(maxFillIndexes[2] - minFillIndexes[2] + 1);
95 
96  return initOther();
97 }
98 
100  m_rowSize = m_dx + 2;
101  m_sliceSize = m_rowSize * (m_dy + 2);
102  m_gridSize = m_sliceSize * (m_dz + 2);
104 
105  for (unsigned i = 0; i < CC_FM_MAX_NUMBER_OF_NEIGHBOURS; ++i) {
108  static_cast<int>(m_rowSize) +
110  static_cast<int>(m_sliceSize);
111 
113  sqrt(static_cast<float>(
119  c_FastMarchingNeighbourPosShift[i * 3 + 2])) *
120  m_cellSize;
121  }
122 
123  m_activeCells.resize(0);
124  m_trialCells.resize(0);
125  m_ignoredCells.resize(0);
126 
127  if (!instantiateGrid(m_gridSize)) return -3;
128 
129  return 0;
130 }
131 
132 void FastMarching::resetCells(std::vector<unsigned>& list) {
133  for (std::vector<unsigned>::const_iterator it = list.begin();
134  it != list.end(); ++it) {
135  if (m_theGrid[*it]) {
137  m_theGrid[*it]->T = Cell::T_INF();
138  }
139  }
140  list.clear();
141 }
142 
144  // reset all cells state
148 }
149 
151  unsigned index = pos2index(pos);
152 
153  assert(index < m_gridSize);
154 
155  Cell* aCell = m_theGrid[index];
156  assert(aCell);
157 
158  if (aCell && aCell->state != Cell::ACTIVE_CELL) {
159  // we add the cell to the "ACTIVE" set
160  aCell->T = 0;
161  addActiveCell(index);
162  return true;
163  } else {
164  return false;
165  }
166 }
167 
169  for (std::size_t j = 0; j < m_activeCells.size(); ++j) {
170  const unsigned& index = m_activeCells[j];
171  Cell* aCell = m_theGrid[index];
172 
173  assert(aCell != nullptr);
174 
175  for (unsigned i = 0; i < m_numberOfNeighbours; ++i) {
176  unsigned nIndex = index + m_neighboursIndexShift[i];
177  Cell* nCell = m_theGrid[nIndex];
178  // if the neighbor exists
179  if (nCell) {
180  // and if it's not already in the TRIAL set
181  if (nCell->state == Cell::FAR_CELL) {
182  nCell->T = m_neighboursDistance[i] *
183  computeTCoefApprox(aCell, nCell);
184  addTrialCell(nIndex);
185  }
186  }
187  }
188  }
189 }
190 
191 void FastMarching::addTrialCell(unsigned index) {
192  m_theGrid[index]->state = Cell::TRIAL_CELL;
193  m_trialCells.push_back(index);
194 }
195 
196 void FastMarching::addActiveCell(unsigned index) {
198  m_activeCells.push_back(index);
199 }
200 
201 void FastMarching::addIgnoredCell(unsigned index) {
202  m_theGrid[index]->state = Cell::EMPTY_CELL;
203  m_ignoredCells.push_back(index);
204 }
205 
207  if (m_trialCells.empty()) return 0; // 0 = error
208 
209  // we look for the "TRIAL" cell with the minimum time (T)
210  std::size_t minTCellIndexPos = 0;
211  unsigned minTCellIndex = m_trialCells[minTCellIndexPos];
212  cloudViewer::FastMarching::Cell* minTCell = m_theGrid[minTCellIndex];
213  assert(minTCell != nullptr);
214 
215  for (std::size_t i = 1; i < m_trialCells.size(); ++i) {
216  unsigned cellIndex = m_trialCells[i];
217  cloudViewer::FastMarching::Cell* cell = m_theGrid[cellIndex];
218  assert(cell != nullptr);
219 
220  if (cell->T < minTCell->T) {
221  minTCellIndexPos = i;
222  minTCellIndex = cellIndex;
223  minTCell = cell;
224  }
225  }
226 
227  // we remove this cell from the TRIAL set
228  m_trialCells[minTCellIndexPos] = m_trialCells.back();
229  m_trialCells.pop_back();
230 
231  return minTCellIndex;
232 }
233 
234 float FastMarching::computeT(unsigned index) {
235  Cell* theCell = m_theGrid[index];
236  if (!theCell) return Cell::T_INF();
237 
238  // arrival time FROM the neighbors
239  double T[CC_FM_MAX_NUMBER_OF_NEIGHBOURS] = {0};
240  {
241  for (unsigned n = 0; n < m_numberOfNeighbours; ++n) {
242  int nIndex = static_cast<int>(index) + m_neighboursIndexShift[n];
243  Cell* nCell = m_theGrid[nIndex];
244  if (nCell && (nCell->state == Cell::TRIAL_CELL ||
245  nCell->state == Cell::ACTIVE_CELL)) {
246  // compute front arrival time
247  T[n] = static_cast<double>(nCell->T) +
248  static_cast<double>(m_neighboursDistance[n]) *
249  static_cast<double>(
250  computeTCoefApprox(nCell, theCell));
251  } else {
252  // no front yet
253  T[n] = static_cast<double>(Cell::T_INF());
254  }
255  }
256  }
257 
258  double A = 0, B = 0, C = 0;
259  double Tij = static_cast<double>(theCell->T /*Cell::T_INF()*/);
260 
261  // Quadratic eq. along X
262  {
263  // look for the minimum arrival time from +/-X
264  double Tmin = static_cast<double>(Cell::T_INF());
265  for (unsigned n = 0; n < m_numberOfNeighbours; ++n)
267  if (T[n] < Tmin) Tmin = T[n];
268  if (Tij > Tmin) {
269  A += 1.0;
270  B += -2.0 * Tmin;
271  C += Tmin * Tmin;
272  }
273  }
274 
275  // Quadratic eq. along Y
276  {
277  // look for the minimum arrival time from +/-Y
278  double Tmin = static_cast<double>(Cell::T_INF());
279  for (unsigned n = 0; n < m_numberOfNeighbours; ++n)
281  if (T[n] < Tmin) Tmin = T[n];
282  if (Tij > Tmin) {
283  A += 1.0;
284  B += -2.0 * Tmin;
285  C += Tmin * Tmin;
286  }
287  }
288 
289  // Quadratic eq. along Z
290  {
291  // look for the minimum arrival time from +/-Z
292  double Tmin = static_cast<double>(Cell::T_INF());
293  for (unsigned n = 0; n < m_numberOfNeighbours; ++n)
295  if (T[n] < Tmin) Tmin = T[n];
296  if (Tij > Tmin) {
297  A += 1.0;
298  B += -2.0 * Tmin;
299  C += Tmin * Tmin;
300  }
301  }
302 
303  // DGM: why?
304  // C -= static_cast<double>(m_cellSize*m_cellSize);
305 
306  // solve the quadratic equation
307  double delta = B * B - 4.0 * A * C;
308 
309  // cases when the quadratic equation is singular
310  if (A == 0 || delta < 0) {
311  // take the 'earliest' neighbour
312  Tij = T[0];
313  for (unsigned n = 1; n < m_numberOfNeighbours; n++)
314  if (T[n] < Tij) Tij = T[n];
315  } else {
316  // Note that the new crossing must be GREATER than the average
317  // of the active neighbors, since only EARLIER elements are active.
318  // Therefore the plus sign is appropriate.
319  Tij = (-B + sqrt(delta)) / (2.0 * A);
320  }
321 
322  return static_cast<float>(Tij);
323 }
Tuple3Tpl< int > Tuple3i
Tuple of 3 int values.
Definition: CVGeom.h:217
#define CC_FM_MAX_NUMBER_OF_NEIGHBOURS
Definition: FastMarching.h:26
Type y
Definition: CVGeom.h:137
Type x
Definition: CVGeom.h:137
Type z
Definition: CVGeom.h:137
The octree structure used throughout the library.
Definition: DgmOctree.h:39
const int * getMaxFillIndexes(unsigned char level) const
Definition: DgmOctree.h:485
static const int MAX_OCTREE_LEVEL
Max octree subdivision level.
Definition: DgmOctree.h:67
const int * getMinFillIndexes(unsigned char level) const
Definition: DgmOctree.h:474
const PointCoordinateType & getCellSize(unsigned char level) const
Returns the octree cells length for a given level of subdivision.
Definition: DgmOctree.h:494
A generic Fast Marching grid cell.
Definition: FastMarching.h:95
static float T_INF()
Returns infinite time value.
Definition: FastMarching.h:98
float T
Front arrival time.
Definition: FastMarching.h:118
virtual void addActiveCell(unsigned index)
Add a cell to the ACTIVE cells list.
float m_cellSize
Octree cell size at equivalent subdivision level.
Definition: FastMarching.h:242
unsigned pos2index(const Tuple3i &pos) const
Definition: FastMarching.h:87
Cell ** m_theGrid
Grid used to process Fast Marching.
Definition: FastMarching.h:235
virtual float computeT(unsigned index)
Computes the front arrival time at a given cell.
unsigned m_dx
Grid size along the X dimension.
Definition: FastMarching.h:221
DgmOctree * m_octree
Associated octree.
Definition: FastMarching.h:238
std::vector< unsigned > m_activeCells
ACTIVE cells list.
Definition: FastMarching.h:212
unsigned char m_gridLevel
Equivalent octree subdivision level.
Definition: FastMarching.h:240
virtual bool instantiateGrid(unsigned size)=0
Instantiates grid in memory.
void resetCells(std::vector< unsigned > &list)
Resets the state of cells in a given list.
unsigned m_indexShift
First index of innerbound grid.
Definition: FastMarching.h:231
virtual float getTime(Tuple3i &pos, bool absoluteCoordinates=false) const
Returns the front arrival time at a given cell.
Tuple3i m_minFillIndexes
Octree min fill indexes at 'm_gridLevel'.
Definition: FastMarching.h:244
virtual void addTrialCell(unsigned index)
Add a cell to the TRIAL cells list.
float m_neighboursDistance[26]
Neighbours distance weight.
Definition: FastMarching.h:251
unsigned m_gridSize
Grid size.
Definition: FastMarching.h:233
virtual ~FastMarching()
Destructor.
std::vector< unsigned > m_trialCells
TRIAL cells list.
Definition: FastMarching.h:214
virtual float computeTCoefApprox(Cell *currentCell, Cell *neighbourCell) const =0
Computes the front acceleration between two cells.
unsigned m_dz
Grid size along the Z dimension.
Definition: FastMarching.h:225
unsigned m_rowSize
Shift for cell access acceleration (Y dimension)
Definition: FastMarching.h:227
FastMarching()
Default constructor.
std::vector< unsigned > m_ignoredCells
IGNORED cells lits.
Definition: FastMarching.h:216
virtual int initGridWithOctree(DgmOctree *octree, unsigned char gridLevel)
virtual void initTrialCells()
Initializes the TRIAL cells list.
unsigned m_sliceSize
Shift for cell access acceleration (Z dimension)
Definition: FastMarching.h:229
virtual int initGrid(float step, unsigned dim[3])
Intializes the grid with a given step and dimensions.
virtual bool setSeedCell(const Tuple3i &pos)
Sets a given cell as "seed".
unsigned m_numberOfNeighbours
Current number of neighbours (6 or 26)
Definition: FastMarching.h:247
virtual void addIgnoredCell(unsigned index)
Add a cell to the IGNORED cells list.
virtual unsigned getNearestTrialCell()
Returns the TRIAL cell with the smallest front arrival time.
int m_neighboursIndexShift[26]
Neighbours coordinates shifts in grid.
Definition: FastMarching.h:249
virtual int step()=0
Propagates the front (one step)
virtual void cleanLastPropagation()
unsigned m_dy
Grid size along the Y dimension.
Definition: FastMarching.h:223
Generic file read and write utility for python interface.
const int c_FastMarchingNeighbourPosShift[]
Grid neighboring cells positions.
Definition: FastMarching.h:29
cloudViewer::DgmOctree * octree