Skip to content

Commit 911eb38

Browse files
committed
[algorithms] export triangulated face indices to buffer
1 parent c365148 commit 911eb38

File tree

5 files changed

+221
-32
lines changed

5 files changed

+221
-32
lines changed

examples/core/007-mesh-conversion/main.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,5 +56,12 @@ int main()
5656

5757
vcl::save(m, VCLIB_RESULTS_PATH "/cube_from_poly.ply", s);
5858

59+
pm = vcl::loadObj<vcl::PolyMesh>(VCLIB_EXAMPLE_MESHES_PATH
60+
"/rhombicosidodecahedron.obj");
61+
62+
m.importFrom(pm);
63+
64+
vcl::save(m, VCLIB_RESULTS_PATH "/tri_rhombicosidodecahedron.ply", s);
65+
5966
return 0;
6067
}

tests/core/019-export-matrix/main.cpp

Lines changed: 62 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -107,8 +107,7 @@ void testCoordsMatrix(const auto& tm)
107107
REQUIRE(verts.rows() == tm.vertexNumber());
108108
REQUIRE(verts.cols() == 3);
109109

110-
vcl::uint i = 0;
111-
for (const auto& c : tm.vertices() | vcl::views::coords) {
110+
for (vcl::uint i = 0; const auto& c : tm.vertices() | vcl::views::coords) {
112111
REQUIRE(verts(i, 0) == c.x());
113112
REQUIRE(verts(i, 1) == c.y());
114113
REQUIRE(verts(i, 2) == c.z());
@@ -124,8 +123,7 @@ void testTrianglesMatrix(const auto& tm)
124123
REQUIRE(tris.rows() == tm.faceNumber());
125124
REQUIRE(tris.cols() == 3);
126125

127-
vcl::uint i = 0;
128-
for (const auto& f : tm.faces()) {
126+
for (vcl::uint i = 0; const auto& f : tm.faces()) {
129127
for (vcl::uint j = 0; j < 3; ++j) {
130128
REQUIRE(tris(i, j) == f.vertexIndex(j));
131129
}
@@ -140,8 +138,7 @@ void testFaceSizesVector(const auto& pm)
140138

141139
REQUIRE(sizes.size() == pm.faceNumber());
142140

143-
vcl::uint i = 0;
144-
for (const auto& f : pm.faces()) {
141+
for (vcl::uint i = 0; const auto& f : pm.faces()) {
145142
REQUIRE(sizes[i] == f.vertexNumber());
146143
++i;
147144
}
@@ -155,8 +152,7 @@ void testFaceVector(const auto& pm)
155152
vcl::uint nIndices = countPerFaceVertexReferences(pm);
156153
REQUIRE(faces.size() == nIndices);
157154

158-
vcl::uint i = 0;
159-
for (const auto& f : pm.faces()) {
155+
for (vcl::uint i = 0; const auto& f : pm.faces()) {
160156
for (const auto* v : f.vertices()) {
161157
REQUIRE(faces[i] == pm.index(v));
162158
++i;
@@ -172,8 +168,7 @@ void testFaceMatrix(const auto& pm)
172168
REQUIRE(faces.rows() == pm.faceNumber());
173169
REQUIRE(faces.cols() == vcl::largestFaceSize(pm));
174170

175-
vcl::uint i = 0;
176-
for (const auto& f : pm.faces()) {
171+
for (vcl::uint i = 0; const auto& f : pm.faces()) {
177172
vcl::uint j = 0;
178173
for (j = 0; j < f.vertexNumber(); ++j) {
179174
REQUIRE(faces(i, j) == f.vertexIndex(j));
@@ -186,15 +181,37 @@ void testFaceMatrix(const auto& pm)
186181
}
187182
}
188183

184+
template<typename MatrixType>
185+
void testTriangulatedFaceMatrix(const auto& pm)
186+
{
187+
vcl::TriPolyIndexBiMap indexMap;
188+
auto tris = vcl::triangulatedFaceIndicesMatrix<MatrixType>(pm, indexMap);
189+
190+
vcl::uint tNumber = countTriangulatedTriangles(pm);
191+
192+
REQUIRE(tris.rows() == tNumber);
193+
REQUIRE(tris.cols() == 3);
194+
195+
for (vcl::uint i = 0; i < 3; ++i) {
196+
// polygon associated to ith triangle
197+
vcl::uint fIdx = indexMap.polygon(i);
198+
const auto& f = pm.face(fIdx);
199+
200+
for (vcl::uint j = 0; j < 3; ++j) {
201+
REQUIRE(f.containsVertex(tris(i, j)));
202+
}
203+
++i;
204+
}
205+
}
206+
189207
template<typename VectorType>
190208
void testVertexSelectionVector(const auto& tm)
191209
{
192210
auto sel = vcl::vertexSelectionVector<VectorType>(tm);
193211

194212
REQUIRE(sel.size() == tm.vertexNumber());
195213

196-
vcl::uint i = 0;
197-
for (const auto& v : tm.vertices()) {
214+
for (vcl::uint i = 0; const auto& v : tm.vertices()) {
198215
REQUIRE((bool) sel[i] == v.selected());
199216
++i;
200217
}
@@ -207,8 +224,7 @@ void testFaceSelectionVector(const auto& tm)
207224

208225
REQUIRE(sel.size() == tm.faceNumber());
209226

210-
vcl::uint i = 0;
211-
for (const auto& f : tm.faces()) {
227+
for (vcl::uint i = 0; const auto& f : tm.faces()) {
212228
REQUIRE((bool) sel[i] == f.selected());
213229
++i;
214230
}
@@ -222,8 +238,7 @@ void testVertNormalsMatrix(const auto& tm)
222238
REQUIRE(vertNormals.rows() == tm.vertexNumber());
223239
REQUIRE(vertNormals.cols() == 3);
224240

225-
vcl::uint i = 0;
226-
for (const auto& n : tm.vertices() | vcl::views::normals) {
241+
for (vcl::uint i = 0; const auto& n : tm.vertices() | vcl::views::normals) {
227242
REQUIRE(vertNormals(i, 0) == n.x());
228243
REQUIRE(vertNormals(i, 1) == n.y());
229244
REQUIRE(vertNormals(i, 2) == n.z());
@@ -239,8 +254,7 @@ void testFaceNormalsMatrix(const auto& tm)
239254
REQUIRE(faceNormals.rows() == tm.faceNumber());
240255
REQUIRE(faceNormals.cols() == 3);
241256

242-
vcl::uint i = 0;
243-
for (const auto& n : tm.faces() | vcl::views::normals) {
257+
for (vcl::uint i = 0; const auto& n : tm.faces() | vcl::views::normals) {
244258
REQUIRE(faceNormals(i, 0) == n.x());
245259
REQUIRE(faceNormals(i, 1) == n.y());
246260
REQUIRE(faceNormals(i, 2) == n.z());
@@ -256,8 +270,7 @@ void testVertColorsMatrix(const auto& tm)
256270
REQUIRE(vertColors.rows() == tm.vertexNumber());
257271
REQUIRE(vertColors.cols() == 4);
258272

259-
vcl::uint i = 0;
260-
for (const auto& c : tm.vertices() | vcl::views::colors) {
273+
for (vcl::uint i = 0; const auto& c : tm.vertices() | vcl::views::colors) {
261274
REQUIRE(vertColors(i, 0) == c.red());
262275
REQUIRE(vertColors(i, 1) == c.green());
263276
REQUIRE(vertColors(i, 2) == c.blue());
@@ -274,8 +287,7 @@ void testVertColorsVector(const auto& tm)
274287

275288
REQUIRE(vertColors.size() == tm.vertexNumber());
276289

277-
vcl::uint i = 0;
278-
for (const auto& c : tm.vertices() | vcl::views::colors) {
290+
for (vcl::uint i = 0; const auto& c : tm.vertices() | vcl::views::colors) {
279291
REQUIRE(vertColors[i] == c.rgba());
280292
++i;
281293
}
@@ -289,8 +301,7 @@ void testFaceColorsMatrix(const auto& tm)
289301
REQUIRE(faceColors.rows() == tm.faceNumber());
290302
REQUIRE(faceColors.cols() == 4);
291303

292-
vcl::uint i = 0;
293-
for (const auto& c : tm.faces() | vcl::views::colors) {
304+
for (vcl::uint i = 0; const auto& c : tm.faces() | vcl::views::colors) {
294305
REQUIRE(faceColors(i, 0) == c.red());
295306
REQUIRE(faceColors(i, 1) == c.green());
296307
REQUIRE(faceColors(i, 2) == c.blue());
@@ -307,8 +318,7 @@ void testFaceColorsVector(const auto& tm)
307318

308319
REQUIRE(faceColors.size() == tm.faceNumber());
309320

310-
vcl::uint i = 0;
311-
for (const auto& c : tm.faces() | vcl::views::colors) {
321+
for (vcl::uint i = 0; const auto& c : tm.faces() | vcl::views::colors) {
312322
REQUIRE(faceColors[i] == c.rgba());
313323
++i;
314324
}
@@ -321,8 +331,7 @@ void testVertexQualityVector(const auto& tm)
321331

322332
REQUIRE(qual.size() == tm.vertexNumber());
323333

324-
vcl::uint i = 0;
325-
for (const auto& v : tm.vertices()) {
334+
for (vcl::uint i = 0; const auto& v : tm.vertices()) {
326335
REQUIRE(qual[i] == v.quality());
327336
++i;
328337
}
@@ -335,8 +344,7 @@ void testFaceQualityVector(const auto& tm)
335344

336345
REQUIRE(qual.size() == tm.faceNumber());
337346

338-
vcl::uint i = 0;
339-
for (const auto& f : tm.faces()) {
347+
for (vcl::uint i = 0; const auto& f : tm.faces()) {
340348
REQUIRE(qual[i] == f.quality());
341349
++i;
342350
}
@@ -475,6 +483,30 @@ TEMPLATE_TEST_CASE(
475483
}
476484
}
477485

486+
SECTION("Triangulated Faces...")
487+
{
488+
SECTION("Eigen Row Major")
489+
{
490+
testTriangulatedFaceMatrix<EigenRowMatrix<vcl::uint>>(pm);
491+
}
492+
SECTION("Eigen 3 Row Major")
493+
{
494+
testTriangulatedFaceMatrix<Eigen3RowMatrix<vcl::uint>>(pm);
495+
}
496+
SECTION("Eigen Col Major")
497+
{
498+
testTriangulatedFaceMatrix<EigenColMatrix<vcl::uint>>(pm);
499+
}
500+
SECTION("Eigen 3 Col Major")
501+
{
502+
testTriangulatedFaceMatrix<Eigen3ColMatrix<vcl::uint>>(pm);
503+
}
504+
SECTION("vcl::Array2")
505+
{
506+
testTriangulatedFaceMatrix<vcl::Array2<vcl::uint>>(pm);
507+
}
508+
}
509+
478510
SECTION("Vertex selection...")
479511
{
480512
randomSelection<vcl::ElemId::VERTEX>(tm);

vclib/core/include/vclib/algorithms/mesh/import_export/export_buffer.h

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,19 @@
2323
#ifndef VCL_ALGORITHMS_MESH_IMPORT_EXPORT_EXPORT_BUFFER_H
2424
#define VCL_ALGORITHMS_MESH_IMPORT_EXPORT_EXPORT_BUFFER_H
2525

26+
#include <vclib/algorithms/core/polygon/ear_cut.h>
2627
#include <vclib/mesh/requirements.h>
28+
#include <vclib/space/complex/tri_poly_index_bimap.h>
2729
#include <vclib/views/mesh.h>
2830

2931
namespace vcl {
3032

33+
namespace detail {
34+
35+
inline static TriPolyIndexBiMap indexMap;
36+
37+
} // namespace detail
38+
3139
/**
3240
* @brief Export the vertex coordinates of a mesh to a buffer.
3341
*
@@ -266,6 +274,100 @@ void faceIndicesToBuffer(
266274
}
267275
}
268276

277+
/**
278+
* @brief Export into a buffer the vertex indices for each triangle computed
279+
* by triangulating the faces of a Mesh.
280+
*
281+
* This function exports the vertex indices of the triangles computed by
282+
* triangulating the faces of a mesh to a buffer. Indices are stored following
283+
* the order the faces appear in the mesh. The buffer must be preallocated with
284+
* the correct size (number of *resulting triangles* times 3).
285+
*
286+
* You can use the function @ref vcl::countTriangulatedTriangles to get the
287+
* number of resulting triangles and allocate the buffer accordingly:
288+
*
289+
* @code{.cpp}
290+
* uint numTris = vcl::countTriangulatedTriangles(myMesh);
291+
* Eigen::MatrixXi triIndices(numTris, 3);
292+
* vcl::TriPolyIndexBiMap indexMap;
293+
* vcl::triangulatedFaceIndicesToBuffer(
294+
* myMesh, triIndices.data(), indexMap, MatrixStorageType::COLUMN_MAJOR,
295+
* numTris);
296+
* @endcode
297+
*
298+
* The input indexMap is used to map each triangle to the face index. If the
299+
* storage of the buffer is column major, the number of resulting triangles
300+
* (that should be known when calling this function) should be given as input.
301+
* If the number of resulting triangles is not given, the function will compute
302+
* it again.
303+
*
304+
* @note This function does not guarantee that the vertex indices stored in the
305+
* buffer correspond to the vertex indices of the mesh. This scenario is
306+
* possible when the mesh has deleted vertices. To be sure to have a direct
307+
* correspondence, compact the vertex container before calling this function.
308+
*
309+
* @param[in] mesh: input mesh
310+
* @param[out] buffer: preallocated buffer
311+
* @param[out] indexMap: map from triangle index to face index
312+
* @param[in] storage: storage type of the matrix (row or column major)
313+
* @param[in] numTriangles: number of resulting triangles (necessary only if
314+
* the storage is column major)
315+
*/
316+
template<FaceMeshConcept MeshType>
317+
void triangulatedFaceIndicesToBuffer(
318+
const MeshType& mesh,
319+
auto* buffer,
320+
TriPolyIndexBiMap& indexMap = detail::indexMap,
321+
MatrixStorageType storage = MatrixStorageType::ROW_MAJOR,
322+
uint numTriangles = UINT_NULL)
323+
{
324+
// there will be at least a triangle for each polygon
325+
indexMap.clear();
326+
indexMap.reserve(mesh.faceNumber(), mesh.faceContainerSize());
327+
328+
if constexpr (TriangleMeshConcept<MeshType>) {
329+
// construct the indexMap, which maps each triangle to the face index
330+
for (uint t = 0; const auto& f : mesh.faces()) {
331+
// map the ith triangle to the f face
332+
indexMap.insert(t, f.index());
333+
++t;
334+
}
335+
336+
return triangleIndicesToBuffer(mesh, buffer, storage);
337+
}
338+
else {
339+
// if the user did not give the number of triangles, and the buffer
340+
// storage is column major, we need to compute the number of resulting
341+
// triangles
342+
if (numTriangles == UINT_NULL &&
343+
storage == MatrixStorageType::COLUMN_MAJOR &&
344+
mesh.faceNumber() > 0) {
345+
numTriangles = countTriangulatedTriangles(mesh);
346+
}
347+
for (uint t = 0; const auto& f : mesh.faces()) {
348+
std::vector<uint> vind = vcl::earCut(f);
349+
350+
// for each triangle of the triangulation (t is the triangle index)
351+
for (uint vi = 0; vi < vind.size(); vi += 3) {
352+
// map the t-th triangle to the f polygonal face
353+
indexMap.insert(t, f.index());
354+
355+
if (storage == MatrixStorageType::ROW_MAJOR) {
356+
buffer[t * 3 + 0] = f.vertexIndex(vind[vi + 0]);
357+
buffer[t * 3 + 1] = f.vertexIndex(vind[vi + 1]);
358+
buffer[t * 3 + 2] = f.vertexIndex(vind[vi + 2]);
359+
}
360+
else {
361+
buffer[0 * numTriangles + t] = f.vertexIndex(vind[vi + 0]);
362+
buffer[1 * numTriangles + t] = f.vertexIndex(vind[vi + 1]);
363+
buffer[2 * numTriangles + t] = f.vertexIndex(vind[vi + 2]);
364+
}
365+
++t;
366+
}
367+
}
368+
}
369+
}
370+
269371
/**
270372
* @brief Export into a buffer the vertex indices for each edge of a Mesh.
271373
*

0 commit comments

Comments
 (0)