From a480ab95fc290a001c7cdc5595a1053d0f7a5d3f Mon Sep 17 00:00:00 2001 From: Andrea Maggiordomo Date: Tue, 25 Oct 2022 11:28:08 +0200 Subject: [PATCH 01/10] Switched to io::Precision for writing obj values, refactored io::Precision to allow users to specify the desired decimal precision (#205) --- wrap/io_trimesh/export_obj.h | 32 ++++++++++++++++-------------- wrap/io_trimesh/precision.h | 38 ++++++++++++++++++++++-------------- 2 files changed, 40 insertions(+), 30 deletions(-) diff --git a/wrap/io_trimesh/export_obj.h b/wrap/io_trimesh/export_obj.h index ce0626fe3..4b482593f 100644 --- a/wrap/io_trimesh/export_obj.h +++ b/wrap/io_trimesh/export_obj.h @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -65,7 +66,7 @@ class ExporterOBJ E_NO_VERTICES, // 6 E_NOTFACESVALID, // 7 E_NO_VALID_MATERIAL, // 8 - E_STREAMERROR // 9 + E_STREAMERROR // 9 }; /* @@ -84,7 +85,7 @@ class ExporterOBJ "Vertices not valid", // 6 "Faces not valid", // 7 "The mesh has not a attribute containing the vector of materials", // 8 - "Output Stream Error" //9 + "Output Stream Error" //9 }; if(error>9 || error<0) return "Unknown error"; @@ -126,6 +127,7 @@ class ExporterOBJ */ static int Save(SaveMeshType &m, const char * filename, int mask, bool useMaterialAttribute ,CallBackPos *cb=0) { + const int DGT = vcg::tri::io::Precision::digits(); // texture coord and color: in obj we cannot save BOTH per vertex and per wedge information. We default on wedge if (mask & vcg::tri::io::Mask::IOM_WEDGTEXCOORD && mask & vcg::tri::io::Mask::IOM_VERTTEXCOORD ) { @@ -176,22 +178,22 @@ class ExporterOBJ { if(AddNewNormalVertex(NormalVertex,(*vi).N(),curNormalIndex)) { - fprintf(fp,"vn %f %f %f\n",(*vi).N()[0],(*vi).N()[1],(*vi).N()[2]); + fprintf(fp,"vn %.*f %.*f %.*f\n", DGT, (*vi).N()[0], DGT, (*vi).N()[1], DGT, (*vi).N()[2]); curNormalIndex++; } } if (mask & Mask::IOM_VERTNORMAL ) { - fprintf(fp,"vn %f %f %f\n",(*vi).N()[0],(*vi).N()[1],(*vi).N()[2]); + fprintf(fp,"vn %.*f %.*f %.*f\n", DGT, (*vi).N()[0], DGT, (*vi).N()[1], DGT, (*vi).N()[2]); } if (mask & Mask::IOM_VERTTEXCOORD ) { - fprintf(fp,"vt %f %f\n",(*vi).T().P()[0],(*vi).T().P()[1]); + fprintf(fp,"vt %.*f %.*f\n", DGT, (*vi).T().P()[0], DGT, (*vi).T().P()[1]); } - fprintf(fp,"v %f %f %f",(*vi).P()[0],(*vi).P()[1],(*vi).P()[2]); + fprintf(fp,"v %.*f %.*f %.*f", DGT, (*vi).P()[0], DGT, (*vi).P()[1], DGT, (*vi).P()[2]); if(mask & Mask::IOM_VERTCOLOR) // the socially accepted extension to the obj format. - fprintf(fp," %f %f %f",double((*vi).C()[0])/255.,double((*vi).C()[1])/255.,double((*vi).C()[2])/255.); + fprintf(fp," %f %f %f", double((*vi).C()[0])/255., double((*vi).C()[1])/255., double((*vi).C()[2])/255.); fprintf(fp,"\n"); if (cb !=NULL) @@ -234,7 +236,7 @@ class ExporterOBJ { if(AddNewTextureCoord(CoordIndexTexture,(*fi).WT(k),curTexCoordIndex)) { - fprintf(fp,"vt %f %f\n",(*fi).WT(k).u(),(*fi).WT(k).v()); + fprintf(fp,"vt %.*f %.*f\n", DGT, (*fi).WT(k).u(), DGT, (*fi).WT(k).v()); curTexCoordIndex++; //ncreases the value number to be associated to the Texture } } @@ -289,13 +291,13 @@ class ExporterOBJ else errCode = WriteMaterials(materialVec, filename,cb); } - int result = E_NOERROR; - if (errCode != E_NOERROR) - result = errCode; - else if (ferror(fp)) - result = E_STREAMERROR; - fclose(fp); - return result; + int result = E_NOERROR; + if (errCode != E_NOERROR) + result = errCode; + else if (ferror(fp)) + result = E_STREAMERROR; + fclose(fp); + return result; } /* diff --git a/wrap/io_trimesh/precision.h b/wrap/io_trimesh/precision.h index a5b3bdb11..a363f18a9 100644 --- a/wrap/io_trimesh/precision.h +++ b/wrap/io_trimesh/precision.h @@ -8,29 +8,37 @@ namespace vcg namespace io { template - struct Precision + class Precision { + static int decimalPrecision; // the desired decimal precision + public: static int digits() {return 0;} - static const char* typeName() {return "";} + static void setDigits(int digits) { decimalPrecision = digits; } + static const char* typeName() {return "";} }; - + + template + int Precision::decimalPrecision = 0; + + // Precision specializations with reasonable defaults + + // Precision specializations template<> - struct Precision - { - static int digits() {return 7;} - static const char* typeName() {return "float";} + int Precision::digits() { return decimalPrecision <= 0 ? 7 : decimalPrecision; } - }; - template<> - struct Precision - { - static int digits() {return 16;} - static const char* typeName() {return "double";} - }; + const char* Precision::typeName() { return "float"; } + + // Precision specializations + template<> + int Precision::digits() { return decimalPrecision <= 0 ? 16 : decimalPrecision; } + + template<> + const char* Precision::typeName() { return "double"; } + } } } -#endif \ No newline at end of file +#endif From c2c782a2184ba04a9618b7ac6501856e1a008758 Mon Sep 17 00:00:00 2001 From: Andrea Maggiordomo Date: Tue, 25 Oct 2022 11:29:27 +0200 Subject: [PATCH 02/10] Colormaps (#204) Added alternative colormaps (sampled from Matplotlib) --- vcg/complex/algorithms/update/color.h | 20 +- vcg/space/colormap.h | 258 ++++++++++++++++++++++++++ 2 files changed, 269 insertions(+), 9 deletions(-) create mode 100644 vcg/space/colormap.h diff --git a/vcg/complex/algorithms/update/color.h b/vcg/complex/algorithms/update/color.h index b1c7f3a3f..e0ed06add 100644 --- a/vcg/complex/algorithms/update/color.h +++ b/vcg/complex/algorithms/update/color.h @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -220,7 +221,7 @@ class UpdateColor If no range of quality is passed it is automatically computed. */ - static void PerVertexQualityRamp(MeshType &m, ScalarType minq = 0., ScalarType maxq = 0.) + static void PerVertexQualityRamp(MeshType &m, ScalarType minq = 0., ScalarType maxq = 0., vcg::ColorMap cmap = vcg::ColorMap::RGB) { RequirePerVertexQuality(m); RequirePerVertexColor(m); @@ -232,8 +233,9 @@ class UpdateColor maxq=minmax.second; } for(VertexIterator vi=m.vert.begin();vi!=m.vert.end();++vi) - if(!(*vi).IsD()) - (*vi).C().SetColorRamp(minq,maxq,(*vi).Q()); + if(!(*vi).IsD()) { + (*vi).C() = vcg::GetColorMapping((*vi).Q(), minq, maxq, cmap); + } } @@ -261,7 +263,7 @@ class UpdateColor If no range of quality is passed it is automatically computed. */ - static void PerTetraQualityRamp(MeshType &m, ScalarType minq = 0., ScalarType maxq = 0., bool selected = false) + static void PerTetraQualityRamp(MeshType &m, ScalarType minq = 0., ScalarType maxq = 0., bool selected = false, vcg::ColorMap cmap = vcg::ColorMap::RGB) { RequirePerTetraColor(m); RequirePerTetraQuality(m); @@ -275,14 +277,14 @@ class UpdateColor ForEachTetra(m, [&] (TetraType & t){ if (!selected || t.IsS()) - t.C().SetColorRamp(minq, maxq, t.Q()); + t.C() = vcg::GetColorMapping(t.Q(), minq, maxq, cmap); }); } /*! \brief This function colores all the faces of a mesh with a hue color shade dependent on the quality. If no range of quality is passed it is automatically computed. */ - static void PerFaceQualityRamp(MeshType &m, ScalarType minq = 0, ScalarType maxq = 0, bool selected = false) + static void PerFaceQualityRamp(MeshType &m, ScalarType minq = 0, ScalarType maxq = 0, bool selected = false, vcg::ColorMap cmap = vcg::ColorMap::RGB) { RequirePerFaceColor(m); RequirePerFaceQuality(m); @@ -296,14 +298,14 @@ class UpdateColor for(FaceIterator fi = m.face.begin();fi != m.face.end(); ++fi) if(!(*fi).IsD()) if(!selected || (*fi).IsS()) - (*fi).C().SetColorRamp(minq, maxq, (*fi).Q()); + (*fi).C() = vcg::GetColorMapping((*fi).Q(), minq, maxq, cmap); } /*! \brief This function colores all the edges of a mesh with a hue color shade dependent on the quality. If no range of quality is passed it is automatically computed. */ - static void PerEdgeQualityRamp(MeshType &m, ScalarType minq = 0, ScalarType maxq = 0, bool selected = false) + static void PerEdgeQualityRamp(MeshType &m, ScalarType minq = 0, ScalarType maxq = 0, bool selected = false, vcg::ColorMap cmap = vcg::ColorMap::RGB) { RequirePerEdgeColor(m); RequirePerEdgeQuality(m); @@ -316,7 +318,7 @@ class UpdateColor } for(EdgeIterator ei=m.edge.begin();ei!=m.edge.end();++ei) if(!(*ei).IsD()) if(!selected || (*ei).IsS()) - (*ei).C().SetColorRamp(minq,maxq,(*ei).Q()); + (*ei).C() = vcg::GetColorMapping((*ei).Q(), minq, maxq, cmap); } /*! \brief This function colores all the vertices of a mesh with a gray shade dependent on the quality. diff --git a/vcg/space/colormap.h b/vcg/space/colormap.h new file mode 100644 index 000000000..b500dce85 --- /dev/null +++ b/vcg/space/colormap.h @@ -0,0 +1,258 @@ +#ifndef __VCGLIB_COLORMAP_H +#define __VCGLIB_COLORMAP_H + +#include +#include +#include + +// Colormaps sampled from Matplotlib +// https://matplotlib.org + +namespace vcg { + +enum ColorMap { + RGB = 0, + Viridis = 1, + Plasma = 2, + Cividis = 3, + Turbo = 4, + RdPu = 5, +}; + +static std::vector ColorMapEnums = { + RGB, + Viridis, + Plasma, + Cividis, + Turbo, + RdPu, +}; + +static std::map> colorMaps = { + { + ColorMap::Viridis, + { + vcg::Color4b(68, 1, 84, 255), + vcg::Color4b(70, 12, 95, 255), + vcg::Color4b(71, 24, 106, 255), + vcg::Color4b(72, 34, 115, 255), + vcg::Color4b(70, 45, 124, 255), + vcg::Color4b(68, 55, 129, 255), + vcg::Color4b(65, 65, 134, 255), + vcg::Color4b(61, 74, 137, 255), + vcg::Color4b(57, 84, 139, 255), + vcg::Color4b(53, 92, 140, 255), + vcg::Color4b(49, 100, 141, 255), + vcg::Color4b(46, 108, 142, 255), + vcg::Color4b(42, 117, 142, 255), + vcg::Color4b(39, 124, 142, 255), + vcg::Color4b(36, 132, 141, 255), + vcg::Color4b(34, 139, 141, 255), + vcg::Color4b(31, 148, 139, 255), + vcg::Color4b(30, 155, 137, 255), + vcg::Color4b(31, 163, 134, 255), + vcg::Color4b(36, 170, 130, 255), + vcg::Color4b(46, 178, 124, 255), + vcg::Color4b(57, 185, 118, 255), + vcg::Color4b(71, 192, 110, 255), + vcg::Color4b(87, 198, 101, 255), + vcg::Color4b(107, 205, 89, 255), + vcg::Color4b(126, 210, 78, 255), + vcg::Color4b(146, 215, 65, 255), + vcg::Color4b(167, 219, 51, 255), + vcg::Color4b(191, 223, 36, 255), + vcg::Color4b(212, 225, 26, 255), + vcg::Color4b(233, 228, 25, 255), + vcg::Color4b(253, 231, 36, 255), + } + }, + { + ColorMap::Plasma, + { + vcg::Color4b(12, 7, 134, 255), + vcg::Color4b(33, 5, 143, 255), + vcg::Color4b(49, 4, 150, 255), + vcg::Color4b(63, 3, 156, 255), + vcg::Color4b(78, 2, 161, 255), + vcg::Color4b(90, 0, 165, 255), + vcg::Color4b(103, 0, 167, 255), + vcg::Color4b(115, 0, 168, 255), + vcg::Color4b(129, 4, 167, 255), + vcg::Color4b(140, 10, 164, 255), + vcg::Color4b(151, 19, 160, 255), + vcg::Color4b(162, 28, 154, 255), + vcg::Color4b(173, 38, 146, 255), + vcg::Color4b(182, 47, 139, 255), + vcg::Color4b(190, 56, 131, 255), + vcg::Color4b(198, 65, 124, 255), + vcg::Color4b(207, 75, 116, 255), + vcg::Color4b(214, 85, 109, 255), + vcg::Color4b(220, 94, 102, 255), + vcg::Color4b(227, 103, 95, 255), + vcg::Color4b(233, 114, 87, 255), + vcg::Color4b(238, 124, 80, 255), + vcg::Color4b(243, 134, 73, 255), + vcg::Color4b(246, 145, 66, 255), + vcg::Color4b(250, 157, 58, 255), + vcg::Color4b(252, 169, 52, 255), + vcg::Color4b(253, 181, 45, 255), + vcg::Color4b(253, 193, 40, 255), + vcg::Color4b(251, 208, 36, 255), + vcg::Color4b(248, 221, 36, 255), + vcg::Color4b(244, 234, 38, 255), + vcg::Color4b(239, 248, 33, 255), + } + }, + { + ColorMap::Cividis, + { + vcg::Color4b(0, 34, 77, 255), + vcg::Color4b(0, 40, 91, 255), + vcg::Color4b(0, 45, 105, 255), + vcg::Color4b(4, 50, 112, 255), + vcg::Color4b(28, 56, 110, 255), + vcg::Color4b(40, 62, 109, 255), + vcg::Color4b(50, 68, 108, 255), + vcg::Color4b(59, 73, 107, 255), + vcg::Color4b(69, 79, 107, 255), + vcg::Color4b(77, 85, 108, 255), + vcg::Color4b(84, 90, 108, 255), + vcg::Color4b(91, 96, 110, 255), + vcg::Color4b(99, 102, 111, 255), + vcg::Color4b(106, 108, 113, 255), + vcg::Color4b(113, 114, 115, 255), + vcg::Color4b(120, 120, 118, 255), + vcg::Color4b(128, 126, 120, 255), + vcg::Color4b(135, 132, 120, 255), + vcg::Color4b(143, 138, 119, 255), + vcg::Color4b(151, 144, 118, 255), + vcg::Color4b(160, 151, 117, 255), + vcg::Color4b(168, 158, 115, 255), + vcg::Color4b(176, 164, 112, 255), + vcg::Color4b(184, 171, 109, 255), + vcg::Color4b(194, 178, 105, 255), + vcg::Color4b(202, 185, 100, 255), + vcg::Color4b(211, 192, 95, 255), + vcg::Color4b(219, 199, 89, 255), + vcg::Color4b(229, 207, 80, 255), + vcg::Color4b(238, 215, 71, 255), + vcg::Color4b(248, 222, 59, 255), + vcg::Color4b(253, 231, 55, 255), + } + }, + { + ColorMap::Turbo, + { + vcg::Color4b(48, 18, 59, 255), + vcg::Color4b(57, 41, 114, 255), + vcg::Color4b(64, 64, 161, 255), + vcg::Color4b(68, 86, 199, 255), + vcg::Color4b(70, 109, 230, 255), + vcg::Color4b(70, 130, 248, 255), + vcg::Color4b(64, 150, 254, 255), + vcg::Color4b(52, 170, 248, 255), + vcg::Color4b(37, 192, 230, 255), + vcg::Color4b(26, 209, 210, 255), + vcg::Color4b(24, 224, 189, 255), + vcg::Color4b(34, 235, 169, 255), + vcg::Color4b(59, 244, 141, 255), + vcg::Color4b(89, 251, 114, 255), + vcg::Color4b(120, 254, 89, 255), + vcg::Color4b(149, 254, 68, 255), + vcg::Color4b(174, 249, 55, 255), + vcg::Color4b(195, 241, 51, 255), + vcg::Color4b(214, 229, 53, 255), + vcg::Color4b(231, 215, 56, 255), + vcg::Color4b(244, 196, 58, 255), + vcg::Color4b(251, 179, 54, 255), + vcg::Color4b(254, 158, 46, 255), + vcg::Color4b(252, 134, 36, 255), + vcg::Color4b(246, 107, 24, 255), + vcg::Color4b(237, 85, 15, 255), + vcg::Color4b(226, 66, 9, 255), + vcg::Color4b(212, 50, 5, 255), + vcg::Color4b(192, 35, 2, 255), + vcg::Color4b(172, 22, 1, 255), + vcg::Color4b(148, 12, 1, 255), + vcg::Color4b(122, 4, 2, 255), + } + }, + { + ColorMap::RdPu, + { + vcg::Color4b(255, 247, 243, 255), + vcg::Color4b(254, 241, 237, 255), + vcg::Color4b(253, 235, 231, 255), + vcg::Color4b(253, 229, 226, 255), + vcg::Color4b(252, 223, 219, 255), + vcg::Color4b(252, 216, 212, 255), + vcg::Color4b(252, 209, 205, 255), + vcg::Color4b(252, 202, 198, 255), + vcg::Color4b(251, 194, 191, 255), + vcg::Color4b(251, 184, 188, 255), + vcg::Color4b(250, 175, 185, 255), + vcg::Color4b(250, 165, 182, 255), + vcg::Color4b(249, 153, 178, 255), + vcg::Color4b(248, 139, 173, 255), + vcg::Color4b(248, 125, 168, 255), + vcg::Color4b(247, 111, 163, 255), + vcg::Color4b(243, 96, 159, 255), + vcg::Color4b(236, 83, 157, 255), + vcg::Color4b(230, 70, 154, 255), + vcg::Color4b(223, 57, 152, 255), + vcg::Color4b(212, 42, 146, 255), + vcg::Color4b(200, 30, 140, 255), + vcg::Color4b(189, 17, 134, 255), + vcg::Color4b(177, 4, 127, 255), + vcg::Color4b(162, 1, 124, 255), + vcg::Color4b(149, 1, 122, 255), + vcg::Color4b(136, 1, 121, 255), + vcg::Color4b(123, 1, 119, 255), + vcg::Color4b(109, 0, 115, 255), + vcg::Color4b(97, 0, 112, 255), + vcg::Color4b(85, 0, 109, 255), + vcg::Color4b(73, 0, 106, 255), + } + }, +}; + +inline vcg::Color4b GetColorMapping(double v, double minv, double maxv, ColorMap cmap) +{ + if (cmap == ColorMap::RGB) { + vcg::Color4b c; + c.SetColorRamp(float(minv), float(maxv), float(v)); + return c; + } + + int sz = int(colorMaps[cmap].size()); + + if (v > maxv) + v = maxv; + if (v < minv) + v = minv; + + v = (v - minv) / (maxv - minv); + + double v0 = v * sz; + int n0 = int(v0); + + if (n0 < 0) + return colorMaps[cmap].front(); + if (n0 >= sz - 1) + return colorMaps[cmap].back(); + + int n1 = n0 + 1; + + double fract = v0 - n0; + + vcg::Color4b c0 = colorMaps[cmap][n0]; + vcg::Color4b c1 = colorMaps[cmap][n1]; + + c0.lerp(c0, c1, fract); + + return c0; +} + +} // namespace vcg + +#endif From 66a3b42a3e3a56bb3aa09699147d1bc587972551 Mon Sep 17 00:00:00 2001 From: Andrea Maggiordomo Date: Tue, 25 Oct 2022 13:28:14 +0200 Subject: [PATCH 03/10] Temporarily reverting changes to Precision --- wrap/io_trimesh/precision.h | 36 ++++++++++++++---------------------- 1 file changed, 14 insertions(+), 22 deletions(-) diff --git a/wrap/io_trimesh/precision.h b/wrap/io_trimesh/precision.h index a363f18a9..148c38863 100644 --- a/wrap/io_trimesh/precision.h +++ b/wrap/io_trimesh/precision.h @@ -8,34 +8,26 @@ namespace vcg namespace io { template - class Precision + struct Precision { - static int decimalPrecision; // the desired decimal precision - public: static int digits() {return 0;} - static void setDigits(int digits) { decimalPrecision = digits; } - static const char* typeName() {return "";} + static const char* typeName() {return "";} }; - - template - int Precision::decimalPrecision = 0; - - // Precision specializations with reasonable defaults - - // Precision specializations - template<> - int Precision::digits() { return decimalPrecision <= 0 ? 7 : decimalPrecision; } - - template<> - const char* Precision::typeName() { return "float"; } - - // Precision specializations + template<> - int Precision::digits() { return decimalPrecision <= 0 ? 16 : decimalPrecision; } + struct Precision + { + static int digits() {return 7;} + static const char* typeName() {return "float";} + }; + template<> - const char* Precision::typeName() { return "double"; } - + struct Precision + { + static int digits() {return 16;} + static const char* typeName() {return "double";} + }; } } } From 5e8da17e362d04d51dd6abb048247955e394f9e1 Mon Sep 17 00:00:00 2001 From: Luigi Malomo Date: Thu, 3 Nov 2022 11:28:23 +0100 Subject: [PATCH 04/10] removed warnings for unused vars --- vcg/complex/algorithms/refine.h | 1 + wrap/io_trimesh/import_off.h | 1 + wrap/io_trimesh/import_vmi.h | 1 + wrap/nanoply/include/nanoply.hpp | 1 + 4 files changed, 4 insertions(+) diff --git a/vcg/complex/algorithms/refine.h b/vcg/complex/algorithms/refine.h index 082a02286..b6ccf98c3 100644 --- a/vcg/complex/algorithms/refine.h +++ b/vcg/complex/algorithms/refine.h @@ -947,6 +947,7 @@ class TriSplit FFi0 = f->FFi(0); FFi1 = f->FFi(1); FFi2 = f->FFi(2); + (void)FFi0; //initial face (*f).FFp(1) = &(*f1); diff --git a/wrap/io_trimesh/import_off.h b/wrap/io_trimesh/import_off.h index 80e9f3829..f7fc55f25 100644 --- a/wrap/io_trimesh/import_off.h +++ b/wrap/io_trimesh/import_off.h @@ -210,6 +210,7 @@ namespace vcg { nVertices = atoi(tokens[0].c_str()); nFaces = atoi(tokens[1].c_str()); nEdges = atoi(tokens[2].c_str()); + (void)nEdges; // unused // dimension is the space dimension of vertices => it must be three(!) if (dimension != 3) diff --git a/wrap/io_trimesh/import_vmi.h b/wrap/io_trimesh/import_vmi.h index e08b2d31b..a8a07b827 100644 --- a/wrap/io_trimesh/import_vmi.h +++ b/wrap/io_trimesh/import_vmi.h @@ -740,6 +740,7 @@ namespace io { read = Read((void*)& m.face[0],sizeof(FaceType),faceSize ); LoadFaceOcf(m.face); } + (void)read; // unused /* load the per vertex attributes */ diff --git a/wrap/nanoply/include/nanoply.hpp b/wrap/nanoply/include/nanoply.hpp index e41109281..be84dc171 100644 --- a/wrap/nanoply/include/nanoply.hpp +++ b/wrap/nanoply/include/nanoply.hpp @@ -2710,6 +2710,7 @@ namespace nanoply if (!info.bigEndian) fixEndian = true; } + (void)fixEndian; if (info.binary) { From 9f6d56c52f92b54d5c50dfed902df070fcb90659 Mon Sep 17 00:00:00 2001 From: alemuntoni Date: Mon, 7 Nov 2022 11:56:09 +0100 Subject: [PATCH 05/10] option to add openmp flag to vcglib target --- CMakeLists.txt | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e48b68163..a7830851e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,12 +6,13 @@ cmake_minimum_required(VERSION 3.10) project(VCGLib) # Eigen options -option(ALLOW_BUNDLED_EIGEN "Allow use of bundled Eigen source" ON) -option(ALLOW_SYSTEM_EIGEN "Allow use of system-provided Eigen" ON) +option(VCG_ALLOW_BUNDLED_EIGEN "Allow use of bundled Eigen source" ON) +option(VCG_ALLOW_SYSTEM_EIGEN "Allow use of system-provided Eigen" ON) # VCG options option(VCG_HEADER_ONLY "Use VCG library in header only mode" ON) option(VCG_BUILD_EXAMPLES "Build a set of examples of the library" OFF) +option(VCG_USE_OPENMP "Allow VCG to find and link OpenMP if detected" ON) set (VCG_INCLUDE_DIRS ${CMAKE_CURRENT_LIST_DIR}) set (VCG_INCLUDE_DIRS ${CMAKE_CURRENT_LIST_DIR} PARENT_SCOPE) @@ -19,19 +20,28 @@ set (VCG_INCLUDE_DIRS ${CMAKE_CURRENT_LIST_DIR} PARENT_SCOPE) ### Build settings set(CMAKE_CXX_STANDARD 11) +### OpenMP +if (VCG_USE_OPENMP) + find_package(OpenMP) + if (APPLE AND OPENMP_FOUND) + set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}") + set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}") + endif() +endif() + ### Eigen set(VCG_EIGEN_DIR ${CMAKE_CURRENT_LIST_DIR}/eigenlib) -if(ALLOW_SYSTEM_EIGEN AND EIGEN3_INCLUDE_DIR) +if(VCG_ALLOW_SYSTEM_EIGEN AND EIGEN3_INCLUDE_DIR) message(STATUS "- Eigen - using system-provided library") set(EIGEN_INCLUDE_DIRS ${EIGEN3_INCLUDE_DIR}) -elseif(ALLOW_BUNDLED_EIGEN AND EXISTS "${VCG_EIGEN_DIR}/Eigen/Eigen") +elseif(VCG_ALLOW_BUNDLED_EIGEN AND EXISTS "${VCG_EIGEN_DIR}/Eigen/Eigen") message(STATUS "- Eigen - using bundled source") set(EIGEN_INCLUDE_DIRS ${VCG_EIGEN_DIR}) else() message( FATAL_ERROR - "Eigen is required - at least one of ALLOW_SYSTEM_EIGEN or ALLOW_BUNDLED_EIGEN must be enabled and found.") + "Eigen is required - at least one of VCG_ALLOW_SYSTEM_EIGEN or VCG_ALLOW_BUNDLED_EIGEN must be enabled and found.") endif() ### VCGLib headers and sources @@ -283,6 +293,9 @@ if (VCG_HEADER_ONLY) vcglib INTERFACE ${CMAKE_CURRENT_LIST_DIR} ${EIGEN_INCLUDE_DIRS}) + if(OPENMP_FOUND) + target_link_libraries(vcglib INTERFACE OpenMP::OpenMP_CXX) + endif() #just to show headers in ide add_custom_target(vcglib_ide SOURCES ${VCG_HEADERS}) From e9aba6d74331f58f63ea6ccaff4745a56afb509e Mon Sep 17 00:00:00 2001 From: alemuntoni Date: Tue, 13 Dec 2022 10:56:32 +0100 Subject: [PATCH 06/10] set a default value to clustering algorithm parameter --- vcg/complex/algorithms/clustering.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vcg/complex/algorithms/clustering.h b/vcg/complex/algorithms/clustering.h index 8e2420f66..b2a6df4b9 100644 --- a/vcg/complex/algorithms/clustering.h +++ b/vcg/complex/algorithms/clustering.h @@ -162,7 +162,7 @@ class Clustering // DuplicateFace=true a model with looks ok if you enable backface culling // DuplicateFace=false a model with looks ok if you enable doublesided lighting and disable backfaceculling - bool DuplicateFaceParam; + bool DuplicateFaceParam = true; //default true // This class keeps the references to the three cells where a face has its vertexes. class SimpleTri From 2833e40848aaf7d41f64f5ca3a408a40421a4f20 Mon Sep 17 00:00:00 2001 From: alemuntoni Date: Tue, 13 Dec 2022 11:18:00 +0100 Subject: [PATCH 07/10] Clustering class reorganization, using constructor and hiding attributes and methods that should not be exposed --- vcg/complex/algorithms/clustering.h | 696 +++++++++++++++------------- 1 file changed, 367 insertions(+), 329 deletions(-) diff --git a/vcg/complex/algorithms/clustering.h b/vcg/complex/algorithms/clustering.h index b2a6df4b9..da2f92826 100644 --- a/vcg/complex/algorithms/clustering.h +++ b/vcg/complex/algorithms/clustering.h @@ -1,361 +1,399 @@ -/**************************************************************************** -* VCGLib o o * -* Visual and Computer Graphics Library o o * -* _ O _ * -* Copyright(C) 2004-2016 \/)\/ * -* Visual Computing Lab /\/| * -* ISTI - Italian National Research Council | * -* \ * -* All rights reserved. * -* * -* This program is free software; you can redistribute it and/or modify * -* it under the terms of the GNU General Public License as published by * -* the Free Software Foundation; either version 2 of the License, or * -* (at your option) any later version. * -* * -* This program is distributed in the hope that it will be useful, * -* but WITHOUT ANY WARRANTY; without even the implied warranty of * -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * -* GNU General Public License (http://www.gnu.org/licenses/gpl.txt) * -* for more details. * -* * -****************************************************************************/ +/***************************************************************************** + * VCGLib o o * + * Visual and Computer Graphics Library o o * + * _ O _ * + * Copyright(C) 2004-2022 \/)\/ * + * Visual Computing Lab /\/| * + * ISTI - Italian National Research Council | * + * \ * + * All rights reserved. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License (http://www.gnu.org/licenses/gpl.txt) * + * for more details. * + * * + ****************************************************************************/ #ifndef __VCGLIB_CLUSTERING #define __VCGLIB_CLUSTERING -#include #include -#include -#include +#include +#include +#include #include #include -#include #include +#include -namespace std +namespace std { +template<> +struct hash { - template<> - struct hash - { - typedef vcg::Point3i argument_type; - - std::size_t operator()(const vcg::Point3i & s) const - { - return std::hash()(s[0]) ^ std::hash()(s[1]) ^ std::hash()(s[2]); - } - }; -} - -namespace vcg{ -namespace tri{ - -template -class NearestToCenter + typedef vcg::Point3i argument_type; + + std::size_t operator()(const vcg::Point3i& s) const + { + return std::hash()(s[0]) ^ std::hash()(s[1]) ^ std::hash()(s[2]); + } +}; +} // namespace std + +namespace vcg { +namespace tri { + +template +class NearestToCenter { - typedef typename MeshType::ScalarType ScalarType; - typedef typename MeshType::CoordType CoordType; - typedef typename MeshType::VertexType VertexType; - typedef typename MeshType::FaceType FaceType; - typedef BasicGrid GridType; + typedef typename MeshType::ScalarType ScalarType; + typedef typename MeshType::CoordType CoordType; + typedef typename MeshType::VertexType VertexType; + typedef typename MeshType::FaceType FaceType; + typedef BasicGrid GridType; public: - inline void AddVertex(MeshType &/*m*/, GridType &g, Point3i &pi, VertexType &v) - { - CoordType c; - g.IPiToBoxCenter(pi,c); - ScalarType newDist = Distance(c,v.cP()); - if(!valid || newDist < bestDist) - { - valid=true; - bestDist=newDist; - bestPos=v.cP(); - bestN=v.cN(); - orig=&v; - } - } - inline void AddFaceVertex(MeshType &/*m*/, FaceType &/*f*/, int /*i*/) { assert(0);} - NearestToCenter(): valid(false){} - - CoordType bestPos; - CoordType bestN; - ScalarType bestDist; - bool valid; - int id; - VertexType *orig; - CoordType Pos() const - { - assert(valid); - return bestPos; - } - Color4b Col() const {return Color4b::White;} - CoordType N() const {return bestN;} - VertexType * Ptr() const {return orig;} - + inline void AddVertex(MeshType& /*m*/, GridType& g, Point3i& pi, VertexType& v) + { + CoordType c; + g.IPiToBoxCenter(pi, c); + ScalarType newDist = Distance(c, v.cP()); + if (!valid || newDist < bestDist) { + valid = true; + bestDist = newDist; + bestPos = v.cP(); + bestN = v.cN(); + orig = &v; + } + } + inline void AddFaceVertex(MeshType& /*m*/, FaceType& /*f*/, int /*i*/) { assert(0); } + NearestToCenter() : valid(false) {} + + CoordType bestPos; + CoordType bestN; + ScalarType bestDist; + bool valid; + int id; + VertexType* orig; + CoordType Pos() const + { + assert(valid); + return bestPos; + } + Color4b Col() const { return Color4b::White; } + CoordType N() const { return bestN; } + VertexType* Ptr() const { return orig; } }; template -class AverageColorCell +class AverageColorCell { - typedef typename MeshType::CoordType CoordType; - typedef typename MeshType::FaceType FaceType; - typedef typename MeshType::VertexType VertexType; + typedef typename MeshType::CoordType CoordType; + typedef typename MeshType::FaceType FaceType; + typedef typename MeshType::VertexType VertexType; - typedef BasicGrid GridType; + typedef BasicGrid GridType; public: - inline void AddFaceVertex(MeshType &/*m*/, FaceType &f, int i) - { - p+=f.cV(i)->cP(); - c+=CoordType(f.cV(i)->C()[0],f.cV(i)->C()[1],f.cV(i)->C()[2]); - - // we prefer to use the un-normalized face normal so small faces facing away are dropped out - // and the resulting average is weighed with the size of the faces falling here. - n+=f.cN(); - cnt++; - } - inline void AddVertex(MeshType &m, GridType &/*g*/, Point3i &/*pi*/, VertexType &v) - { - p+=v.cP(); - n+=v.cN(); - if(tri::HasPerVertexColor(m)) - c+=CoordType(v.C()[0],v.C()[1],v.C()[2]); - cnt++; - } - - AverageColorCell(): p(0,0,0), n(0,0,0), c(0,0,0),cnt(0){} - CoordType p; - CoordType n; - CoordType c; - int cnt; - int id; - Color4b Col() const - { - return Color4b(c[0]/cnt,c[1]/cnt,c[2]/cnt,255); - } - - CoordType N() const {return n;} - VertexType * Ptr() const {return 0;} - CoordType Pos() const { return p/cnt; } + inline void AddFaceVertex(const MeshType&, const FaceType& f, int i) + { + p += f.cV(i)->cP(); + c += CoordType(f.cV(i)->C()[0], f.cV(i)->C()[1], f.cV(i)->C()[2]); + + // we prefer to use the un-normalized face normal so small faces facing away are dropped out + // and the resulting average is weighed with the size of the faces falling here. + n += f.cN(); + cnt++; + } + inline void AddVertex(const MeshType& m, GridType& /*g*/, Point3i& /*pi*/, const VertexType& v) + { + p += v.cP(); + n += v.cN(); + if (tri::HasPerVertexColor(m)) + c += CoordType(v.C()[0], v.C()[1], v.C()[2]); + cnt++; + } + + AverageColorCell() : p(0, 0, 0), n(0, 0, 0), c(0, 0, 0), cnt(0) {} + CoordType p; + CoordType n; + CoordType c; + int cnt; + int id; + Color4b Col() const { return Color4b(c[0] / cnt, c[1] / cnt, c[2] / cnt, 255); } + + CoordType N() const { return n; } + VertexType* Ptr() const { return 0; } + CoordType Pos() const { return p / cnt; } }; - /* Metodo di clustering */ template class Clustering { - public: - typedef typename MeshType::ScalarType ScalarType; - typedef typename MeshType::CoordType CoordType; - typedef typename MeshType::VertexType VertexType; - typedef typename MeshType::FaceType FaceType; - typedef typename MeshType::VertexPointer VertexPointer; - typedef typename MeshType::VertexIterator VertexIterator; - typedef typename MeshType::FaceIterator FaceIterator; - - // DuplicateFace == bool means that during the clustering doublesided surface (like a thin shell) that would be clustered to a single surface - // will be merged into two identical but opposite faces. - // So in practice: - // DuplicateFace=true a model with looks ok if you enable backface culling - // DuplicateFace=false a model with looks ok if you enable doublesided lighting and disable backfaceculling - - bool DuplicateFaceParam = true; //default true - - // This class keeps the references to the three cells where a face has its vertexes. - class SimpleTri - { - public: - CellType *v[3]; - int ii(int i) const {return *((int *)(&(v[i])));} - bool operator < ( const SimpleTri &p) const { - return (v[2]!=p.v[2])?(v[2] v[1] ) std::swap(v[0],v[1]); // now v0 < v1 - if(v[0] > v[2] ) std::swap(v[0],v[2]); // now v0 is the minimum - if(v[1] > v[2] ) std::swap(v[1],v[2]); // sorted! - } - bool operator ==(const SimpleTri &pt) const - { - return (pt.v[0] == v[0]) - && (pt.v[1] == v[1]) - && (pt.v[2] == v[2]); - } - // Hashing Function; - size_t operator () (const SimpleTri &pt) const - { - // return (ii(0)*HASH_P0 ^ ii(1)*HASH_P1 ^ ii(2)*HASH_P2); - return std::hash()(pt.v[0]) ^ std::hash()(pt.v[1]) ^ std::hash()(pt.v[2]); - } - }; - - // The init function Take two parameters - // _size is the approximate total number of cells composing the grid surrounding the objects (usually a large number) - // eg _size==1.000.000 means a 100x100x100 grid - // _cellsize is the absolute length of the edge of the grid cell. - // eg _cellsize==2.0 means that all the vertexes in a 2.0x2.0x2.0 cell are clustered togheter - - // Notes: - // _size is used only if the cell edge IS zero. - // _cellsize gives you an absolute measure of the maximum error introduced - // during the simplification (e.g. half of the cell edge length) - - - void Init(Box3 _mbb, int _size, ScalarType _cellsize=0) - { - GridCell.clear(); - TriSet.clear(); - Grid.bbox=_mbb; - ///inflate the bb calculated - ScalarType infl = (_cellsize == (ScalarType)0) ? (Grid.bbox.Diag() / _size) : (_cellsize); - Grid.bbox.min-=CoordType(infl,infl,infl); - Grid.bbox.max+=CoordType(infl,infl,infl); - Grid.dim = Grid.bbox.max - Grid.bbox.min; - if( _cellsize==0) - BestDim( _size, Grid.dim, Grid.siz ); - else - Grid.siz = Point3i::Construct(Grid.dim / _cellsize); - - // find voxel size - Grid.voxel[0] = Grid.dim[0]/Grid.siz[0]; - Grid.voxel[1] = Grid.dim[1]/Grid.siz[1]; - Grid.voxel[2] = Grid.dim[2]/Grid.siz[2]; - } - - BasicGrid Grid; - - std::unordered_set TriSet; - typedef typename std::unordered_set::iterator TriHashSetIterator; - std::unordered_map GridCell; - - - void AddPointSet(MeshType &m, bool UseOnlySelected=false) - { - for(VertexIterator vi=m.vert.begin();vi!=m.vert.end();++vi) - if(!(*vi).IsD()) - if(!UseOnlySelected || (*vi).IsS()) - { - Point3i pi; - Grid.PToIP((*vi).cP(), pi ); - GridCell[pi].AddVertex(m,Grid,pi,*(vi)); - } - } - - void AddMesh(MeshType &m) - { - FaceIterator fi; - for(fi=m.face.begin();fi!=m.face.end();++fi) if(!(*fi).IsD()) - { - Point3i pi; - SimpleTri st; - for(int i=0;i<3;++i) - { - Grid.PToIP((*fi).cV(i)->cP(), pi ); - st.v[i]=&(GridCell[pi]); - st.v[i]->AddFaceVertex(m,*(fi),i); - } - if( (st.v[0]!=st.v[1]) && (st.v[0]!=st.v[2]) && (st.v[1]!=st.v[2]) ) - { // if we allow the duplication of faces we sort the vertex only partially (to maintain the original face orientation) - if(DuplicateFaceParam) st.sortOrient(); - else st.sort(); - TriSet.insert(st); - } - // printf("Inserted %8i triangles, clustered to %8i tri and %i cells\n",distance(m.face.begin(),fi),TriSet.size(),GridCell.size()); - } - } - - int CountPointSet() {return GridCell.size(); } - - void SelectPointSet(MeshType &m) - { - typename std::unordered_map::iterator gi; - UpdateSelection::VertexClear(m); - for(gi=GridCell.begin();gi!=GridCell.end();++gi) - { - VertexType *ptr=(*gi).second.Ptr(); - if(ptr && ( ptr >= &*m.vert.begin() ) && ( ptr <= &*(m.vert.end() - 1) ) ) - ptr->SetS(); - } - } - void ExtractPointSet(MeshType &m) - { - m.Clear(); - - if (GridCell.empty()) return; - - Allocator::AddVertices(m,GridCell.size()); - typename std::unordered_map::iterator gi; - int i=0; - for(gi=GridCell.begin();gi!=GridCell.end();++gi) - { - m.vert[i].P()=(*gi).second.Pos(); - m.vert[i].N()=(*gi).second.N(); - if(HasPerVertexColor(m)) - m.vert[i].C()=(*gi).second.Col(); - ++i; - } - - } - - void ExtractMesh(MeshType &m) - { - m.Clear(); - - if (GridCell.empty()) return; - - Allocator::AddVertices(m,GridCell.size()); - typename std::unordered_map::iterator gi; - int i=0; - for(gi=GridCell.begin();gi!=GridCell.end();++gi) - { - m.vert[i].P()=(*gi).second.Pos(); - m.vert[i].N()=(*gi).second.N(); - if(HasPerVertexColor(m)) - m.vert[i].C()=(*gi).second.Col(); - (*gi).second.id=i; - ++i; - } - - Allocator::AddFaces(m,TriSet.size()); - TriHashSetIterator ti; - i=0; - for(ti=TriSet.begin();ti!=TriSet.end();++ti) - { - m.face[i].V(0)=&(m.vert[(*ti).v[0]->id]); - m.face[i].V(1)=&(m.vert[(*ti).v[1]->id]); - m.face[i].V(2)=&(m.vert[(*ti).v[2]->id]); - // if we are merging faces even when opposite we choose - // the best orientation according to the averaged normal - if(!DuplicateFaceParam) - { - CoordType N=TriangleNormal(m.face[i]); - int badOrient=0; - if( N.dot((*ti).v[0]->N()) <0) ++badOrient; - if( N.dot((*ti).v[1]->N()) <0) ++badOrient; - if( N.dot((*ti).v[2]->N()) <0) ++badOrient; - if(badOrient>2) - std::swap(m.face[i].V(0),m.face[i].V(1)); - } - i++; - } - - } -}; //end class clustering - } // namespace tri +public: + typedef typename MeshType::ScalarType ScalarType; + typedef typename MeshType::CoordType CoordType; + typedef typename MeshType::VertexType VertexType; + typedef typename MeshType::FaceType FaceType; + typedef typename MeshType::VertexPointer VertexPointer; + typedef typename MeshType::VertexIterator VertexIterator; + typedef typename MeshType::FaceIterator FaceIterator; + + // The constructor takes three parameters + // _mbb the bounding box of the grid + // _size is the approximate total number of cells composing the grid surrounding the objects + // (usually a large number) + // eg _size==1.000.000 means a 100x100x100 grid + // _cellsize is the absolute length of the edge of the grid cell. + // eg _cellsize==2.0 means that all the vertexes in a 2.0x2.0x2.0 cell are clustered + // togheter + // _dupFaceParam: means that during the clustering doublesided surface (like a thin + // shell) that would be clustered to a single surface will be merged into two identical but + // opposite faces. So in practice: DuplicateFace=true a model with looks ok if you enable + // backface culling DuplicateFace=false a model with looks ok if you enable doublesided lighting + // and disable backfaceculling + + // Notes: + // _size is used only if the cell edge IS zero. + // _cellsize gives you an absolute measure of the maximum error introduced + // during the simplification (e.g. half of the cell edge length) + + Clustering( + Box3 _mbb, + int _size, + ScalarType _cellsize = 0, + bool _dupFaceParam = true) : + DuplicateFaceParam(_dupFaceParam) + { + Init(_mbb, _size, _cellsize); + }; + + void AddPointSet(MeshType& m, bool UseOnlySelected = false) + { + for (VertexIterator vi = m.vert.begin(); vi != m.vert.end(); ++vi) + if (!(*vi).IsD()) + if (!UseOnlySelected || (*vi).IsS()) { + Point3i pi; + Grid.PToIP((*vi).cP(), pi); + GridCell[pi].AddVertex(m, Grid, pi, *(vi)); + } + } + + void AddMesh(MeshType& m) + { + FaceIterator fi; + for (fi = m.face.begin(); fi != m.face.end(); ++fi) { + if (!(*fi).IsD()) { + Point3i pi; + SimpleTri st; + for (int i = 0; i < 3; ++i) { + Grid.PToIP((*fi).cV(i)->cP(), pi); + st.v[i] = &(GridCell[pi]); + st.v[i]->AddFaceVertex(m, *(fi), i); + } + if ((st.v[0] != st.v[1]) && (st.v[0] != st.v[2]) && + (st.v[1] != + st.v[2])) { // if we allow the duplication of faces we sort the vertex only + // partially (to maintain the original face orientation) + if (DuplicateFaceParam) + st.sortOrient(); + else + st.sort(); + TriSet.insert(st); + } + // printf("Inserted %8i triangles, clustered to %8i tri and %i + // cells\n",distance(m.face.begin(),fi),TriSet.size(),GridCell.size()); + } + } + } + + int CountPointSet() { return GridCell.size(); } + + void SelectPointSet(MeshType& m) + { + typename std::unordered_map::iterator gi; + UpdateSelection::VertexClear(m); + for (gi = GridCell.begin(); gi != GridCell.end(); ++gi) { + VertexType* ptr = (*gi).second.Ptr(); + if (ptr && (ptr >= &*m.vert.begin()) && (ptr <= &*(m.vert.end() - 1))) + ptr->SetS(); + } + } + void ExtractPointSet(MeshType& m) + { + m.Clear(); + + if (GridCell.empty()) + return; + + Allocator::AddVertices(m, GridCell.size()); + typename std::unordered_map::iterator gi; + int i = 0; + for (gi = GridCell.begin(); gi != GridCell.end(); ++gi) { + m.vert[i].P() = (*gi).second.Pos(); + m.vert[i].N() = (*gi).second.N(); + if (HasPerVertexColor(m)) + m.vert[i].C() = (*gi).second.Col(); + ++i; + } + } + + void ExtractMesh(MeshType& m) + { + m.Clear(); + + if (GridCell.empty()) + return; + + Allocator::AddVertices(m, GridCell.size()); + typename std::unordered_map::iterator gi; + int i = 0; + for (gi = GridCell.begin(); gi != GridCell.end(); ++gi) { + m.vert[i].P() = (*gi).second.Pos(); + m.vert[i].N() = (*gi).second.N(); + if (HasPerVertexColor(m)) + m.vert[i].C() = (*gi).second.Col(); + (*gi).second.id = i; + ++i; + } + + Allocator::AddFaces(m, TriSet.size()); + TriHashSetIterator ti; + i = 0; + for (ti = TriSet.begin(); ti != TriSet.end(); ++ti) { + m.face[i].V(0) = &(m.vert[(*ti).v[0]->id]); + m.face[i].V(1) = &(m.vert[(*ti).v[1]->id]); + m.face[i].V(2) = &(m.vert[(*ti).v[2]->id]); + // if we are merging faces even when opposite we choose + // the best orientation according to the averaged normal + if (!DuplicateFaceParam) { + CoordType N = TriangleNormal(m.face[i]); + int badOrient = 0; + if (N.dot((*ti).v[0]->N()) < 0) + ++badOrient; + if (N.dot((*ti).v[1]->N()) < 0) + ++badOrient; + if (N.dot((*ti).v[2]->N()) < 0) + ++badOrient; + if (badOrient > 2) + std::swap(m.face[i].V(0), m.face[i].V(1)); + } + i++; + } + } + +private: + // This class keeps the references to the three cells where a face has its vertexes. + class SimpleTri + { + public: + CellType* v[3]; + int ii(int i) const { return *((int*) (&(v[i]))); } + bool operator<(const SimpleTri& p) const + { + return (v[2] != p.v[2]) ? (v[2] < p.v[2]) : + (v[1] != p.v[1]) ? (v[1] < p.v[1]) : + (v[0] < p.v[0]); + } + + // Sort the vertex of the face maintaining the original face orientation (it only ensure + // that v0 is the minimum) + void sortOrient() + { + if (v[1] < v[0] && v[1] < v[2]) { + std::swap(v[0], v[1]); + std::swap(v[1], v[2]); + return; + } // v1 was the minimum + if (v[2] < v[0] && v[2] < v[1]) { + std::swap(v[0], v[2]); + std::swap(v[1], v[2]); + return; + } // v2 was the minimum + return; // v0 was the minimum; + } + void sort() + { + if (v[0] > v[1]) + std::swap(v[0], v[1]); // now v0 < v1 + if (v[0] > v[2]) + std::swap(v[0], v[2]); // now v0 is the minimum + if (v[1] > v[2]) + std::swap(v[1], v[2]); // sorted! + } + bool operator==(const SimpleTri& pt) const + { + return (pt.v[0] == v[0]) && (pt.v[1] == v[1]) && (pt.v[2] == v[2]); + } + // Hashing Function; + size_t operator()(const SimpleTri& pt) const + { + // return (ii(0)*HASH_P0 ^ ii(1)*HASH_P1 ^ ii(2)*HASH_P2); + return std::hash()(pt.v[0]) ^ std::hash()(pt.v[1]) ^ + std::hash()(pt.v[2]); + } + }; + + // DuplicateFace == bool means that during the clustering doublesided surface (like a thin + // shell) that would be clustered to a single surface will be merged into two identical but + // opposite faces. So in practice: DuplicateFace=true a model with looks ok if you enable + // backface culling DuplicateFace=false a model with looks ok if you enable doublesided lighting + // and disable backfaceculling + + bool DuplicateFaceParam = true; + + BasicGrid Grid; + + std::unordered_set TriSet; + typedef typename std::unordered_set::iterator TriHashSetIterator; + std::unordered_map GridCell; + + // The init function Take two parameters + // _size is the approximate total number of cells composing the grid surrounding the objects + // (usually a large number) + // eg _size==1.000.000 means a 100x100x100 grid + // _cellsize is the absolute length of the edge of the grid cell. + // eg _cellsize==2.0 means that all the vertexes in a 2.0x2.0x2.0 cell are clustered + // togheter + + // Notes: + // _size is used only if the cell edge IS zero. + // _cellsize gives you an absolute measure of the maximum error introduced + // during the simplification (e.g. half of the cell edge length) + + void Init(Box3 _mbb, int _size, ScalarType _cellsize = 0) + { + GridCell.clear(); + TriSet.clear(); + Grid.bbox = _mbb; + /// inflate the bb calculated + ScalarType infl = (_cellsize == (ScalarType) 0) ? (Grid.bbox.Diag() / _size) : (_cellsize); + Grid.bbox.min -= CoordType(infl, infl, infl); + Grid.bbox.max += CoordType(infl, infl, infl); + Grid.dim = Grid.bbox.max - Grid.bbox.min; + if (_cellsize == 0) + BestDim(_size, Grid.dim, Grid.siz); + else + Grid.siz = Point3i::Construct(Grid.dim / _cellsize); + + // find voxel size + Grid.voxel[0] = Grid.dim[0] / Grid.siz[0]; + Grid.voxel[1] = Grid.dim[1] / Grid.siz[1]; + Grid.voxel[2] = Grid.dim[2] / Grid.siz[2]; + } + +}; // end class clustering +} // namespace tri } // namespace vcg #endif From 1ad36d292df20cd94fc42e65b40ef4207db09ca5 Mon Sep 17 00:00:00 2001 From: alemuntoni Date: Tue, 13 Dec 2022 11:32:54 +0100 Subject: [PATCH 08/10] fix vcg samples to build with clustering reorganization --- apps/sample/trimesh_clustering/trimesh_clustering.cpp | 10 ++++------ .../trimesh_pointcloud_sampling.cpp | 4 ++-- vcg/complex/algorithms/clustering.h | 10 ++++++++++ 3 files changed, 16 insertions(+), 8 deletions(-) diff --git a/apps/sample/trimesh_clustering/trimesh_clustering.cpp b/apps/sample/trimesh_clustering/trimesh_clustering.cpp index b8ae8d531..dc1659ae6 100644 --- a/apps/sample/trimesh_clustering/trimesh_clustering.cpp +++ b/apps/sample/trimesh_clustering/trimesh_clustering.cpp @@ -86,13 +86,11 @@ int main(int argc, char **argv) vcg::tri::UpdateBounding::Box(m); vcg::tri::UpdateNormal::PerFace(m); printf("Input mesh vn:%i fn:%i\n",m.VN(),m.FN()); - vcg::tri::Clustering > Grid; - Grid.DuplicateFaceParam=DupFace; - Grid.Init(m.bbox,CellNum,CellSize); + vcg::tri::Clustering > Grid(m.bbox,CellNum,CellSize, DupFace); - printf("Clustering to %i cells\n",Grid.Grid.siz[0]*Grid.Grid.siz[1]*Grid.Grid.siz[2] ); - printf("Grid of %i x %i x %i cells\n",Grid.Grid.siz[0],Grid.Grid.siz[1],Grid.Grid.siz[2]); - printf("with cells size of %.2f x %.2f x %.2f units\n",Grid.Grid.voxel[0],Grid.Grid.voxel[1],Grid.Grid.voxel[2]); + printf("Clustering to %i cells\n",Grid.gridSize()[0]*Grid.gridSize()[1]*Grid.gridSize()[2] ); + printf("Grid of %i x %i x %i cells\n",Grid.gridSize()[0],Grid.gridSize()[1],Grid.gridSize()[2]); + printf("with cells size of %.2f x %.2f x %.2f units\n",Grid.gridVoxel()[0],Grid.gridVoxel()[1],Grid.gridVoxel()[2]); Grid.AddMesh(m); Grid.ExtractMesh(m); diff --git a/apps/sample/trimesh_pointcloud_sampling/trimesh_pointcloud_sampling.cpp b/apps/sample/trimesh_pointcloud_sampling/trimesh_pointcloud_sampling.cpp index 9ce7e8d42..4dab85fc9 100644 --- a/apps/sample/trimesh_pointcloud_sampling/trimesh_pointcloud_sampling.cpp +++ b/apps/sample/trimesh_pointcloud_sampling/trimesh_pointcloud_sampling.cpp @@ -76,8 +76,8 @@ int main( int argc, char **argv ) printf("Sampled %i vertices in %5.2f\n",subM.VN(), float(pp.pds.pruneTime+pp.pds.gridTime)/float(CLOCKS_PER_SEC)); int t0=clock(); - tri::Clustering > ClusteringGrid; - ClusteringGrid.Init(m.bbox,100000,radius*sqrt(2.0f)); + tri::Clustering > ClusteringGrid( + m.bbox,100000,radius*sqrt(2.0f)); ClusteringGrid.AddPointSet(m); ClusteringGrid.ExtractMesh(cluM); int t1=clock(); diff --git a/vcg/complex/algorithms/clustering.h b/vcg/complex/algorithms/clustering.h index da2f92826..df702f541 100644 --- a/vcg/complex/algorithms/clustering.h +++ b/vcg/complex/algorithms/clustering.h @@ -178,6 +178,16 @@ class Clustering Init(_mbb, _size, _cellsize); }; + Point3i gridSize() const + { + return Grid.siz; + } + + Point3 gridVoxel() const + { + return Grid.voxel; + } + void AddPointSet(MeshType& m, bool UseOnlySelected = false) { for (VertexIterator vi = m.vert.begin(); vi != m.vert.end(); ++vi) From 61aebd8f1f3f70989019b0efac6c7ebe2fd44e51 Mon Sep 17 00:00:00 2001 From: Luigi Malomo Date: Sat, 17 Dec 2022 00:18:00 +0100 Subject: [PATCH 09/10] fixed nonply wrapper import bug: not importing mesh attributes made of just one element --- wrap/nanoply/include/nanoplyWrapper.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wrap/nanoply/include/nanoplyWrapper.hpp b/wrap/nanoply/include/nanoplyWrapper.hpp index 800b34279..cb02938cc 100644 --- a/wrap/nanoply/include/nanoplyWrapper.hpp +++ b/wrap/nanoply/include/nanoplyWrapper.hpp @@ -1192,7 +1192,7 @@ namespace nanoply std::string name((*iter).first); meshDescr.push_back(new ElementDescriptor(name)); count = info.GetElementCount(name); - if (count > 1) + if (count > 0) { meshDescr.back()->dataDescriptor = (*iter).second; } From a443e903a66e14a44b170056eee90d233cd753f9 Mon Sep 17 00:00:00 2001 From: alemuntoni Date: Mon, 9 Jan 2023 15:53:59 +0100 Subject: [PATCH 10/10] clear visited face flag before using it in updateCurvatureLocal --- vcg/complex/algorithms/update/curvature_fitting.h | 1 + 1 file changed, 1 insertion(+) diff --git a/vcg/complex/algorithms/update/curvature_fitting.h b/vcg/complex/algorithms/update/curvature_fitting.h index 332b3d36e..b5c17a6a9 100644 --- a/vcg/complex/algorithms/update/curvature_fitting.h +++ b/vcg/complex/algorithms/update/curvature_fitting.h @@ -621,6 +621,7 @@ class Quadric static void updateCurvatureLocal (MeshType & mesh, float radiusSphere, vcg::CallBackPos * cb = NULL) { + vcg::tri::UpdateFlags::FaceClear(mesh, FaceType::VISITED); bool projectionPlaneCheck = true; int vertexesPerFit = 0;