iMSTK
Interactive Medical Simulation Toolkit
imstkPointToTetMap.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 "imstkPointToTetMap.h"
8 #include "imstkLogger.h"
9 #include "imstkParallelUtils.h"
10 #include "imstkTetrahedralMesh.h"
11 #include "imstkVecDataArray.h"
12 
13 namespace imstk
14 {
15 PointToTetMap::PointToTetMap() : m_boundingBoxAvailable(false)
16 {
17  setRequiredInputType<TetrahedralMesh>(0);
18  setRequiredInputType<PointSet>(1);
19 }
20 
21 PointToTetMap::PointToTetMap(
22  std::shared_ptr<Geometry> parent,
23  std::shared_ptr<Geometry> child)
24  : m_boundingBoxAvailable(false)
25 {
26  setRequiredInputType<TetrahedralMesh>(0);
27  setRequiredInputType<PointSet>(1);
28 
29  setParentGeometry(parent);
30  setChildGeometry(child);
31 }
32 
33 void
35 {
36  if (!areInputsValid())
37  {
38  LOG(WARNING) << "PointToTetMap failed to run, inputs not satisfied";
39  return;
40  }
41  auto tetMesh = std::dynamic_pointer_cast<TetrahedralMesh>(getParentGeometry());
42  auto triMesh = std::dynamic_pointer_cast<PointSet>(getChildGeometry());
43 
44  m_verticesEnclosingTetraId.clear();
45  m_verticesWeights.clear();
46  m_verticesEnclosingTetraId.resize(triMesh->getNumVertices());
47  m_verticesWeights.resize(triMesh->getNumVertices());
48  m_childVerts = triMesh->getVertexPositions();
49  bool bValid = true;
50 
51  if (!m_boundingBoxAvailable)
52  {
53  // calling this function inside findEnclosingTetrahedron is not thread-safe.
54  updateBoundingBox();
55  }
56 
57  ParallelUtils::parallelFor(triMesh->getNumVertices(),
58  [&](const int vertexIdx)
59  {
60  if (!bValid) // If map is invalid, no need to check further
61  {
62  return;
63  }
64  const Vec3d& surfVertPos = triMesh->getVertexPosition(vertexIdx);
65 
66  // Find the enclosing or closest tetrahedron
67  int closestTetId = findEnclosingTetrahedron(surfVertPos);
68  if (closestTetId == IMSTK_INT_MAX)
69  {
70  closestTetId = findClosestTetrahedron(surfVertPos);
71  }
72  if (closestTetId == IMSTK_INT_MAX)
73  {
74  LOG(WARNING) << "Could not find closest tetrahedron";
75  bValid = false;
76  return;
77  }
78 
79  // Compute the weights
80  const Vec4d weights = tetMesh->computeBarycentricWeights(closestTetId, surfVertPos);
81 
82  m_verticesEnclosingTetraId[vertexIdx] = closestTetId; // store nearest tetrahedron
83  m_verticesWeights[vertexIdx] = weights; // store weights
84  });
85 
86  // Clear result if could not find closest tet
87  if (!bValid)
88  {
89  m_verticesEnclosingTetraId.clear();
90  m_verticesWeights.clear();
91  }
92 }
93 
94 void
96 {
97  auto tetMesh = std::dynamic_pointer_cast<TetrahedralMesh>(getParentGeometry());
98  auto pointSet = std::dynamic_pointer_cast<PointSet>(getChildGeometry());
99 
100  std::shared_ptr<VecDataArray<int, 4>> parentIndicesPtr = tetMesh->getCells();
101  const VecDataArray<int, 4>& parentIndices = *parentIndicesPtr;
102  std::shared_ptr<VecDataArray<double, 3>> parentVertsPtr = tetMesh->getVertexPositions();
103  const VecDataArray<double, 3>& parentVerts = *parentVertsPtr;
104 
105  VecDataArray<double, 3>& childVerts = *m_childVerts;
106 
107  ParallelUtils::parallelFor(pointSet->getNumVertices(),
108  [&](const int vertexId)
109  {
110  const Vec4i& tet =
111  parentIndices[m_verticesEnclosingTetraId[vertexId]];
112  const Vec4d& weights = m_verticesWeights[vertexId];
113 
114  childVerts[vertexId] = parentVerts[tet[0]] * weights[0] +
115  parentVerts[tet[1]] * weights[1] +
116  parentVerts[tet[2]] * weights[2] +
117  parentVerts[tet[3]] * weights[3];
118  });
119 
120  pointSet->postModified();
121 
122  setOutput(pointSet);
123 }
124 
125 int
127 {
128  auto tetMesh = std::dynamic_pointer_cast<TetrahedralMesh>(getParentGeometry());
129  double closestDistanceSqr = IMSTK_DOUBLE_MAX;
130  int closestTetrahedron = IMSTK_INT_MAX;
131  Vec3d center(0.0, 0.0, 0.0);
132 
133  for (int tetId = 0; tetId < tetMesh->getNumCells(); tetId++)
134  {
135  center = Vec3d::Zero();
136  const Vec4i& vert = (*tetMesh->getCells())[tetId];
137  for (int i = 0; i < 4; i++)
138  {
139  center += tetMesh->getInitialVertexPosition(vert[i]);
140  }
141  center = center / 4.0;
142 
143  const double distSqr = (pos - center).squaredNorm();
144  if (distSqr < closestDistanceSqr)
145  {
146  closestDistanceSqr = distSqr;
147  closestTetrahedron = tetId;
148  }
149  }
150 
151  return closestTetrahedron;
152 }
153 
154 int
156 {
157  auto tetMesh = std::dynamic_pointer_cast<TetrahedralMesh>(getParentGeometry());
158  int enclosingTetrahedron = IMSTK_INT_MAX;
159 
160  for (int idx = 0; idx < tetMesh->getNumCells(); idx++)
161  {
162  const bool inBox = (pos[0] >= m_bBoxMin[idx][0] && pos[0] <= m_bBoxMax[idx][0])
163  && (pos[1] >= m_bBoxMin[idx][1] && pos[1] <= m_bBoxMax[idx][1])
164  && (pos[2] >= m_bBoxMin[idx][2] && pos[2] <= m_bBoxMax[idx][2]);
165 
166  // If the point is outside the bounding box, it is for sure not inside
167  // the element
168  if (!inBox)
169  {
170  continue;
171  }
172 
173  const Vec4d weights = tetMesh->computeBarycentricWeights(idx, pos);
174  if (weights[0] >= 0 && weights[1] >= 0 && weights[2] >= 0 && weights[3] >= 0)
175  {
176  enclosingTetrahedron = idx;
177  break;
178  }
179  }
180 
181  return enclosingTetrahedron;
182 }
183 
184 void
186 {
187  auto tetMesh = std::dynamic_pointer_cast<TetrahedralMesh>(getParentGeometry());
188  m_bBoxMin.resize(tetMesh->getNumCells());
189  m_bBoxMax.resize(tetMesh->getNumCells());
190 
191  ParallelUtils::parallelFor(tetMesh->getNumCells(),
192  [&](const int tid)
193  {
194  tetMesh->computeTetrahedronBoundingBox(tid, m_bBoxMin[tid], m_bBoxMax[tid]);
195  });
196 
197  m_boundingBoxAvailable = true;
198 }
199 } // namespace imstk
Base class for all geometries represented by discrete points and elements The pointsets follow a pipe...
Definition: imstkPointSet.h:25
void compute() override
Compute the tetra-triangle mesh map.
void requestUpdate() override
Apply (if active) the tetra-triangle mesh map.
void updateBoundingBox()
Update bounding box of each tetrahedra of the mesh.
void setParentGeometry(std::shared_ptr< Geometry > parent)
Get/Set parent geometry.
Compound Geometry.
int findClosestTetrahedron(const Vec3d &pos) const
Find the closest tetrahedron based on the distance to their centroids for a given point in 3D space...
Represents a set of tetrahedrons & vertices via an array of Vec3d double vertices & Vec4i integer ind...
void setChildGeometry(std::shared_ptr< Geometry > child)
Get/Set child geometry.
void postModified()
emits signal to all observers, informing them on the current address in memory and size of array ...
virtual void clear()
Clears all the mesh data.
virtual bool areInputsValid()
Check inputs are correct.
void setOutput(std::shared_ptr< Geometry > inputGeometry, const size_t port=0)
Set the output at the port.
int findEnclosingTetrahedron(const Vec3d &pos) const
Find the tetrahedron that encloses a given point in 3D space.