7 #include "imstkSurfaceMesh.h" 8 #include "imstkLogger.h" 9 #include "imstkVecDataArray.h" 10 #include "imstkGeometryUtilities.h" 17 const bool computeDerivedData)
21 if (computeDerivedData)
35 const bool computeDerivedData)
37 this->
initialize(vertices, triangleIndices, computeDerivedData);
41 if (computeDerivedData)
54 std::shared_ptr<SurfaceMesh> surfMesh(
this, [](
SurfaceMesh*) {});
61 LOG(WARNING) <<
"SurfaceMesh not closed";
70 std::shared_ptr<VecDataArray<double, 3>> triangleNormalsPtr = getCellNormals();
71 if (triangleNormalsPtr ==
nullptr)
73 triangleNormalsPtr = std::make_shared<VecDataArray<double, 3>>(m_indices->size());
77 if (m_indices->size() != triangleNormalsPtr->size())
79 triangleNormalsPtr->resize(m_indices->size());
86 for (
int triangleId = 0; triangleId < triangleNormals.size(); ++triangleId)
88 const auto& t = indices[triangleId];
89 const auto& p0 = vertices[t[0]];
90 const auto& p1 = vertices[t[1]];
91 const auto& p2 = vertices[t[2]];
93 triangleNormals[triangleId] = ((p1 - p0).cross(p2 - p0)).normalized();
101 std::shared_ptr<VecDataArray<float, 2>> uvsPtr = getVertexTCoords();
102 if (uvsPtr !=
nullptr)
105 std::shared_ptr<VecDataArray<double, 3>> triangleTangentsPtr = getCellTangents();
106 if (triangleTangentsPtr ==
nullptr)
108 triangleTangentsPtr = std::make_shared<VecDataArray<double, 3>>(m_indices->size());
112 if (m_indices->size() != triangleTangentsPtr->size())
114 triangleTangentsPtr->resize(m_indices->size());
120 std::shared_ptr<VecDataArray<double, 3>> triangleNormalsPtr = getCellNormals();
121 if (triangleNormalsPtr ==
nullptr)
125 triangleNormalsPtr = getCellNormals();
130 for (
int triangleId = 0; triangleId < triangleNormals.size(); ++triangleId)
132 const Vec3i& t = indices[triangleId];
133 const Vec3d& p0 = vertices[t[0]];
134 const Vec3d& p1 = vertices[t[1]];
135 const Vec3d& p2 = vertices[t[2]];
136 const Vec2f& uv0 = uvs[t[0]];
137 const Vec2f& uv1 = uvs[t[1]];
138 const Vec2f& uv2 = uvs[t[2]];
140 const Vec3d diffPos1 = p1 - p0;
141 const Vec3d diffPos2 = p2 - p0;
142 const float diffUV1[2] = { uv1[0] - uv0[0], uv1[1] - uv0[1] };
143 const float diffUV2[2] = { uv2[0] - uv0[0], uv2[1] - uv0[1] };
145 triangleTangents[triangleId] = (diffPos1 * diffUV2[1] - diffPos2 * diffUV1[0]) /
146 (diffUV1[0] * diffUV2[1] - diffUV1[1] * diffUV2[0]);
156 std::shared_ptr<VecDataArray<double, 3>> vertexNormalsPtr = getVertexNormals();
157 if (vertexNormalsPtr ==
nullptr)
159 vertexNormalsPtr = std::make_shared<VecDataArray<double, 3>>(m_vertexPositions->size());
163 if (m_vertexPositions->size() != vertexNormalsPtr->size())
165 vertexNormalsPtr->resize(m_vertexPositions->size());
177 std::shared_ptr<VecDataArray<double, 3>> triangleNormalsPtr = getCellNormals();
179 for (
int vertexId = 0; vertexId < vertexNormals.size(); ++vertexId)
181 temp_normals[vertexId] = Vec3d(0.0, 0.0, 0.0);
184 temp_normals[vertexId] += triangleNormals[triangleId];
191 for (
int vertexId = 0; vertexId < vertexNormals.size(); ++vertexId)
193 NormalGroup group = { vertices[vertexId], vertexNormals[vertexId] };
195 normal = temp_normals[vertexId];
197 if (m_UVSeamVertexGroups.find(group) == m_UVSeamVertexGroups.end())
200 vertexNormals[vertexId] = normal;
204 auto seamGroup = *m_UVSeamVertexGroups[group].get();
206 for (
auto index : seamGroup)
208 normal += temp_normals[index];
212 vertexNormals[vertexId] = normal;
225 std::shared_ptr<VecDataArray<float, 3>> vertexTangentsPtr = getVertexTangents();
226 if (vertexTangentsPtr ==
nullptr)
228 vertexTangentsPtr = std::make_shared<VecDataArray<float, 3>>(m_vertexPositions->size());
232 if (m_vertexPositions->size() != vertexTangentsPtr->size())
234 vertexTangentsPtr->resize(m_vertexPositions->size());
243 std::shared_ptr<VecDataArray<double, 3>> triangleTangentsPtr = getCellTangents();
245 for (
int vertexId = 0; vertexId < vertexTangents.size(); ++vertexId)
247 temp_vertex_tangents[vertexId] = Vec3d(0.0, 0.0, 0.0);
250 temp_vertex_tangents[vertexId] += triangleTangents[triangleId];
256 for (
int vertexId = 0; vertexId < vertexTangents.size(); ++vertexId)
258 tangent = temp_vertex_tangents[vertexId];
260 vertexTangents[vertexId] = tangent.
cast<
float>();
267 LOG(FATAL) <<
"Tried to compute per vertex tangents for mesh with no UVs";
276 return baryCentric(pos,
277 vertices[triIndices[triId][0]],
278 vertices[triIndices[triId][1]],
279 vertices[triIndices[triId][2]]);
289 std::vector<std::vector<int>> vertexNeighbors;
293 for (
const auto& tri : triangleIndices)
295 vertexNeighbors[tri[0]].push_back(triangleId);
296 vertexNeighbors[tri[1]].push_back(triangleId);
297 vertexNeighbors[tri[2]].push_back(triangleId);
302 std::shared_ptr<VecDataArray<int, 3>> optimizedConnectivityPtr = std::make_shared<VecDataArray<int, 3>>();
304 std::vector<int> optimallyOrderedNodes;
305 std::list<int> triUnderConsideration;
306 std::vector<bool> isNodeAdded(numVertices,
false);
307 std::vector<bool> isTriangleAdded(numTriangles,
false);
308 std::list<int> newlyAddedNodes;
311 optimallyOrderedNodes.push_back(0);
312 isNodeAdded.at(0) =
true;
313 for (
const auto& neighTriId : vertexNeighbors[0])
315 triUnderConsideration.push_back(neighTriId);
321 while (!triUnderConsideration.empty())
324 for (
const auto& triId : triUnderConsideration)
326 for (
int i = 0; i < 3; ++i)
328 if (!isNodeAdded.at(triangleIndices[triId][i]))
330 optimallyOrderedNodes.push_back(triangleIndices[triId][i]);
331 isNodeAdded.at(triangleIndices[triId][i]) =
true;
332 newlyAddedNodes.push_back(triangleIndices[triId][i]);
334 vertId[i] = *std::find(optimallyOrderedNodes.begin(),
335 optimallyOrderedNodes.end(),
336 triangleIndices[triId][i]);
338 optimizedConnectivity.push_back(Vec3i(vertId[0], vertId[1], vertId[2]));
339 isTriangleAdded.at(triId) =
true;
343 triUnderConsideration.clear();
344 for (
const auto& newNodes : newlyAddedNodes)
346 for (
const auto& neighTriId : vertexNeighbors[newNodes])
348 if (!isTriangleAdded[neighTriId])
350 triUnderConsideration.push_back(neighTriId);
354 triUnderConsideration.sort();
355 triUnderConsideration.unique();
357 newlyAddedNodes.clear();
361 std::shared_ptr<VecDataArray<double, 3>> optimallyOrderedNodalPos = std::make_shared<VecDataArray<double, 3>>();
362 std::shared_ptr<VecDataArray<int, 3>> optConnectivityRenumbered = std::make_shared<VecDataArray<int, 3>>();
365 optimallyOrderedNodalPos->reserve(static_cast<int>(optimallyOrderedNodes.size()));
366 for (
const auto& nodalId : optimallyOrderedNodes)
372 for (
size_t i = 0; i < numTriangles; ++i)
374 for (
int j = 0; j < 3; ++j)
376 vertId[j] = (std::find(optimallyOrderedNodes.begin(),
377 optimallyOrderedNodes.end(),
378 optimizedConnectivity[i][j]) -
379 optimallyOrderedNodes.begin());
382 Vec3i tmpTriArray = Vec3i(vertId[0], vertId[1], vertId[2]);
383 optConnectivityRenumbered->push_back(tmpTriArray);
387 this->
initialize(optimallyOrderedNodalPos, optConnectivityRenumbered);
393 for (
auto& tri : *m_indices)
395 std::swap(tri[0], tri[1]);
404 auto enforceWindingConsistency =
405 [&](
const size_t masterTriId,
const size_t neighTriId)
407 const Vec3i& parentTri = indices[masterTriId];
408 Vec3i& neighTri = indices[neighTriId];
410 for (
unsigned int l = 0; l < 3; ++l)
412 for (
unsigned int k = 0; k < 3; ++k)
414 if (parentTri[k] == neighTri[l] && parentTri[(k + 1) % 3] == neighTri[(l + 1) % 3])
417 auto tempId = neighTri[0];
418 neighTri[0] = neighTri[1];
419 neighTri[1] = tempId;
427 auto getTriangleNeighbors =
428 [&](
const size_t triID,
int* neig)
430 const auto& currentTri = indices[triID];
431 size_t currentId = 0;
433 for (
int j = 0; j < indices.size(); j++)
435 Vec3i& tri = indices[j];
436 if (triID == currentId)
443 for (
int i = 0; i < 3; ++i)
445 if (currentTri[i] == tri[0] || currentTri[i] == tri[1] || currentTri[i] == tri[2])
450 neig[numNeigh] = (int)currentId;
472 std::vector<bool> trianglesCorrected(this->
getNumCells(),
false);
473 std::vector<size_t> correctedTriangles;
475 size_t currentTriangle = 0;
476 correctedTriangles.push_back(currentTriangle);
477 trianglesCorrected[currentTriangle] =
true;
480 currentTriangle = correctedTriangles[0];
481 int neighborTri[3] = { -1, -1, -1 };
482 getTriangleNeighbors(currentTriangle, &neighborTri[0]);
484 for (
int i = 0; i < 3; ++i)
486 if (neighborTri[i] >= 0 && !trianglesCorrected[neighborTri[i]])
488 enforceWindingConsistency(currentTriangle, neighborTri[i]);
490 correctedTriangles.push_back(neighborTri[i]);
491 trianglesCorrected[neighborTri[i]] =
true;
495 correctedTriangles.erase(
496 std::remove(correctedTriangles.begin(), correctedTriangles.end(), currentTriangle),
497 correctedTriangles.end());
499 while (correctedTriangles.size() > 0);
506 m_UVSeamVertexGroups.clear();
508 std::shared_ptr<VecDataArray<double, 3>> vertexNormalsPtr = getVertexNormals();
509 if (m_vertexPositions->size() != vertexNormalsPtr->size())
517 for (
int i = 0; i < vertices.size(); i++)
519 NormalGroup group = { vertices[i], vertexNormals[i] };
521 if (m_UVSeamVertexGroups.find(group) == m_UVSeamVertexGroups.end())
523 m_UVSeamVertexGroups.insert(
524 std::pair<
NormalGroup, std::shared_ptr<std::vector<size_t>>>(
525 group, std::make_shared<std::vector<size_t>>()));
527 m_UVSeamVertexGroups[group]->push_back(i);
532 SurfaceMesh::cloneImplementation()
const 537 geom->m_indices = std::make_shared<VecDataArray<int, 3>>(*m_indices);
538 for (
auto i : m_cellAttributes)
540 geom->m_cellAttributes[i.first] = i.second->clone();
542 geom->m_initialVertexPositions = std::make_shared<VecDataArray<double, 3>>(*m_initialVertexPositions);
543 geom->m_vertexPositions = std::make_shared<VecDataArray<double, 3>>(*m_vertexPositions);
544 for (
auto i : m_vertexAttributes)
546 geom->m_vertexAttributes[i.first] = i.second->clone();
void setVertexNormals(const std::string &arrayName, std::shared_ptr< VecDataArray< double, 3 >> normals)
Get/Set the active normals.
void setCellNormals(const std::string &arrayName, std::shared_ptr< VecDataArray< double, 3 >> normals)
Get/Set the active normals.
void setVertexTangents(const std::string &arrayName, std::shared_ptr< VecDataArray< float, 3 >> tangents)
Get/Set the active tangents.
bool isClosed(std::shared_ptr< SurfaceMesh > surfMesh)
Returns if the surface is closed or not.
bool hasVertexAttribute(const std::string &arrayName) const
Check if a specific data array exists.
void optimizeForDataLocality()
Rewire the node order and triangle connectivity to optimize for memory layout The intended use is for...
void initialize(std::shared_ptr< VecDataArray< double, 3 >> vertices, std::shared_ptr< VecDataArray< int, 3 >> triangleIndices, const bool computeDerivedData=false)
Initializes the rest of the data structures given vertex positions and triangle connectivity.
void initialize(std::shared_ptr< VecDataArray< double, 3 >> vertices, std::shared_ptr< VecDataArray< int, N >> indices)
Initializes the rest of the data structures given vertex positions and connectivity.
void correctWindingOrder()
Enforces consistency in the winding order of the triangles.
void computeVertexNormals()
Computes the normals of all the vertices.
void setVertexAttribute(const std::string &arrayName, std::shared_ptr< AbstractDataArray > arr)
Set a data array holding some per vertex data.
int getNumCells() const override
Returns the number of cells.
void flipNormals()
Flip the normals for the whole mesh by reversing the winding order.
Vec3d computeBarycentricWeights(const int tetId, const Vec3d &pos) const override
compute the barycentric weights of a given point in 3D space for a given the triangle ...
void computeTriangleTangents()
Compute the tangents of all the triangles based off.
std::vector< std::unordered_set< int > > m_vertexToCells
Map of vertices to neighbor cells.
void setCellTangents(const std::string &arrayName, std::shared_ptr< VecDataArray< double, 3 >> tangents)
Get/Set the active tangents.
void computeUVSeamVertexGroups()
Finds vertices along vertex seams that share geometric properties.
Represents a set of triangles & vertices via an array of Vec3d double vertices & Vec3i integer indice...
VecDataArray< U, N > cast()
Templated copy the current array with a new internal data type, does not change the number of compone...
Vec3d & getInitialVertexPosition(const size_t vertNum)
Returns the initial position of a vertex given its index.
double getVolume() override
Get the volume enclosed by the surface mesh.
int getNumVertices() const
Returns the number of total vertices in the mesh.
void computeVertexTangents()
Comptues the tangents of all the vertices.
double getVolume(std::shared_ptr< SurfaceMesh > surfMesh)
Returns volume estimate of closed SurfaceMesh.
void computeTrianglesNormals()
Compute the normals of all the triangles.
Helper class for indentifying duplicate points.
void computeVertexToCellMap() override
Computes neighboring cells for all vertices.