10 #include <Eigen/Dense>
13 #include <unordered_map>
14 #include <unordered_set>
22 int number_of_iterations)
const {
23 if (hasTriangleUvs()) {
25 "[SubdivideMidpoint] This mesh contains triangle uvs that are "
26 "not handled in this function");
32 "[ccMesh::SimplifyVertexClustering] mesh"
33 "should set associated cloud before using!");
41 auto mesh = std::make_shared<ccMesh>(baseVertices);
42 mesh->addChild(baseVertices);
43 mesh->merge(
this,
false);
54 int vidx0,
int vidx1) {
55 size_t min =
static_cast<size_t>(std::min(vidx0, vidx1));
56 size_t max =
static_cast<size_t>(std::max(vidx0, vidx1));
58 if (new_verts.count(edge) == 0) {
63 if (has_vert_normal) {
73 int vidx01 = int(baseVertices->
size()) - 1;
74 new_verts[edge] = vidx01;
77 return new_verts[edge];
81 for (
int iter = 0; iter < number_of_iterations; ++iter) {
85 std::vector<Eigen::Vector3i> new_triangles(4 * mesh->size());
86 for (
size_t tidx = 0; tidx < mesh->size(); ++tidx) {
87 const auto& triangle = mesh->getTriangle(tidx);
88 int vidx0 = triangle(0);
89 int vidx1 = triangle(1);
90 int vidx2 = triangle(2);
91 int vidx01 = SubdivideEdge(new_verts, vidx0, vidx1);
92 int vidx12 = SubdivideEdge(new_verts, vidx1, vidx2);
93 int vidx20 = SubdivideEdge(new_verts, vidx2, vidx0);
94 new_triangles[tidx * 4 + 0] =
96 new_triangles[tidx * 4 + 1] =
98 new_triangles[tidx * 4 + 2] =
100 new_triangles[tidx * 4 + 3] =
103 mesh->setTriangles(new_triangles);
106 if (hasTriNormals()) {
107 mesh->ComputeTriangleNormals();
114 if (hasTriangleUvs()) {
116 "[SubdivideLoop] This mesh contains triangle uvs that are not "
117 "handled in this function");
122 typedef std::unordered_map<Eigen::Vector2i, std::unordered_set<int>,
125 typedef std::vector<std::unordered_set<int>> VertexNeighbours;
130 "[ccMesh::SimplifyVertexClustering] mesh"
131 "should set associated cloud before using!");
135 bool has_vert_color = cloud->
hasColors();
137 auto UpdateVertex = [&](
int vidx,
const std::shared_ptr<ccMesh>& old_mesh,
138 std::shared_ptr<ccMesh>& new_mesh,
139 const std::unordered_set<int>& nbs,
140 const EdgeTrianglesMap& edge_to_triangles) {
142 std::unordered_set<int> boundary_nbs;
145 if (edge_to_triangles.at(edge).size() == 1) {
146 boundary_nbs.insert(nb);
151 if (boundary_nbs.size() > 2) {
153 "[SubdivideLoop] boundary edge with > 2 neighbours, maybe "
154 "mesh is not manifold.");
158 if (boundary_nbs.size() >= 2) {
160 alpha = 1. - boundary_nbs.size() * beta;
161 }
else if (nbs.size() == 3) {
163 alpha = 1. - nbs.size() * beta;
165 beta = 3. / (8. * nbs.size());
166 alpha = 1. - nbs.size() * beta;
173 "[ccMesh::SimplifyVertexClustering] mesh"
174 "should set associated cloud before using!");
180 "[ccMesh::SimplifyVertexClustering] mesh"
181 "should set associated cloud before using!");
185 static_cast<unsigned>(vidx),
186 *oldVertice->
getPoint(
static_cast<unsigned>(vidx)) * alpha);
187 if (has_vert_normal) {
189 static_cast<unsigned>(vidx),
192 static_cast<unsigned>(vidx)));
194 if (has_vert_color) {
196 static_cast<unsigned>(vidx),
198 static_cast<unsigned>(vidx)));
201 auto Update = [&](
int nb) {
203 *p += *oldVertice->
getPoint(
static_cast<unsigned>(nb)) * beta;
204 if (has_vert_normal) {
206 static_cast<unsigned>(vidx),
208 static_cast<unsigned>(vidx)) +
211 static_cast<unsigned>(nb)));
213 if (has_vert_color) {
215 static_cast<unsigned>(vidx),
218 static_cast<unsigned>(nb)));
222 if (boundary_nbs.size() >= 2) {
223 for (
int nb : boundary_nbs) {
233 auto SubdivideEdge = [&](
int vidx0,
int vidx1,
234 const std::shared_ptr<ccMesh>& old_mesh,
235 std::shared_ptr<ccMesh>& new_mesh,
236 EdgeNewVertMap& new_verts,
237 const EdgeTrianglesMap& edge_to_triangles) {
244 "[ccMesh::SimplifyVertexClustering] mesh"
245 "should set associated cloud before using!");
251 "[ccMesh::SimplifyVertexClustering] mesh"
252 "should set associated cloud before using!");
255 if (new_verts.count(edge) == 0) {
256 Eigen::Vector3d new_vert =
259 Eigen::Vector3d new_normal;
260 if (has_vert_normal) {
265 Eigen::Vector3d new_color;
266 if (has_vert_color) {
272 const auto& edge_triangles = edge_to_triangles.at(edge);
273 if (edge_triangles.size() < 2) {
275 if (has_vert_normal) {
278 if (has_vert_color) {
283 if (has_vert_normal) {
284 new_normal *= 3. / 8.;
286 if (has_vert_color) {
287 new_color *= 3. / 8.;
289 size_t n_adjacent_trias = edge_triangles.size();
290 double scale = 1. / (4. * n_adjacent_trias);
291 for (
int tidx : edge_triangles) {
293 old_mesh->getTriangle(
static_cast<size_t>(tidx));
295 (tria(0) != vidx0 && tria(0) != vidx1)
297 : ((tria(1) != vidx0 && tria(1) != vidx1)
301 static_cast<size_t>(vidx2));
302 if (has_vert_normal) {
305 static_cast<size_t>(vidx2));
307 if (has_vert_color) {
310 static_cast<size_t>(vidx2));
315 int vidx01 = int(oldVertice->
size() + new_verts.size());
317 newVertice->
setPoint(
static_cast<size_t>(vidx01), new_vert);
318 if (has_vert_normal) {
322 if (has_vert_color) {
327 new_verts[edge] = vidx01;
330 int vidx01 = new_verts[edge];
335 auto InsertTriangle = [&](
int tidx,
int vidx0,
int vidx1,
int vidx2,
336 std::shared_ptr<ccMesh>& mesh,
337 EdgeTrianglesMap& edge_to_triangles,
338 VertexNeighbours& vertex_neighbours) {
339 mesh->setTriangle(
static_cast<size_t>(tidx),
344 vertex_neighbours[vidx0].insert(vidx1);
345 vertex_neighbours[vidx0].insert(vidx2);
346 vertex_neighbours[vidx1].insert(vidx0);
347 vertex_neighbours[vidx1].insert(vidx2);
348 vertex_neighbours[vidx2].insert(vidx0);
349 vertex_neighbours[vidx2].insert(vidx1);
352 EdgeTrianglesMap edge_to_triangles;
353 VertexNeighbours vertex_neighbours(cloud->
size());
354 for (
size_t tidx = 0; tidx <
size(); ++tidx) {
355 const auto& tria = getTriangle(tidx);
357 edge_to_triangles[e0].insert(
int(tidx));
359 edge_to_triangles[e1].insert(
int(tidx));
361 edge_to_triangles[
e2].insert(
int(tidx));
363 if (edge_to_triangles[e0].
size() > 2 ||
364 edge_to_triangles[e1].
size() > 2 ||
365 edge_to_triangles[
e2].
size() > 2) {
369 vertex_neighbours[tria(0)].insert(tria(1));
370 vertex_neighbours[tria(0)].insert(tria(2));
371 vertex_neighbours[tria(1)].insert(tria(0));
372 vertex_neighbours[tria(1)].insert(tria(2));
373 vertex_neighbours[tria(2)].insert(tria(0));
374 vertex_neighbours[tria(2)].insert(tria(1));
382 auto old_mesh = std::make_shared<ccMesh>(oldVertices);
383 old_mesh->addChild(oldVertices);
384 old_mesh->merge(
this,
false);
386 for (
int iter = 0; iter < number_of_iterations; ++iter) {
387 size_t n_new_vertices =
388 old_mesh->getVerticeSize() + edge_to_triangles.size();
389 size_t n_new_triangles = 4 * old_mesh->size();
396 auto new_mesh = std::make_shared<ccMesh>(newVertices);
397 new_mesh->addChild(newVertices);
399 newVertices->
resize(
static_cast<unsigned>(n_new_vertices));
400 if (has_vert_normal) {
403 if (has_vert_color) {
406 new_mesh->resize(n_new_triangles);
408 EdgeNewVertMap new_verts;
409 EdgeTrianglesMap new_edge_to_triangles;
410 VertexNeighbours new_vertex_neighbours(n_new_vertices);
412 for (
size_t vidx = 0; vidx < old_mesh->getVerticeSize(); ++vidx) {
413 UpdateVertex(
int(vidx), old_mesh, new_mesh, vertex_neighbours[vidx],
417 for (
size_t tidx = 0; tidx < old_mesh->size(); ++tidx) {
418 const auto& triangle = old_mesh->getTriangle(tidx);
419 int vidx0 = triangle(0);
420 int vidx1 = triangle(1);
421 int vidx2 = triangle(2);
423 int vidx01 = SubdivideEdge(vidx0, vidx1, old_mesh, new_mesh,
424 new_verts, edge_to_triangles);
425 int vidx12 = SubdivideEdge(vidx1, vidx2, old_mesh, new_mesh,
426 new_verts, edge_to_triangles);
427 int vidx20 = SubdivideEdge(vidx2, vidx0, old_mesh, new_mesh,
428 new_verts, edge_to_triangles);
430 InsertTriangle(
int(tidx) * 4 + 0, vidx0, vidx01, vidx20, new_mesh,
431 new_edge_to_triangles, new_vertex_neighbours);
432 InsertTriangle(
int(tidx) * 4 + 1, vidx01, vidx1, vidx12, new_mesh,
433 new_edge_to_triangles, new_vertex_neighbours);
434 InsertTriangle(
int(tidx) * 4 + 2, vidx12, vidx2, vidx20, new_mesh,
435 new_edge_to_triangles, new_vertex_neighbours);
436 InsertTriangle(
int(tidx) * 4 + 3, vidx01, vidx12, vidx20, new_mesh,
437 new_edge_to_triangles, new_vertex_neighbours);
440 old_mesh = std::move(new_mesh);
441 edge_to_triangles = std::move(new_edge_to_triangles);
442 vertex_neighbours = std::move(new_vertex_neighbours);
445 if (hasTriNormals()) {
446 old_mesh->ComputeTriangleNormals();
float PointCoordinateType
Type of the coordinates of a (N-D) point.
static ccPointCloud * ToPointCloud(ccHObject *obj, bool *isLockedVertices=nullptr)
Converts current object to 'equivalent' ccPointCloud.
std::shared_ptr< ccMesh > SubdivideLoop(int number_of_iterations) const
std::shared_ptr< ccMesh > SubdivideMidpoint(int number_of_iterations) const
virtual void setLocked(bool state)
Sets the "enabled" property.
virtual void setEnabled(bool state)
Sets the "enabled" property.
A 3D cloud and its associated features (color, normals, scalar fields, etc.)
void addEigenNorm(const Eigen::Vector3d &N)
void setEigenColor(size_t index, const Eigen::Vector3d &color)
bool resizeTheNormsTable()
Resizes the compressed normals array.
void addEigenColor(const Eigen::Vector3d &color)
void setEigenNormal(size_t index, const Eigen::Vector3d &normal)
Eigen::Vector3d getEigenNormal(size_t index) const
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.
bool resize(unsigned numberOfPoints) override
Resizes all the active features arrays.
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.
Eigen::Vector3d getEigenColor(size_t index) const
void addEigenPoint(const Eigen::Vector3d &point)
CCVector3 * getPointPtr(size_t index)
unsigned size() const override
Eigen::Vector3d getEigenPoint(size_t index) const
void setPoint(size_t index, const CCVector3 &P)
const CCVector3 * getPoint(unsigned index) const override
static Edge< T > GetOrderedEdge(T vidx0, T vidx1)
brief Helper function to get an edge with ordered vertex indices.
Generic file read and write utility for python interface.
Eigen::Matrix< Index, 3, 1 > Vector3i
Eigen::Matrix< Index, 2, 1 > Vector2i