iMSTK
Interactive Medical Simulation Toolkit
imstkGridBasedNeighborSearch.cpp
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 #include "imstkGridBasedNeighborSearch.h"
8 #include "imstkParallelUtils.h"
9 
10 namespace imstk
11 {
12 void
14 {
15  m_SearchRadius = radius;
16  m_SearchRadiusSqr = radius * radius;
17 }
18 
19 std::vector<std::vector<size_t>>
21 {
22  std::vector<std::vector<size_t>> result;
23  getNeighbors(result, points, points);
24  return result;
25 }
26 
27 void
28 GridBasedNeighborSearch::getNeighbors(std::vector<std::vector<size_t>>& result, const VecDataArray<double, 3>& points)
29 {
30  getNeighbors(result, points, points);
31 }
32 
33 void
34 GridBasedNeighborSearch::getNeighbors(std::vector<std::vector<size_t>>& result, const VecDataArray<double, 3>& setA, const VecDataArray<double, 3>& setB)
35 {
36  LOG_IF(FATAL, (std::abs(m_SearchRadius) < 1e-8)) << "Neighbor search radius is zero";
37 
38  // firstly compute the bounding box of points in setB
39  Vec3d lowerCorner;
40  Vec3d upperCorner;
41  ParallelUtils::findAABB(setB, lowerCorner, upperCorner);
42 
43  // the upper corner need to be expanded a bit, to avoid round-off error during computation
44  upperCorner += Vec3d(m_SearchRadius, m_SearchRadius, m_SearchRadius) * 0.1;
45 
46  // resize grid to fit the bounding box covering setB
47  m_Grid.initialize(lowerCorner, upperCorner, m_SearchRadius);
48 
49  // clear all particle lists in each grid cell
50  ParallelUtils::parallelFor(m_Grid.getAllCellData().size(),
51  [&](const size_t cellIdx)
52  {
53  m_Grid.getCellData(cellIdx).particleIndices.resize(0);
54  });
55 
56  // collect particle indices of points in setB into their corresponding cells
57  ParallelUtils::parallelFor(setB.size(),
58  [&](const size_t p)
59  {
60  auto& cellData = m_Grid.getCellData(setB[p]);
61  cellData.lock.lock();
62  cellData.particleIndices.push_back(p);
63  cellData.lock.unlock();
64  });
65 
66  // for each point in setA, collect setB neighbors within the search radius
67  result.resize(setA.size());
68  ParallelUtils::parallelFor(setA.size(),
69  [&](const size_t p)
70  {
71  auto& pneighbors = result[p];
72 
73  // important: must clear the old result (if applicable)
74  pneighbors.resize(0);
75 
76  const auto ppos = setA[p];
77  const auto cellIdx = m_Grid.template getCell3DIndices<int>(ppos);
78 
79  for (int k = -1; k <= 1; ++k)
80  {
81  int cellZ = cellIdx[2] + k;
82  if (!m_Grid.template isValidCellIndex<2>(cellZ))
83  {
84  continue;
85  }
86  for (int j = -1; j <= 1; ++j)
87  {
88  int cellY = cellIdx[1] + j;
89  if (!m_Grid.template isValidCellIndex<1>(cellY))
90  {
91  continue;
92  }
93  for (int i = -1; i <= 1; ++i)
94  {
95  int cellX = cellIdx[0] + i;
96  if (!m_Grid.template isValidCellIndex<0>(cellX))
97  {
98  continue;
99  }
100 
101  // get index q of point in setB
102  for (auto q : m_Grid.getCellData(cellX, cellY, cellZ).particleIndices)
103  {
104  const auto qpos = setB[q];
105  const Vec3d diff = ppos - qpos;
106  const auto d2 = diff[0] * diff[0] + diff[1] * diff[1] + diff[2] * diff[2];
107  if (d2 < m_SearchRadiusSqr)
108  {
109  pneighbors.push_back(q);
110  }
111  }
112  }
113  }
114  }
115  });
116 }
117 } // namespace imstk
void setSearchRadius(const double radius)
Set the search radius.
Compound Geometry.
void push_back(const ValueType &val)
Append the data array to hold the new value, resizes if neccesary.
std::vector< std::vector< size_t > > getNeighbors(const VecDataArray< double, 3 > &points)
Search neighbors for each points within the search radius.