ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
SurfaceReconstructionAlphaShape.cpp
Go to the documentation of this file.
1 // ----------------------------------------------------------------------------
2 // - CloudViewer: www.cloudViewer.org -
3 // ----------------------------------------------------------------------------
4 // Copyright (c) 2018-2024 www.cloudViewer.org
5 // SPDX-License-Identifier: MIT
6 // ----------------------------------------------------------------------------
7 
8 #include <Logging.h>
9 
10 #include <Eigen/Dense>
11 #include <iostream>
12 #include <list>
13 
14 #include "ecvHObjectCaster.h"
15 #include "ecvMesh.h"
16 #include "ecvPointCloud.h"
17 #include "ecvQhull.h"
18 #include "ecvTetraMesh.h"
19 
21  const ccPointCloud& pcd,
22  double alpha,
23  std::shared_ptr<cloudViewer::geometry::TetraMesh> tetra_mesh,
24  std::vector<size_t>* pt_map) {
25  std::vector<size_t> pt_map_computed;
26  if (tetra_mesh == nullptr) {
28  "[CreateFromPointCloudAlphaShape] "
29  "ComputeDelaunayTetrahedralization");
30  std::tie(tetra_mesh, pt_map_computed) =
32  pcd.getPoints());
33  pt_map = &pt_map_computed;
35  "[CreateFromPointCloudAlphaShape] done "
36  "ComputeDelaunayTetrahedralization");
37  }
38 
40  "[CreateFromPointCloudAlphaShape] init triangle mesh");
41 
42  ccPointCloud* baseVertices = new ccPointCloud("vertices");
43  assert(baseVertices);
44  baseVertices->setEnabled(false);
45  // DGM: no need to lock it as it is only used by one mesh!
46  baseVertices->setLocked(false);
47  auto mesh = std::make_shared<ccMesh>(baseVertices);
48  mesh->addChild(baseVertices);
49 
50  baseVertices->addPoints(tetra_mesh->vertices_);
51  if (pcd.hasNormals()) {
52  baseVertices->resizeTheNormsTable();
53  for (size_t idx = 0; idx < (*pt_map).size(); ++idx) {
54  baseVertices->setPointNormal(
55  static_cast<unsigned>(idx),
56  pcd.getPointNormal(static_cast<unsigned>((*pt_map)[idx])));
57  }
58  }
59  if (pcd.hasColors()) {
60  baseVertices->resizeTheRGBTable();
61  for (size_t idx = 0; idx < (*pt_map).size(); ++idx) {
62  baseVertices->setPointColor(
63  static_cast<unsigned>(idx),
64  pcd.getPointColor(static_cast<unsigned>((*pt_map)[idx])));
65  }
66  }
68  "[CreateFromPointCloudAlphaShape] done init triangle mesh");
69 
70  std::vector<double> vsqn(tetra_mesh->vertices_.size());
71  for (size_t vidx = 0; vidx < vsqn.size(); ++vidx) {
72  vsqn[vidx] = tetra_mesh->vertices_[vidx].squaredNorm();
73  }
74 
76  "[CreateFromPointCloudAlphaShape] add triangles from tetras that "
77  "satisfy constraint");
78  const auto& verts = tetra_mesh->vertices_;
79  for (size_t tidx = 0; tidx < tetra_mesh->tetras_.size(); ++tidx) {
80  const auto& tetra = tetra_mesh->tetras_[tidx];
81  // clang-format off
82  Eigen::Matrix4d tmp;
83  tmp << verts[tetra(0)](0), verts[tetra(0)](1), verts[tetra(0)](2), 1,
84  verts[tetra(1)](0), verts[tetra(1)](1), verts[tetra(1)](2), 1,
85  verts[tetra(2)](0), verts[tetra(2)](1), verts[tetra(2)](2), 1,
86  verts[tetra(3)](0), verts[tetra(3)](1), verts[tetra(3)](2), 1;
87  double a = tmp.determinant();
88  tmp << vsqn[tetra(0)], verts[tetra(0)](0), verts[tetra(0)](1), verts[tetra(0)](2),
89  vsqn[tetra(1)], verts[tetra(1)](0), verts[tetra(1)](1), verts[tetra(1)](2),
90  vsqn[tetra(2)], verts[tetra(2)](0), verts[tetra(2)](1), verts[tetra(2)](2),
91  vsqn[tetra(3)], verts[tetra(3)](0), verts[tetra(3)](1), verts[tetra(3)](2);
92  double c = tmp.determinant();
93  tmp << vsqn[tetra(0)], verts[tetra(0)](1), verts[tetra(0)](2), 1,
94  vsqn[tetra(1)], verts[tetra(1)](1), verts[tetra(1)](2), 1,
95  vsqn[tetra(2)], verts[tetra(2)](1), verts[tetra(2)](2), 1,
96  vsqn[tetra(3)], verts[tetra(3)](1), verts[tetra(3)](2), 1;
97  double dx = tmp.determinant();
98  tmp << vsqn[tetra(0)], verts[tetra(0)](0), verts[tetra(0)](2), 1,
99  vsqn[tetra(1)], verts[tetra(1)](0), verts[tetra(1)](2), 1,
100  vsqn[tetra(2)], verts[tetra(2)](0), verts[tetra(2)](2), 1,
101  vsqn[tetra(3)], verts[tetra(3)](0), verts[tetra(3)](2), 1;
102  double dy = tmp.determinant();
103  tmp << vsqn[tetra(0)], verts[tetra(0)](0), verts[tetra(0)](1), 1,
104  vsqn[tetra(1)], verts[tetra(1)](0), verts[tetra(1)](1), 1,
105  vsqn[tetra(2)], verts[tetra(2)](0), verts[tetra(2)](1), 1,
106  vsqn[tetra(3)], verts[tetra(3)](0), verts[tetra(3)](1), 1;
107  double dz = tmp.determinant();
108  // clang-format on
109  if (a == 0) {
111  "[CreateFromPointCloudAlphaShape] invalid tetra in "
112  "TetraMesh");
113  }
114  double r = std::sqrt(dx * dx + dy * dy + dz * dz - 4 * a * c) /
115  (2 * std::abs(a));
116 
117  if (r <= alpha) {
118  mesh->addTriangle(
119  ccMesh::GetOrderedTriangle(tetra(0), tetra(1), tetra(2)));
120  mesh->addTriangle(
121  ccMesh::GetOrderedTriangle(tetra(0), tetra(1), tetra(3)));
122  mesh->addTriangle(
123  ccMesh::GetOrderedTriangle(tetra(0), tetra(2), tetra(3)));
124  mesh->addTriangle(
125  ccMesh::GetOrderedTriangle(tetra(1), tetra(2), tetra(3)));
126  }
127  }
129  "[CreateFromPointCloudAlphaShape] done add triangles from tetras "
130  "that satisfy constraint");
131 
133  "[CreateFromPointCloudAlphaShape] remove triangles within "
134  "the mesh");
135  std::unordered_map<Eigen::Vector3i, int,
137  triangle_count;
138  for (size_t tidx = 0; tidx < mesh->size(); ++tidx) {
139  Eigen::Vector3i triangle = mesh->getTriangle(tidx);
140  if (triangle_count.count(triangle) == 0) {
141  triangle_count[triangle] = 1;
142  } else {
143  triangle_count[triangle] += 1;
144  }
145  }
146 
147  size_t to_idx = 0;
148  for (size_t tidx = 0; tidx < mesh->size(); ++tidx) {
149  Eigen::Vector3i triangle = mesh->getTriangle(tidx);
150  if (triangle_count[triangle] == 1) {
151  mesh->setTriangle(to_idx, triangle);
152  to_idx++;
153  }
154  }
155  mesh->resize(to_idx);
157  "[CreateFromPointCloudAlphaShape] done remove triangles within "
158  "the mesh");
159 
161  "[CreateFromPointCloudAlphaShape] remove duplicate triangles and "
162  "unreferenced vertices");
163 
164  // do some cleaning
165  {
166  baseVertices->shrinkToFit();
167  mesh->shrinkToFit();
168  NormsIndexesTableType* normals = mesh->getTriNormsTable();
169  if (normals) {
170  normals->shrink_to_fit();
171  }
172  mesh->RemoveDuplicatedTriangles();
173  mesh->RemoveUnreferencedVertices();
174  }
175 
177  "[CreateFromPointCloudAlphaShape] done remove duplicate triangles "
178  "and unreferenced vertices");
179 
180  return mesh;
181 }
Array of compressed 3D normals (single index)
static cloudViewer::VerticesIndexes GetOrderedTriangle(int vidx0, int vidx1, int vidx2)
Definition: ecvMesh.h:92
static std::shared_ptr< ccMesh > CreateFromPointCloudAlphaShape(const ccPointCloud &pcd, double alpha, std::shared_ptr< cloudViewer::geometry::TetraMesh > tetra_mesh=nullptr, std::vector< size_t > *pt_map=nullptr)
Alpha shapes are a generalization of the convex hull. With decreasing alpha value the shape schrinks ...
virtual void setLocked(bool state)
Sets the "enabled" property.
Definition: ecvObject.h:117
virtual void setEnabled(bool state)
Sets the "enabled" property.
Definition: ecvObject.h:102
A 3D cloud and its associated features (color, normals, scalar fields, etc.)
bool resizeTheNormsTable()
Resizes the compressed normals array.
bool hasNormals() const override
Returns whether normals are enabled or not.
bool resizeTheRGBTable(bool fillWithWhite=false)
Resizes the RGB colors array.
bool hasColors() const override
Returns whether colors are enabled or not.
void setPointColor(size_t pointIndex, const ecvColor::Rgb &col)
Sets a particular point color.
void setPointNormal(size_t pointIndex, const CCVector3 &N)
Sets a particular point normal (shortcut)
const CCVector3 & getPointNormal(unsigned pointIndex) const override
Returns normal corresponding to a given point.
void shrinkToFit()
Removes unused capacity.
const ecvColor::Rgb & getPointColor(unsigned pointIndex) const override
Returns color corresponding to a given point.
std::vector< CCVector3 > & getPoints()
void addPoints(const std::vector< CCVector3 > &points)
static std::tuple< std::shared_ptr< TetraMesh >, std::vector< size_t > > ComputeDelaunayTetrahedralization(const std::vector< Eigen::Vector3d > &points)
Definition: ecvQhull.cpp:133
double normals[3]
#define LogError(...)
Definition: Logging.h:60
#define LogDebug(...)
Definition: Logging.h:90
a[190]
Eigen::Matrix< Index, 3, 1 > Vector3i
Definition: knncpp.h:30