11 #include <Eigen/Dense>
17 #include <unordered_map>
37 if (mesh.
IsEmpty())
return (*
this);
39 size_t old_tetra_num =
tetras_.size();
40 size_t add_tetra_num = mesh.
tetras_.size();
43 Vector4i index_shift = Vector4i::Constant(
static_cast<int>(old_vert_num));
44 for (
size_t i = 0; i < add_tetra_num; i++) {
56 typedef std::tuple<double, double, double> Coordinate3;
57 std::unordered_map<Coordinate3, size_t,
60 std::vector<Index> index_old_to_new(
vertices_.size());
63 for (
size_t i = 0; i < old_vertex_num; i++) {
66 if (point_to_old_index.find(coord) == point_to_old_index.end()) {
67 point_to_old_index[coord] = i;
69 index_old_to_new[i] = (
Index)k;
72 index_old_to_new[i] = index_old_to_new[point_to_old_index[coord]];
76 if (k < old_vertex_num) {
78 tetra(0) = index_old_to_new[tetra(0)];
79 tetra(1) = index_old_to_new[tetra(1)];
80 tetra(2) = index_old_to_new[tetra(2)];
81 tetra(3) = index_old_to_new[tetra(3)];
85 "[RemoveDuplicatedVertices] {:d} vertices have been removed.",
86 (
int)(old_vertex_num - k));
93 typedef std::tuple<Index, Index, Index, Index> Index4;
94 std::unordered_map<Index4, size_t, utility::hash_tuple<Index4>>
96 size_t old_tetra_num =
tetras_.size();
98 for (
size_t i = 0; i < old_tetra_num; i++) {
105 std::sort(t.begin(), t.end());
106 index = std::make_tuple(t[0], t[1], t[2], t[3]);
108 if (tetra_to_old_index.find(index) == tetra_to_old_index.end()) {
109 tetra_to_old_index[index] = i;
116 "[RemoveDuplicatedTetras] {:d} tetras have been removed.",
117 (
int)(old_tetra_num - k));
124 std::vector<bool> vertex_has_reference(
vertices_.size(),
false);
125 for (
const auto &tetra :
tetras_) {
126 vertex_has_reference[tetra(0)] =
true;
127 vertex_has_reference[tetra(1)] =
true;
128 vertex_has_reference[tetra(2)] =
true;
129 vertex_has_reference[tetra(3)] =
true;
131 std::vector<Index> index_old_to_new(
vertices_.size());
132 size_t old_vertex_num =
vertices_.size();
134 for (
size_t i = 0; i < old_vertex_num; i++) {
135 if (vertex_has_reference[i]) {
137 index_old_to_new[i] = (
Index)k;
140 index_old_to_new[i] = -1;
144 if (k < old_vertex_num) {
146 tetra(0) = index_old_to_new[tetra(0)];
147 tetra(1) = index_old_to_new[tetra(1)];
148 tetra(2) = index_old_to_new[tetra(2)];
149 tetra(3) = index_old_to_new[tetra(3)];
153 "[RemoveUnreferencedVertices] {:d} vertices have been removed.",
154 (
int)(old_vertex_num - k));
160 size_t old_tetra_num =
tetras_.size();
162 for (
size_t i = 0; i < old_tetra_num; i++) {
163 const auto &tetra =
tetras_[i];
164 if (tetra(0) != tetra(1) && tetra(0) != tetra(2) &&
165 tetra(0) != tetra(3) && tetra(1) != tetra(2) &&
166 tetra(1) != tetra(3) && tetra(2) != tetra(3)) {
173 "[RemoveDegenerateTetras] {:d} tetras have been "
175 (
int)(old_tetra_num - k));
180 const std::vector<double> &values,
double level) {
182 static_assert(std::is_signed<Index>(),
"Index type must be signed");
183 typedef std::tuple<Index, Index> Index2;
186 assert(baseVertices);
187 auto triangle_mesh = std::make_shared<ccMesh>(baseVertices);
191 "[ExtractTriangleMesh] number of values does not match the "
192 "number of vertices.");
195 auto SurfaceIntersectionTest = [](
double v0,
double v1,
double level) {
196 return (v0 < level && v1 >= level) || (v0 >= level && v1 < level);
199 auto ComputeEdgeVertex = [&values, level,
this](
Index idx1,
Index idx2) {
200 double v1 = values[idx1];
201 double v2 = values[idx2];
203 double t = (level - v2) / (v1 - v2);
204 if (std::isnan(t) || t < 0 || t > 1) {
207 Eigen::Vector3d intersection =
213 auto ComputeTriangleNormal = [](
const Eigen::Vector3d &
a,
214 const Eigen::Vector3d &b,
215 const Eigen::Vector3d &c) {
216 Eigen::Vector3d ab = b -
a;
217 Eigen::Vector3d ac = c -
a;
223 return std::make_tuple(
a, b);
225 return std::make_tuple(b,
a);
228 auto HasCommonVertexIndex = [](Index2
a, Index2 b) {
229 return std::get<0>(b) == std::get<0>(
a) ||
230 std::get<1>(b) == std::get<0>(
a) ||
231 std::get<0>(b) == std::get<1>(
a) ||
232 std::get<1>(b) == std::get<1>(
a);
235 std::unordered_map<Index2, size_t, utility::hash_tuple<Index2>>
238 const int tetra_edges[][2] = {{0, 1}, {0, 2}, {0, 3},
239 {1, 2}, {1, 3}, {2, 3}};
241 for (
size_t tetra_i = 0; tetra_i <
tetras_.size(); ++tetra_i) {
242 const auto &tetra =
tetras_[tetra_i];
244 std::array<Eigen::Vector3d, 4> verts;
245 std::array<Index2, 4> keys;
246 std::array<Index, 4> verts_indices;
247 std::array<Eigen::Vector3d, 4> edge_dirs;
250 for (
int tet_edge_i = 0; tet_edge_i < 6; ++tet_edge_i) {
251 Index edge_vert1 = tetra[tetra_edges[tet_edge_i][0]];
252 Index edge_vert2 = tetra[tetra_edges[tet_edge_i][1]];
253 double vert_value1 = values[edge_vert1];
254 double vert_value2 = values[edge_vert2];
255 if (SurfaceIntersectionTest(vert_value1, vert_value2, level)) {
256 Index2 index = MakeSortedTuple2(edge_vert1, edge_vert2);
257 verts[num_verts] = ComputeEdgeVertex(edge_vert1, edge_vert2);
258 keys[num_verts] = index;
262 if (values[edge_vert1] > values[edge_vert2])
264 edge_dirs[num_verts] =
271 for (
int i = 0; i < num_verts; ++i) {
272 if (intersecting_edges.count(keys[i]) == 0) {
273 Index idx =
static_cast<Index>(intersecting_edges.size());
274 verts_indices[i] = idx;
275 intersecting_edges[keys[i]] = idx;
278 verts_indices[i] =
Index(intersecting_edges[keys[i]]);
283 if (3 == num_verts) {
287 Eigen::Vector3d tri_normal =
288 ComputeTriangleNormal(verts[0], verts[1], verts[2]);
292 for (
int i = 0; i < 3; ++i) dot += tri_normal.dot(edge_dirs[i]);
293 if (dot < 0)
std::swap(tri.x(), tri.y());
295 triangle_mesh->addTriangle(tri);
296 }
else if (4 == num_verts) {
297 std::array<int, 4> order = {-1, 0, 0, 0};
298 if (HasCommonVertexIndex(keys[0], keys[1]) &&
299 HasCommonVertexIndex(keys[0], keys[2])) {
300 order = {1, 0, 2, 3};
301 }
else if (HasCommonVertexIndex(keys[0], keys[1]) &&
302 HasCommonVertexIndex(keys[0], keys[3])) {
303 order = {1, 0, 3, 2};
304 }
else if (HasCommonVertexIndex(keys[0], keys[2]) &&
305 HasCommonVertexIndex(keys[0], keys[3])) {
306 order = {2, 0, 3, 1};
309 if (order[0] != -1) {
313 for (
int i = 0; i < 4; ++i) {
314 Eigen::Vector3d tri_normal = ComputeTriangleNormal(
315 verts[order[(4 + i - 1) % 4]], verts[order[i]],
316 verts[order[(i + 1) % 4]]);
317 dot += tri_normal.dot(edge_dirs[order[i]]);
319 if (dot < 0) std::reverse(order.begin(), order.end());
321 std::array<Eigen::Vector3i, 2> tris;
322 if ((verts[order[0]] - verts[order[2]]).squaredNorm() <
323 (verts[order[1]] - verts[order[3]]).squaredNorm()) {
324 tris[0] << verts_indices[order[0]], verts_indices[order[1]],
325 verts_indices[order[2]];
326 tris[1] << verts_indices[order[2]], verts_indices[order[3]],
327 verts_indices[order[0]];
329 tris[0] << verts_indices[order[0]], verts_indices[order[1]],
330 verts_indices[order[3]];
331 tris[1] << verts_indices[order[1]], verts_indices[order[2]],
332 verts_indices[order[3]];
335 triangle_mesh->addTriangle(tris[0]);
336 triangle_mesh->addTriangle(tris[1]);
339 "[ExtractTriangleMesh] failed to create triangles for "
340 "tetrahedron {:d}: invalid edge configuration for "
344 }
else if (0 != num_verts) {
346 "[ExtractTriangleMesh] failed to create triangles for "
347 "tetrahedron {:d}: unexpected number of vertices {:d}",
348 int(tetra_i), num_verts);
352 return triangle_mesh;
A 3D cloud and its associated features (color, normals, scalar fields, etc.)
void addEigenPoint(const Eigen::Vector3d &point)
Tetra mesh contains vertices and tetrahedra represented by the indices to the vertices.
TetraMesh & operator+=(const TetraMesh &mesh)
TetraMesh & RemoveDuplicatedVertices()
Function that removes duplicated verties, i.e., vertices that have identical coordinates.
TetraMesh(const char *name="TetraMesh")
Default ccMesh constructor.
std::vector< Eigen::Vector4i, cloudViewer::utility::Vector4i_allocator > tetras_
List of tetras denoted by the index of points forming the tetra.
TetraMesh & RemoveUnreferencedVertices()
This function removes vertices from the tetra mesh that are not referenced in any tetrahedron of the ...
std::shared_ptr< ccMesh > ExtractTriangleMesh(const std::vector< double > &values, double level)
Function to extract a triangle mesh of the specified iso-surface at a level This method applies prima...
TetraMesh & RemoveDuplicatedTetras()
Function that removes duplicated tetrahedra, i.e., removes tetrahedra that reference the same four ve...
virtual TetraMesh & clear() override
TetraMesh operator+(const TetraMesh &mesh) const
TetraMesh & RemoveDegenerateTetras()
Function that removes degenerate tetrahedra, i.e., tetrahedra that reference a single vertex multiple...
virtual ecvMeshBase & clear()
ecvMeshBase & operator+=(const ecvMeshBase &mesh)
virtual bool IsEmpty() const override
std::vector< Eigen::Vector3d > vertices_
Vertex coordinates.
Generic file read and write utility for python interface.
Eigen::Matrix< Index, 3, 1 > Vector3i
Eigen::Matrix< Index, 4, 1 > Vector4i
Eigen::MatrixXd::Index Index
void swap(cloudViewer::core::SmallVectorImpl< T > &LHS, cloudViewer::core::SmallVectorImpl< T > &RHS)
Implement std::swap in terms of SmallVector swap.