iMSTK
Interactive Medical Simulation Toolkit
imstkPointSet.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 "imstkPointSet.h"
8 #include "imstkParallelUtils.h"
9 #include "imstkLogger.h"
10 #include "imstkVecDataArray.h"
11 
12 namespace imstk
13 {
14 PointSet::PointSet() :
15  m_initialVertexPositions(std::make_shared<VecDataArray<double, 3>>()),
16  m_vertexPositions(std::make_shared<VecDataArray<double, 3>>())
17 {
18 }
19 
20 void
22 {
23  // Copy data to initial
24  this->setInitialVertexPositions(std::make_shared<VecDataArray<double, 3>>(*vertices));
25 
26  // Use in place as current vertices
27  this->setVertexPositions(vertices);
28 }
29 
30 void
32 {
33  if (m_initialVertexPositions != nullptr)
34  {
35  m_initialVertexPositions->clear();
36  }
37  if (m_vertexPositions != nullptr)
38  {
39  m_vertexPositions->clear();
40  }
41  for (auto i : m_vertexAttributes)
42  {
43  i.second->clear();
44  }
45 }
46 
47 void
49 {
51  LOG(INFO) << "Number of vertices: " << this->getNumVertices();
52  LOG(INFO) << "Vertex positions:";
53  for (auto& verts : *m_vertexPositions)
54  {
55  LOG(INFO) << "\t" << verts.x() << ", " << verts.y() << ", " << verts.z();
56  }
57  for (auto i : m_vertexAttributes)
58  {
59  LOG(INFO) << i.first;
60  //i.second->print();
61  }
62 }
63 
64 void
65 PointSet::computeBoundingBox(Vec3d& lowerCorner, Vec3d& upperCorner, const double paddingPercent)
66 {
67  bool updateBounds = !m_transformApplied || m_boundsDirty;
69  if (updateBounds)
70  {
71  ParallelUtils::findAABB(*m_vertexPositions, m_lowerCorner, m_upperCorner);
72  m_boundsDirty = false;
73  }
74  lowerCorner = m_lowerCorner;
75  upperCorner = m_upperCorner;
76  if (paddingPercent > 0.0)
77  {
78  const Vec3d range = (m_upperCorner - m_lowerCorner) * (paddingPercent / 100.0);
79  lowerCorner -= range;
80  upperCorner += range;
81  }
82 }
83 
84 void
86 {
87  m_initialVertexPositions = vertices;
88 }
89 
90 Vec3d&
92 {
93 #if defined(DEBUG) || defined(_DEBUG) || !defined(NDEBUG)
94  LOG_IF(FATAL, (static_cast<int>(vertNum) >= m_initialVertexPositions->size())) << "Invalid index";
95 #endif
96  return (*m_initialVertexPositions)[vertNum];
97 }
98 
99 void
101 {
102  m_vertexPositions = vertices;
103  m_boundsDirty = true;
104  //m_transformApplied = false;
105 
106  this->updatePostTransformData();
107 }
108 
109 std::shared_ptr<VecDataArray<double, 3>>
111 {
112  if (type == DataType::PostTransform)
113  {
114  this->updatePostTransformData();
115  return m_vertexPositions;
116  }
117  return m_initialVertexPositions;
118 }
119 
120 void
121 PointSet::setVertexPosition(const size_t vertNum, const Vec3d& pos)
122 {
123 #if defined(DEBUG) || defined(_DEBUG) || !defined(NDEBUG)
124  LOG_IF(FATAL, (static_cast<int>(vertNum) >= m_vertexPositions->size())) << "Invalid index";
125 #endif
126  (*m_vertexPositions)[vertNum] = pos;
127  m_transformApplied = false;
128  m_boundsDirty = true;
129  this->updatePostTransformData();
130 }
131 
132 const Vec3d&
133 PointSet::getVertexPosition(const size_t vertNum, DataType type) const
134 {
135 #if defined(DEBUG) || defined(_DEBUG) || !defined(NDEBUG)
136  LOG_IF(FATAL, (static_cast<int>(vertNum) >= getVertexPositions()->size())) << "Invalid index";
137 #endif
138  return (*this->getVertexPositions(type))[vertNum];
139 }
140 
141 Vec3d&
142 PointSet::getVertexPosition(const size_t vertNum, DataType type)
143 {
144 #if defined(DEBUG) || defined(_DEBUG) || !defined(NDEBUG)
145  LOG_IF(FATAL, (static_cast<int>(vertNum) >= getVertexPositions()->size())) << "Invalid index";
146 #endif
147  return (*this->getVertexPositions(type))[vertNum];
148 }
149 
150 int
152 {
153  return m_vertexPositions->size();
154 }
155 
156 // Note: cannot apply tranform twice, let shader tranform if not dyanmic
157 void
159 {
160  VecDataArray<double, 3>& initVertices = *m_initialVertexPositions;
161  VecDataArray<double, 3>& vertices = *m_vertexPositions;
162 
163  std::shared_ptr<VecDataArray<double, 3>> normalsPtr = getVertexNormals();
164  std::shared_ptr<VecDataArray<float, 3>> tangentsPtr = getVertexTangents();
165 
166  ParallelUtils::parallelFor(initVertices.size(),
167  [&](const size_t i)
168  {
169  initVertices[i] = (m * Vec4d(initVertices[i][0], initVertices[i][1], initVertices[i][2], 1.0)).head<3>();
170  vertices[i] = initVertices[i];
171  });
172 
173  // If there are normals, rotate them here
174  if (normalsPtr != NULL)
175  {
176  // Assumes affine, no shear
177  const Vec3d& x = m.block<3, 1>(0, 0);
178  const Vec3d& y = m.block<3, 1>(0, 1);
179  const Vec3d& z = m.block<3, 1>(0, 2);
180 
181  Mat3d r; // rotation part of transformation
182  r.block<3, 1>(0, 0) = x.normalized();
183  r.block<3, 1>(0, 1) = y.normalized();
184  r.block<3, 1>(0, 2) = z.normalized();
185 
186  VecDataArray<double, 3>& normals = *normalsPtr;
187  ParallelUtils::parallelFor(normals.size(),
188  [&](const size_t i)
189  {
190  normals[i] = (r * Vec3d(normals[i][0], normals[i][1], normals[i][2]));
191  });
192 
193  normals.postModified();
194  }
195  // If there are tangents, rotate them here
196  if (tangentsPtr != NULL)
197  {
198  // Assumes affine, no shear
199  const Vec3d& x = m.block<3, 1>(0, 0);
200  const Vec3d& y = m.block<3, 1>(0, 1);
201  const Vec3d& z = m.block<3, 1>(0, 2);
202 
203  Mat3d rd; // rotation part of transformation
204  rd.block<3, 1>(0, 0) = x.normalized();
205  rd.block<3, 1>(0, 1) = y.normalized();
206  rd.block<3, 1>(0, 2) = z.normalized();
207 
208  Mat3f r = rd.cast<float>();
209 
210  VecDataArray<float, 3>& tangents = *tangentsPtr;
211  ParallelUtils::parallelFor(tangents.size(),
212  [&](const size_t i)
213  {
214  tangents[i] = (r * Vec3f(tangents[i][0], tangents[i][1], tangents[i][2]));
215  });
216 
217  tangents.postModified();
218  }
219 
220  m_boundsDirty = true;
221  m_transformApplied = false;
222  this->updatePostTransformData();
223 }
224 
225 void
227 {
228  if (m_transformApplied || m_transform.isApprox(Mat4d::Identity()))
229  {
230  return;
231  }
232 
233  const VecDataArray<double, 3>& initVertices = *m_initialVertexPositions;
234  VecDataArray<double, 3>& vertices = *m_vertexPositions;
235 
236  if (initVertices.size() != vertices.size())
237  {
238  vertices.resize(initVertices.size());
239  }
240 
241  ParallelUtils::parallelFor(vertices.size(),
242  [&](const size_t i)
243  {
244  vertices[i] = (m_transform * Vec4d(initVertices[i][0], initVertices[i][1], initVertices[i][2], 1.0)).head<3>();
245  });
246  m_transformApplied = true;
247  m_boundsDirty = true;
248 }
249 
250 bool
251 PointSet::hasVertexAttribute(const std::string& arrayName) const
252 {
253  return (m_vertexAttributes.find(arrayName) != m_vertexAttributes.end());
254 }
255 
256 void
257 PointSet::setVertexAttribute(const std::string& arrayName, std::shared_ptr<AbstractDataArray> arr)
258 {
259  m_vertexAttributes[arrayName] = arr;
260 }
261 
262 std::shared_ptr<AbstractDataArray>
263 PointSet::getVertexAttribute(const std::string& arrayName) const
264 {
265  auto it = m_vertexAttributes.find(arrayName);
266  if (it == m_vertexAttributes.end())
267  {
268  return nullptr;
269  }
270  return it->second;
271 }
272 
273 void
274 PointSet::setVertexScalars(const std::string& arrayName, std::shared_ptr<AbstractDataArray> scalars)
275 {
276  m_activeVertexScalars = arrayName;
277  m_vertexAttributes[arrayName] = scalars;
278 }
279 
280 void
281 PointSet::setVertexScalars(const std::string& arrayName)
282 {
283  if (hasVertexAttribute(arrayName))
284  {
285  m_activeVertexScalars = arrayName;
286  }
287 }
288 
289 std::shared_ptr<AbstractDataArray>
290 PointSet::getVertexScalars() const
291 {
292  if (hasVertexAttribute(m_activeVertexScalars))
293  {
294  return m_vertexAttributes.at(m_activeVertexScalars);
295  }
296  else
297  {
298  return nullptr;
299  }
300 }
301 
302 void
303 PointSet::setVertexNormals(const std::string& arrayName, std::shared_ptr<VecDataArray<double, 3>> normals)
304 {
305  m_activeVertexNormals = arrayName;
306  m_vertexAttributes[arrayName] = normals;
307 }
308 
309 void
310 PointSet::setVertexNormals(const std::string& arrayName)
311 {
312  if (hasVertexAttribute(arrayName))
313  {
314  setActiveVertexAttribute(m_activeVertexNormals, arrayName, 3, IMSTK_DOUBLE);
315  }
316 }
317 
318 std::shared_ptr<VecDataArray<double, 3>>
319 PointSet::getVertexNormals() const
320 {
321  if (hasVertexAttribute(m_activeVertexNormals))
322  {
323  return std::dynamic_pointer_cast<VecDataArray<double, 3>>(m_vertexAttributes.at(m_activeVertexNormals));
324  }
325  else
326  {
327  return nullptr;
328  }
329 }
330 
331 void
332 PointSet::setVertexTangents(const std::string& arrayName, std::shared_ptr<VecDataArray<float, 3>> tangents)
333 {
334  m_activeVertexTangents = arrayName;
335  m_vertexAttributes[arrayName] = tangents;
336 }
337 
338 void
339 PointSet::setVertexTangents(const std::string& arrayName)
340 {
341  if (hasVertexAttribute(arrayName))
342  {
343  setActiveVertexAttribute(m_activeVertexTangents, arrayName, 3, IMSTK_FLOAT);
344  }
345 }
346 
347 std::shared_ptr<VecDataArray<float, 3>>
348 PointSet::getVertexTangents() const
349 {
350  if (hasVertexAttribute(m_activeVertexTangents))
351  {
352  return std::dynamic_pointer_cast<VecDataArray<float, 3>>(m_vertexAttributes.at(m_activeVertexTangents));
353  }
354  else
355  {
356  return nullptr;
357  }
358 }
359 
360 void
361 PointSet::setVertexTCoords(const std::string& arrayName, std::shared_ptr<VecDataArray<float, 2>> tcoords)
362 {
363  m_activeVertexTCoords = arrayName;
364  m_vertexAttributes[arrayName] = tcoords;
365 }
366 
367 void
368 PointSet::setVertexTCoords(const std::string& arrayName)
369 {
370  if (hasVertexAttribute(arrayName))
371  {
372  setActiveVertexAttribute(m_activeVertexTCoords, arrayName, 2, IMSTK_FLOAT);
373  }
374 }
375 
376 std::shared_ptr<VecDataArray<float, 2>>
377 PointSet::getVertexTCoords() const
378 {
379  if (hasVertexAttribute(m_activeVertexTCoords))
380  {
381  return std::dynamic_pointer_cast<VecDataArray<float, 2>>(m_vertexAttributes.at(m_activeVertexTCoords));
382  }
383  else
384  {
385  return nullptr;
386  }
387 }
388 
389 void
390 PointSet::setActiveVertexAttribute(std::string& activeAttributeName, std::string attributeName,
391  const int expectedNumComponents, const ScalarTypeId expectedScalarType)
392 {
393  std::shared_ptr<AbstractDataArray> attribute = m_vertexAttributes[attributeName];
394  if (attribute->getNumberOfComponents() != expectedNumComponents)
395  {
396  LOG(WARNING) << "Failed to set vertex attribute on PointSet " + getName() + " with "
397  << attribute->getNumberOfComponents() << " components. Expected " <<
398  expectedNumComponents << " components.";
399  return;
400  }
401  else if (attribute->getScalarType() != expectedScalarType)
402  {
403  LOG(INFO) << "Tried to set vertex attribute on PointSet " + getName() + " with scalar type "
404  << static_cast<int>(attribute->getScalarType()) << ". Casting to "
405  << static_cast<int>(expectedScalarType) << " scalar type";
406  m_vertexAttributes[attributeName] = attribute->cast(expectedScalarType);
407  }
408  activeAttributeName = attributeName;
409 }
410 
411 PointSet*
412 PointSet::cloneImplementation() const
413 {
414  // Do shallow copy
415  PointSet* geom = new PointSet(*this);
416  // Deal with deep copy members
417  geom->m_initialVertexPositions = std::make_shared<VecDataArray<double, 3>>(*m_initialVertexPositions);
418  geom->m_vertexPositions = std::make_shared<VecDataArray<double, 3>>(*m_vertexPositions);
419  for (auto i : m_vertexAttributes)
420  {
421  geom->m_vertexAttributes[i.first] = i.second->clone();
422  }
423  return geom;
424 }
425 } // namespace imstk
Mat4d m_transform
Transformation matrix.
void initialize(std::shared_ptr< VecDataArray< double, 3 >> positions)
Initializes the data structure given vertex positions.
void setVertexNormals(const std::string &arrayName, std::shared_ptr< VecDataArray< double, 3 >> normals)
Get/Set the active normals.
Base class for all geometries represented by discrete points and elements The pointsets follow a pipe...
Definition: imstkPointSet.h:25
void setVertexTangents(const std::string &arrayName, std::shared_ptr< VecDataArray< float, 3 >> tangents)
Get/Set the active tangents.
virtual void print() const
Print.
std::shared_ptr< AbstractDataArray > getVertexAttribute(const std::string &arrayName) const
Get a specific data array. If the array name cannot be found, nullptr is returned.
void applyTransform(const Mat4d &m) override
Applies transformation m directly the initial and post transform data.
virtual void print() const override
Print the mesh info.
bool hasVertexAttribute(const std::string &arrayName) const
Check if a specific data array exists.
void setVertexTCoords(const std::string &arrayName, std::shared_ptr< VecDataArray< float, 2 >> tcoords)
Get/Set the active tcoords.
Compound Geometry.
void resize(const int size) override
Resize data array to hold exactly size number of values.
virtual void computeBoundingBox(Vec3d &lowerCorner, Vec3d &upperCorner, const double paddingPercent=0.0) override
Compute the bounding box for the entire mesh.
void setVertexAttribute(const std::string &arrayName, std::shared_ptr< AbstractDataArray > arr)
Set a data array holding some per vertex data.
void updatePostTransformData() const override
Applies the geometries member transform to produce currPositions.
void setVertexScalars(const std::string &arrayName, std::shared_ptr< AbstractDataArray > scalars)
Get/Set the active scalars.
void setActiveVertexAttribute(std::string &activeAttributeName, const std::string attributeName, const int expectedNumComponents, const ScalarTypeId expectedScalarType)
Sets the active vertex attribute name as long as the # components is satisfied. Throws message and ca...
const Vec3d & getVertexPosition(const size_t vertNum, DataType type=DataType::PostTransform) const
Returns the position of a vertex given its index.
const std::string & getName() const
Get the name of the geometry.
void setVertexPosition(const size_t vertNum, const Vec3d &pos)
Set the current position of a vertex given its index to certain position (this is not a thread-safe m...
void setInitialVertexPositions(std::shared_ptr< VecDataArray< double, 3 >> vertices)
Sets initial positions from an array.
std::shared_ptr< VecDataArray< double, 3 > > getVertexPositions(DataType type=DataType::PostTransform) const
Returns the vector of current positions of the mesh vertices.
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.
void setVertexPositions(std::shared_ptr< VecDataArray< double, 3 >> positions)
Sets current vertex positions of the mesh.
Vec3d & getInitialVertexPosition(const size_t vertNum)
Returns the initial position of a vertex given its index.
int getNumVertices() const
Returns the number of total vertices in the mesh.
DataType
Enumeration for the data to retrieve PreTransform for data where transform matrix is not applied Po...
Definition: imstkGeometry.h:41