From 3589cfbe89b5d474e301590705b0ef4fd1ac81fd Mon Sep 17 00:00:00 2001 From: Bertrand Kerautret Date: Thu, 2 Nov 2023 15:49:37 +0100 Subject: [PATCH 01/27] init polyscope in cmake --- CMakeLists.txt | 6 +++++- polyscope.cmake | 14 ++++++++++++++ visualisation/CMakeLists.txt | 1 + 3 files changed, 20 insertions(+), 1 deletion(-) create mode 100644 polyscope.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index 7081bd4..c13c9ef 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,16 +7,19 @@ PROJECT(DGtalTools-contrib) cmake_minimum_required (VERSION 3.11) cmake_policy(SET CMP0057 NEW) +list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake) + SET(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) + # ----------------------------------------------------------------------------- # CPP11 # ----------------------------------------------------------------------------- set (CMAKE_CXX_STANDARD 11) set (CMAKE_CXX_STANDARD_REQUIRED TRUE) - +include(polyscope) FIND_PACKAGE(DGtal 1.3 REQUIRED) INCLUDE_DIRECTORIES(${DGTAL_INCLUDE_DIRS}) @@ -43,6 +46,7 @@ if(WITH_OPENCV) endif() + # CLI11 include_directories( "${PROJECT_SOURCE_DIR}/ext/" ) diff --git a/polyscope.cmake b/polyscope.cmake new file mode 100644 index 0000000..2f9e4a4 --- /dev/null +++ b/polyscope.cmake @@ -0,0 +1,14 @@ +if (TARGET polyscope) + return() +endif() + +include(FetchContent) + +message(STATUS "Fetching polyscope") + +FetchContent_Declare( + polyscope + GIT_REPOSITORY https://github.com/nmwsharp/polyscope.git + GIT_SHALLOW TRUE + ) +FetchContent_MakeAvailable(polyscope) \ No newline at end of file diff --git a/visualisation/CMakeLists.txt b/visualisation/CMakeLists.txt index b710ff1..8368c47 100644 --- a/visualisation/CMakeLists.txt +++ b/visualisation/CMakeLists.txt @@ -2,6 +2,7 @@ SET(DGTAL_TOOLS_CONTRIB displayTgtCoverAlphaTS displayLineSegments displaySet2dPts + polyMeshEdit ) From dcd7d638ce2083a7b944d86e1f915072368acf08 Mon Sep 17 00:00:00 2001 From: Bertrand Kerautret Date: Thu, 2 Nov 2023 23:32:09 +0100 Subject: [PATCH 02/27] polyscope cmake conf --- CMakeLists.txt | 3 ++- visualisation/CMakeLists.txt | 17 ++++++++++++++++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c13c9ef..0d0878d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,6 +10,7 @@ cmake_policy(SET CMP0057 NEW) list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake) SET(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) +include(polyscope) @@ -19,7 +20,6 @@ SET(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) set (CMAKE_CXX_STANDARD 11) set (CMAKE_CXX_STANDARD_REQUIRED TRUE) -include(polyscope) FIND_PACKAGE(DGtal 1.3 REQUIRED) INCLUDE_DIRECTORIES(${DGTAL_INCLUDE_DIRS}) @@ -49,6 +49,7 @@ endif() # CLI11 include_directories( "${PROJECT_SOURCE_DIR}/ext/" ) +include_directories(${PROJECT_SOURCE_DIR}) diff --git a/visualisation/CMakeLists.txt b/visualisation/CMakeLists.txt index 8368c47..c04b7f4 100644 --- a/visualisation/CMakeLists.txt +++ b/visualisation/CMakeLists.txt @@ -2,9 +2,14 @@ SET(DGTAL_TOOLS_CONTRIB displayTgtCoverAlphaTS displayLineSegments displaySet2dPts - polyMeshEdit ) +SET(DGTAL_TOOLS_CONTRIB_POLY + polyMeshEdit +) + + + FOREACH(FILE ${DGTAL_TOOLS_CONTRIB}) @@ -17,6 +22,16 @@ FOREACH(FILE ${DGTAL_TOOLS_CONTRIB}) ENDFOREACH(FILE) +FOREACH(FILE ${DGTAL_TOOLS_CONTRIB_POLY}) + add_executable(${FILE} ${FILE}) + target_link_libraries (${FILE} polyscope ${DGTAL_LIBRARIES} ${DGtalToolsContribLibDependencies}) + install(TARGETS ${FILE} + RUNTIME DESTINATION bin + LIBRARY DESTINATION lib + ARCHIVE DESTINATION lib) +ENDFOREACH(FILE) + + if ( WITH_VISU3D_QGLVIEWER ) From 85aafc8bdf87f1e0654d6f8ec81e573f71ace555 Mon Sep 17 00:00:00 2001 From: Bertrand Kerautret Date: Fri, 3 Nov 2023 17:19:53 +0100 Subject: [PATCH 03/27] polyMeshEdit base --- visualisation/polyMeshEdit.cpp | 146 +++++++++++++++++++++++++++++++++ 1 file changed, 146 insertions(+) create mode 100644 visualisation/polyMeshEdit.cpp diff --git a/visualisation/polyMeshEdit.cpp b/visualisation/polyMeshEdit.cpp new file mode 100644 index 0000000..e7bab21 --- /dev/null +++ b/visualisation/polyMeshEdit.cpp @@ -0,0 +1,146 @@ +#include +#include +#include +#include +#include +#include "DGtal/io/readers/MeshReader.h" +#include "DGtal/io/writers/MeshWriter.h" +#include "DGtal/io/readers/PointListReader.h" + + +#include +#include +#include +#include + +#include "CLI11.hpp" + + +using namespace DGtal; +using namespace Z3i; + +typedef PolygonalSurface PolySurface; + +static PolySurface polysurf; +static PolySurface reconsSelectSurf; +static std::vector> facesSelectSurf; + +static std::vector vectSelection; + +static int shiftFaceIndex = 0; + +static Z3i::RealPoint +getFaceBarycenter(PolySurface &polysurf, const PolySurface::Face &aFace){ + Z3i::RealPoint res(0.0, 0.0, 0.0); + for(auto const &v: polysurf.verticesAroundFace(aFace)){ + res += polysurf.positions()[v]; + } + double s = (double) polysurf.verticesAroundFace(aFace).size(); + return res/s; +} + +// Helper function +std::vector faceAround( PolySurface &polysurf, PolySurface::Face faceId, + double radius){ + std::vector result; + std::queue q; + std::map fVisited; + std::map vVisited; + + for (auto const &v : polysurf.verticesAroundFace(faceId) ){ + q.push(v); + } + fVisited[faceId] = true; + bool addNewFaces = true; + while (!q.empty() ) { + PolySurface::Vertex v = q.front(); q.pop(); + auto listFace = polysurf.facesAroundVertex(v); + for (auto const & f : listFace){ + if (fVisited.count(f)==0){ + if((getFaceBarycenter(polysurf, f) - + getFaceBarycenter(polysurf, faceId)).norm() < radius){ + fVisited[f]=true; + result.push_back(f); + for (auto const & v : polysurf.verticesAroundFace(f)){ + if (vVisited.count(v)==0){ + vVisited[v]=true; + q.push(v); + } + } + } + } + } + } + return result; +} + + +void callbackFaceID() { + ImGuiIO& io = ImGui::GetIO(); + auto digsurf = polyscope::getSurfaceMesh("InputMesh"); + if (io.MouseDoubleClicked[0]) { + unsigned long indexSelect = polyscope::pick::getSelection().second; + if (indexSelect < shiftFaceIndex){ + std::cout << "vertices selected" << std::endl; + }else{ + int nb = (int) polyscope::pick::getSelection().second - shiftFaceIndex; + std::cout << "face selected " << nb << std::endl; + if (nb > 0 && nb < vectSelection.size()){ + auto fVois = faceAround(polysurf, nb, 2); + std::cout << "face around " << fVois.size() << std::endl; + vectSelection[nb] = 0; + for (auto f: fVois){ + vectSelection[f] = 50; + } + } + } + } + digsurf -> removeQuantity("selection"); + digsurf -> addFaceScalarQuantity("selection", vectSelection); +} + + + + + +int main(int argc, char** argv) +{ + std::string inputFileName {""}; + std::string colorFileName; // The file containing the index to be colored in the colors + + // parse command line using CLI ---------------------------------------------- + CLI::App app; + + app.description("Test display accumulation\n" + " testPolyscope -i file.obj \n"); + app.add_option("-i,--input,1", inputFileName, "an input mesh file in .obj format." ) + ->required() + ->check(CLI::ExistingFile); + + + app.get_formatter()->column_width(40); + CLI11_PARSE(app, argc, argv); + polyscope::init(); + + // read input mesh + DGtal::Mesh aMesh(true); + aMesh << inputFileName; + + DGtal::MeshHelpers::mesh2PolygonalSurface(aMesh, polysurf); + DGtal::MeshHelpers::mesh2PolygonalSurface(aMesh, reconsSelectSurf); + shiftFaceIndex = aMesh.nbVertex(); + std::vector> faces; + for(auto &face: polysurf.allFaces()){ + faces.push_back(polysurf.verticesAroundFace( face )); + vectSelection.push_back(200); + } + polyscope::state::userCallback = callbackFaceID; + vectSelection[0]=0; + auto digsurf = polyscope::registerSurfaceMesh("InputMesh", polysurf.positions(), faces); + digsurf->addFaceScalarQuantity("selection", vectSelection); + digsurf->setAllQuantitiesEnabled(true); + polyscope::show(); + + return 0; +} + From 1df9fd2dc12472cd0aa52daef8f8171067b1f65a Mon Sep 17 00:00:00 2001 From: Bertrand Kerautret Date: Sun, 5 Nov 2023 22:19:27 +0100 Subject: [PATCH 04/27] delete faces regions and export results --- visualisation/polyMeshEdit.cpp | 165 ++++++++++++++++++++++++--------- 1 file changed, 119 insertions(+), 46 deletions(-) diff --git a/visualisation/polyMeshEdit.cpp b/visualisation/polyMeshEdit.cpp index e7bab21..1e81c24 100644 --- a/visualisation/polyMeshEdit.cpp +++ b/visualisation/polyMeshEdit.cpp @@ -5,8 +5,6 @@ #include #include "DGtal/io/readers/MeshReader.h" #include "DGtal/io/writers/MeshWriter.h" -#include "DGtal/io/readers/PointListReader.h" - #include #include @@ -21,47 +19,66 @@ using namespace Z3i; typedef PolygonalSurface PolySurface; -static PolySurface polysurf; -static PolySurface reconsSelectSurf; -static std::vector> facesSelectSurf; - +static PolySurface currentPolysurf; static std::vector vectSelection; +static long int shiftFaceIndex = 0; +static float paintRad = 1.0; + +static const int labelSelect = 200; +static const int labelRef = 50; -static int shiftFaceIndex = 0; +static std::string outputFileName {"result.obj"}; + + +void addSurfaceInPolyscope(PolySurface &psurf){ + polyscope::removeStructure("InputMesh"); + std::vector> faces; + vectSelection.clear(); + for(auto &face: psurf.allFaces()){ + faces.push_back(psurf.verticesAroundFace( face )); + vectSelection.push_back(labelSelect); + } + auto digsurf = polyscope::registerSurfaceMesh("InputMesh", + psurf.positions(), faces); + digsurf->addFaceScalarQuantity("selection", vectSelection); + digsurf->setAllQuantitiesEnabled(true); + shiftFaceIndex = psurf.nbVertices(); + +} static Z3i::RealPoint -getFaceBarycenter(PolySurface &polysurf, const PolySurface::Face &aFace){ +getFaceBarycenter(PolySurface &polysurff, const PolySurface::Face &aFace){ Z3i::RealPoint res(0.0, 0.0, 0.0); - for(auto const &v: polysurf.verticesAroundFace(aFace)){ - res += polysurf.positions()[v]; + for(auto const &v: polysurff.verticesAroundFace(aFace)){ + res += polysurff.positions()[v]; } - double s = (double) polysurf.verticesAroundFace(aFace).size(); - return res/s; + return res/polysurff.verticesAroundFace(aFace).size(); } // Helper function -std::vector faceAround( PolySurface &polysurf, PolySurface::Face faceId, - double radius){ +std::vector faceAround(PolySurface &polysurff, + PolySurface::Face faceId, + double radius){ std::vector result; std::queue q; std::map fVisited; std::map vVisited; - for (auto const &v : polysurf.verticesAroundFace(faceId) ){ + for (auto const &v : polysurff.verticesAroundFace(faceId) ){ q.push(v); } fVisited[faceId] = true; bool addNewFaces = true; while (!q.empty() ) { PolySurface::Vertex v = q.front(); q.pop(); - auto listFace = polysurf.facesAroundVertex(v); + auto listFace = polysurff.facesAroundVertex(v); for (auto const & f : listFace){ if (fVisited.count(f)==0){ - if((getFaceBarycenter(polysurf, f) - - getFaceBarycenter(polysurf, faceId)).norm() < radius){ + if((getFaceBarycenter(polysurff, f) - + getFaceBarycenter(polysurff, faceId)).norm() < radius){ fVisited[f]=true; result.push_back(f); - for (auto const & v : polysurf.verticesAroundFace(f)){ + for (auto const & v : polysurff.verticesAroundFace(f)){ if (vVisited.count(v)==0){ vVisited[v]=true; q.push(v); @@ -75,23 +92,83 @@ std::vector faceAround( PolySurface &polysurf, PolySurface::F } +void deleteSelectedFaces(){ + PolySurface newSur; + std::vector vertexUsed (currentPolysurf.nbVertices(), false); + for ( unsigned int i = 0; i< currentPolysurf.nbFaces(); i++ ){ + if (vectSelection[i]==labelSelect){ + auto face = currentPolysurf.verticesAroundFace( i ); + for (auto v: face){ + vertexUsed[v] = true; + } + } + } + auto lp = currentPolysurf.positions(); + for(unsigned int i = 0; i < currentPolysurf.nbVertices(); i++){ + if(vertexUsed[i]){ + newSur.addVertex(lp[i]); + } + } + std::vector translateIndexId; + int currentIndex = 0; + for(unsigned int i = 0; i < currentPolysurf.nbVertices(); i++ ){ + if (vertexUsed[i]){ + translateIndexId.push_back(currentIndex); + currentIndex++; + }else{ + translateIndexId.push_back(-1); + } + } + for ( unsigned int f = 0; f< currentPolysurf.nbFaces(); f++ ){ + if (vectSelection[f]==labelSelect){ + auto face = currentPolysurf.verticesAroundFace( f ); + for (unsigned int i = 0; i= shiftFaceIndex){ + nb = (unsigned long) polyscope::pick::getSelection().second - shiftFaceIndex; }else{ - int nb = (int) polyscope::pick::getSelection().second - shiftFaceIndex; - std::cout << "face selected " << nb << std::endl; - if (nb > 0 && nb < vectSelection.size()){ - auto fVois = faceAround(polysurf, nb, 2); - std::cout << "face around " << fVois.size() << std::endl; - vectSelection[nb] = 0; - for (auto f: fVois){ - vectSelection[f] = 50; - } + // vertex selected (selecting a face connected to it) + if(currentPolysurf.facesAroundVertex(polyscope::pick::getSelection().second) + .size()> 0){ + nb = currentPolysurf.facesAroundVertex(polyscope::pick::getSelection().second)[0]; + } + } + if (nb > 0 && nb < vectSelection.size()){ + auto fVois = faceAround(currentPolysurf, nb, paintRad); + vectSelection[nb] = 0; + for (auto f: fVois){ + vectSelection[f] = labelRef; } } } @@ -106,17 +183,20 @@ void callbackFaceID() { int main(int argc, char** argv) { std::string inputFileName {""}; + + std::string colorFileName; // The file containing the index to be colored in the colors // parse command line using CLI ---------------------------------------------- CLI::App app; - - app.description("Test display accumulation\n" - " testPolyscope -i file.obj \n"); - app.add_option("-i,--input,1", inputFileName, "an input mesh file in .obj format." ) + app.description("polyMeshEdit \n" + " polyMeshEdit -i file.obj \n"); + app.add_option("-i,--input,1", inputFileName, "an input mesh file in .obj or .off format." ) ->required() ->check(CLI::ExistingFile); - + app.add_option("-o,--output,2", outputFileName, "an output mesh file in .obj or .off format." ) + ->check(CLI::ExistingFile); + app.get_formatter()->column_width(40); CLI11_PARSE(app, argc, argv); @@ -126,21 +206,14 @@ int main(int argc, char** argv) DGtal::Mesh aMesh(true); aMesh << inputFileName; - DGtal::MeshHelpers::mesh2PolygonalSurface(aMesh, polysurf); - DGtal::MeshHelpers::mesh2PolygonalSurface(aMesh, reconsSelectSurf); + DGtal::MeshHelpers::mesh2PolygonalSurface(aMesh, currentPolysurf); shiftFaceIndex = aMesh.nbVertex(); - std::vector> faces; - for(auto &face: polysurf.allFaces()){ - faces.push_back(polysurf.verticesAroundFace( face )); - vectSelection.push_back(200); - } polyscope::state::userCallback = callbackFaceID; - vectSelection[0]=0; - auto digsurf = polyscope::registerSurfaceMesh("InputMesh", polysurf.positions(), faces); - digsurf->addFaceScalarQuantity("selection", vectSelection); - digsurf->setAllQuantitiesEnabled(true); + + addSurfaceInPolyscope(currentPolysurf); polyscope::show(); return 0; } + From 542c312dcc1fdfbcff6205a6ff525c560fc7a56c Mon Sep 17 00:00:00 2001 From: Bertrand Kerautret Date: Tue, 7 Nov 2023 11:30:39 +0100 Subject: [PATCH 05/27] select with frequence --- visualisation/polyMeshEdit.cpp | 39 +++++++++++++++++++++++++++++++--- 1 file changed, 36 insertions(+), 3 deletions(-) diff --git a/visualisation/polyMeshEdit.cpp b/visualisation/polyMeshEdit.cpp index 1e81c24..58850f5 100644 --- a/visualisation/polyMeshEdit.cpp +++ b/visualisation/polyMeshEdit.cpp @@ -23,6 +23,8 @@ static PolySurface currentPolysurf; static std::vector vectSelection; static long int shiftFaceIndex = 0; static float paintRad = 1.0; +static int partialF = 1; + static const int labelSelect = 200; static const int labelRef = 50; @@ -88,8 +90,23 @@ std::vector faceAround(PolySurface &polysurff, } } } + return result; } +/** + * Remove face from selectio with a probability of 1/selFreq + */ +void partialSelect(int selFreq=1){ + srand((unsigned) time(NULL)); + for ( unsigned int i = 0; i< currentPolysurf.nbFaces(); i++ ){ + if (vectSelection[i]==labelRef){ + if (rand()%selFreq==0){ + vectSelection[i]=labelSelect; + } + } + } +} + void deleteSelectedFaces(){ @@ -134,8 +151,17 @@ void deleteSelectedFaces(){ } void callbackFaceID() { - ImGui::Text("Setting selection:"); + srand((unsigned) time(NULL)); + + ImGui::Text("Setting selection size:"); ImGui::SliderFloat("radius values", &paintRad, 0.01f, 10.0f, "ratio = %.3f"); + + ImGui::Separator(); + + ImGui::Text("Set selection freq:"); + ImGui::SliderInt(" freq (1=select all, 2= select 1 over 2", &partialF, 1, 100, "ratio = %i"); + ImGui::Separator(); + ImGui::Text("Action:"); if (ImGui::Button("Clear selection")) { for(auto &i : vectSelection){ @@ -145,6 +171,7 @@ void callbackFaceID() { if (ImGui::Button("delete selected faces")) { deleteSelectedFaces(); } + if (ImGui::Button("save in .obj")) { std::ofstream obj_stream( outputFileName.c_str() ); MeshHelpers::exportOBJ(obj_stream, currentPolysurf); @@ -164,12 +191,18 @@ void callbackFaceID() { nb = currentPolysurf.facesAroundVertex(polyscope::pick::getSelection().second)[0]; } } + if (nb > 0 && nb < vectSelection.size()){ auto fVois = faceAround(currentPolysurf, nb, paintRad); vectSelection[nb] = 0; + srand((unsigned) time(NULL)); for (auto f: fVois){ - vectSelection[f] = labelRef; - } + if (rand()%partialF==0){ + vectSelection[f]=labelRef; + }else{ + vectSelection[f]=labelSelect; + } + } } } digsurf -> removeQuantity("selection"); From 1b74e24d99f06c705384aec06562253540c4b3cc Mon Sep 17 00:00:00 2001 From: Bertrand Kerautret Date: Tue, 7 Nov 2023 16:33:10 +0100 Subject: [PATCH 06/27] add missing file --- cmake/polyscope.cmake | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 cmake/polyscope.cmake diff --git a/cmake/polyscope.cmake b/cmake/polyscope.cmake new file mode 100644 index 0000000..2f9e4a4 --- /dev/null +++ b/cmake/polyscope.cmake @@ -0,0 +1,14 @@ +if (TARGET polyscope) + return() +endif() + +include(FetchContent) + +message(STATUS "Fetching polyscope") + +FetchContent_Declare( + polyscope + GIT_REPOSITORY https://github.com/nmwsharp/polyscope.git + GIT_SHALLOW TRUE + ) +FetchContent_MakeAvailable(polyscope) \ No newline at end of file From 60406098fafd636bd057e7f53cef166440cb8574 Mon Sep 17 00:00:00 2001 From: Bertrand Kerautret Date: Tue, 7 Nov 2023 16:33:13 +0100 Subject: [PATCH 07/27] add missing file --- visualisation/polyMeshEdit.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/visualisation/polyMeshEdit.cpp b/visualisation/polyMeshEdit.cpp index 58850f5..31b17e2 100644 --- a/visualisation/polyMeshEdit.cpp +++ b/visualisation/polyMeshEdit.cpp @@ -154,12 +154,12 @@ void callbackFaceID() { srand((unsigned) time(NULL)); ImGui::Text("Setting selection size:"); - ImGui::SliderFloat("radius values", &paintRad, 0.01f, 10.0f, "ratio = %.3f"); + ImGui::SliderFloat("radius values", &paintRad, 0.01f, 10.0f, "size = %.3f"); ImGui::Separator(); ImGui::Text("Set selection freq:"); - ImGui::SliderInt(" freq (1=select all, 2= select 1 over 2", &partialF, 1, 100, "ratio = %i"); + ImGui::SliderInt(" freq (1=select all, 2=select 1over2)", &partialF, 1, 10, "freq = %i"); ImGui::Separator(); ImGui::Text("Action:"); From bb2b7c4c022f98a56a09591d70757b855488dcf2 Mon Sep 17 00:00:00 2001 From: Bertrand Kerautret Date: Wed, 8 Nov 2023 01:23:33 +0100 Subject: [PATCH 08/27] fix mesh non used vertex --- visualisation/polyMeshEdit.cpp | 96 ++++++++++++++++++++++++++++++++-- 1 file changed, 91 insertions(+), 5 deletions(-) diff --git a/visualisation/polyMeshEdit.cpp b/visualisation/polyMeshEdit.cpp index 31b17e2..0f0271d 100644 --- a/visualisation/polyMeshEdit.cpp +++ b/visualisation/polyMeshEdit.cpp @@ -20,9 +20,12 @@ using namespace Z3i; typedef PolygonalSurface PolySurface; static PolySurface currentPolysurf; +static PolySurface firstPolysurf; + static std::vector vectSelection; static long int shiftFaceIndex = 0; static float paintRad = 1.0; +static float noiseLevel = 1.0; static int partialF = 1; @@ -44,7 +47,7 @@ void addSurfaceInPolyscope(PolySurface &psurf){ psurf.positions(), faces); digsurf->addFaceScalarQuantity("selection", vectSelection); digsurf->setAllQuantitiesEnabled(true); - shiftFaceIndex = psurf.nbVertices(); + shiftFaceIndex = psurf.positions().size(); } @@ -107,8 +110,73 @@ void partialSelect(int selFreq=1){ } } +void noisify(double scale = 0.01){ + + srand((unsigned) time(NULL)); + for ( unsigned int i = 0; i< currentPolysurf.nbFaces(); i++ ){ + Z3i::RealPoint pDep(((double)(rand()%100000)/100000.0)*scale, + ((double)(rand()%100000)/100000.0)*scale, + ((double)(rand()%100000)/100000.0)*scale); + if (vectSelection[i]==labelRef){ + for (auto f: currentPolysurf.verticesAroundFace(i)){ + currentPolysurf.positions()[f][0] += pDep[0]; + currentPolysurf.positions()[f][1] += pDep[1]; + currentPolysurf.positions()[f][2] += pDep[2]; + + } + } + } + addSurfaceInPolyscope(currentPolysurf); +} + +DGtal::Mesh +meshFixVertexUnity(DGtal::Mesh &aMesh){ + DGtal::Mesh res; + std::map mapPt; + std::vector vertexUsed (aMesh.nbVertex(), false); + for ( unsigned int f = 0; f< aMesh.nbFaces(); f++ ){ + auto face = aMesh.getFace(f); + for (unsigned int i = 0; i translateIndexId; + int currentIndex = 0; + for(unsigned int i = 0; i < aMesh.nbVertex(); i++ ){ + if (vertexUsed[i]){ + res.addVertex(aMesh.getVertex(i)); + translateIndexId.push_back(currentIndex); + currentIndex++; + }else{ + translateIndexId.push_back(-1); + } + } + vertexUsed = std::vector (aMesh.nbVertex(), false); + for ( unsigned int f = 0; f< aMesh.nbFaces(); f++ ){ + auto face = aMesh.getFace(f); + for (unsigned int i = 0; i vertexUsed (currentPolysurf.nbVertices(), false); @@ -161,21 +229,39 @@ void callbackFaceID() { ImGui::Text("Set selection freq:"); ImGui::SliderInt(" freq (1=select all, 2=select 1over2)", &partialF, 1, 10, "freq = %i"); ImGui::Separator(); - + ImGui::Text("Noise parameters:"); + ImGui::SliderFloat("noise scale", &noiseLevel, 0.001, 10, "scale = %f"); + ImGui::Separator(); + ImGui::Text("Action:"); if (ImGui::Button("Clear selection")) { for(auto &i : vectSelection){ i=labelSelect; } } + ImGui::SameLine(); if (ImGui::Button("delete selected faces")) { deleteSelectedFaces(); } - + ImGui::SameLine(); + if (ImGui::Button("noisify selected faces")) { + noisify(noiseLevel); + } + ImGui::Separator(); + ImGui::Text("IO"); + if (ImGui::Button("save in .obj")) { std::ofstream obj_stream( outputFileName.c_str() ); MeshHelpers::exportOBJ(obj_stream, currentPolysurf); } + ImGui::SameLine(); + + if (ImGui::Button("reload src")) { + currentPolysurf = firstPolysurf; + addSurfaceInPolyscope(currentPolysurf); + + } + ImGuiIO& io = ImGui::GetIO(); auto digsurf = polyscope::getSurfaceMesh("InputMesh"); if (io.MouseDoubleClicked[0]) { @@ -238,12 +324,12 @@ int main(int argc, char** argv) // read input mesh DGtal::Mesh aMesh(true); aMesh << inputFileName; - + aMesh = meshFixVertexUnity(aMesh); DGtal::MeshHelpers::mesh2PolygonalSurface(aMesh, currentPolysurf); shiftFaceIndex = aMesh.nbVertex(); polyscope::state::userCallback = callbackFaceID; - addSurfaceInPolyscope(currentPolysurf); + firstPolysurf = currentPolysurf; polyscope::show(); return 0; From 36e3a78034dcdc1f8039f31c2fff880d80373c8b Mon Sep 17 00:00:00 2001 From: Bertrand Kerautret Date: Wed, 8 Nov 2023 01:30:33 +0100 Subject: [PATCH 09/27] noise neg --- visualisation/polyMeshEdit.cpp | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/visualisation/polyMeshEdit.cpp b/visualisation/polyMeshEdit.cpp index 0f0271d..c24593a 100644 --- a/visualisation/polyMeshEdit.cpp +++ b/visualisation/polyMeshEdit.cpp @@ -111,18 +111,16 @@ void partialSelect(int selFreq=1){ } void noisify(double scale = 0.01){ - srand((unsigned) time(NULL)); for ( unsigned int i = 0; i< currentPolysurf.nbFaces(); i++ ){ - Z3i::RealPoint pDep(((double)(rand()%100000)/100000.0)*scale, - ((double)(rand()%100000)/100000.0)*scale, - ((double)(rand()%100000)/100000.0)*scale); + Z3i::RealPoint pDep(((double)(rand()%100000-50000)/100000.0)*scale, + ((double)(rand()%100000-50000)/100000.0)*scale, + ((double)(rand()%100000-50000)/100000.0)*scale); if (vectSelection[i]==labelRef){ for (auto f: currentPolysurf.verticesAroundFace(i)){ currentPolysurf.positions()[f][0] += pDep[0]; currentPolysurf.positions()[f][1] += pDep[1]; currentPolysurf.positions()[f][2] += pDep[2]; - } } } @@ -230,7 +228,7 @@ void callbackFaceID() { ImGui::SliderInt(" freq (1=select all, 2=select 1over2)", &partialF, 1, 10, "freq = %i"); ImGui::Separator(); ImGui::Text("Noise parameters:"); - ImGui::SliderFloat("noise scale", &noiseLevel, 0.001, 10, "scale = %f"); + ImGui::SliderFloat("noise scale", &noiseLevel, 0.001, 2, "scale = %f"); ImGui::Separator(); ImGui::Text("Action:"); From 04cdc923b62cce97ee9063bca3e08ce1d040a335 Mon Sep 17 00:00:00 2001 From: Bertrand Kerautret Date: Sat, 11 Nov 2023 00:33:00 +0100 Subject: [PATCH 10/27] hide show interface --- visualisation/polyMeshEdit.cpp | 67 ++++++++++++++++++---------------- 1 file changed, 36 insertions(+), 31 deletions(-) diff --git a/visualisation/polyMeshEdit.cpp b/visualisation/polyMeshEdit.cpp index c24593a..067b32d 100644 --- a/visualisation/polyMeshEdit.cpp +++ b/visualisation/polyMeshEdit.cpp @@ -23,11 +23,10 @@ static PolySurface currentPolysurf; static PolySurface firstPolysurf; static std::vector vectSelection; -static long int shiftFaceIndex = 0; static float paintRad = 1.0; static float noiseLevel = 1.0; static int partialF = 1; - +static int randLarge = 100000; static const int labelSelect = 200; static const int labelRef = 50; @@ -43,12 +42,11 @@ void addSurfaceInPolyscope(PolySurface &psurf){ faces.push_back(psurf.verticesAroundFace( face )); vectSelection.push_back(labelSelect); } + auto digsurf = polyscope::registerSurfaceMesh("InputMesh", psurf.positions(), faces); digsurf->addFaceScalarQuantity("selection", vectSelection); digsurf->setAllQuantitiesEnabled(true); - shiftFaceIndex = psurf.positions().size(); - } static Z3i::RealPoint @@ -113,9 +111,9 @@ void partialSelect(int selFreq=1){ void noisify(double scale = 0.01){ srand((unsigned) time(NULL)); for ( unsigned int i = 0; i< currentPolysurf.nbFaces(); i++ ){ - Z3i::RealPoint pDep(((double)(rand()%100000-50000)/100000.0)*scale, - ((double)(rand()%100000-50000)/100000.0)*scale, - ((double)(rand()%100000-50000)/100000.0)*scale); + Z3i::RealPoint pDep((((double)(rand()%randLarge)-randLarge/2.0)/randLarge)*scale, + (((double)(rand()%randLarge)-randLarge/2.0)/randLarge)*scale, + (((double)(rand()%randLarge)-randLarge/2.0)/randLarge)*scale); if (vectSelection[i]==labelRef){ for (auto f: currentPolysurf.verticesAroundFace(i)){ currentPolysurf.positions()[f][0] += pDep[0]; @@ -127,6 +125,7 @@ void noisify(double scale = 0.01){ addSurfaceInPolyscope(currentPolysurf); } + DGtal::Mesh meshFixVertexUnity(DGtal::Mesh &aMesh){ DGtal::Mesh res; @@ -141,7 +140,7 @@ meshFixVertexUnity(DGtal::Mesh &aMesh){ } } } - + std::vector translateIndexId; int currentIndex = 0; for(unsigned int i = 0; i < aMesh.nbVertex(); i++ ){ @@ -154,27 +153,20 @@ meshFixVertexUnity(DGtal::Mesh &aMesh){ } } vertexUsed = std::vector (aMesh.nbVertex(), false); - + for ( unsigned int f = 0; f< aMesh.nbFaces(); f++ ){ auto face = aMesh.getFace(f); for (unsigned int i = 0; i vertexUsed (currentPolysurf.nbVertices(), false); @@ -259,6 +251,16 @@ void callbackFaceID() { addSurfaceInPolyscope(currentPolysurf); } + ImGui::Separator(); + ImGui::Text("Polyscope interface:"); + + if (ImGui::Button("show ")) { + polyscope::options::buildGui=true; + } + ImGui::SameLine(); + if (ImGui::Button("hide")) { + polyscope::options::buildGui=false; + } ImGuiIO& io = ImGui::GetIO(); auto digsurf = polyscope::getSurfaceMesh("InputMesh"); @@ -266,8 +268,8 @@ void callbackFaceID() { unsigned long indexSelect = polyscope::pick::getSelection().second; unsigned long nb = 0; // face selected - if (indexSelect >= shiftFaceIndex){ - nb = (unsigned long) polyscope::pick::getSelection().second - shiftFaceIndex; + if (indexSelect >= currentPolysurf.nbVertices()){ + nb = (unsigned long) polyscope::pick::getSelection().second - currentPolysurf.nbVertices(); }else{ // vertex selected (selecting a face connected to it) if(currentPolysurf.facesAroundVertex(polyscope::pick::getSelection().second) @@ -300,10 +302,8 @@ void callbackFaceID() { int main(int argc, char** argv) { std::string inputFileName {""}; - - std::string colorFileName; // The file containing the index to be colored in the colors - + // parse command line using CLI ---------------------------------------------- CLI::App app; app.description("polyMeshEdit \n" @@ -313,24 +313,29 @@ int main(int argc, char** argv) ->check(CLI::ExistingFile); app.add_option("-o,--output,2", outputFileName, "an output mesh file in .obj or .off format." ) ->check(CLI::ExistingFile); - - + + app.get_formatter()->column_width(40); CLI11_PARSE(app, argc, argv); polyscope::init(); - + polyscope::options::programName = "PolyMeshEdit"; + polyscope::options::buildGui=false; // read input mesh DGtal::Mesh aMesh(true); aMesh << inputFileName; - aMesh = meshFixVertexUnity(aMesh); + aMesh.removeIsolatedVertices(); DGtal::MeshHelpers::mesh2PolygonalSurface(aMesh, currentPolysurf); - shiftFaceIndex = aMesh.nbVertex(); polyscope::state::userCallback = callbackFaceID; addSurfaceInPolyscope(currentPolysurf); firstPolysurf = currentPolysurf; polyscope::show(); - return 0; + } + + + + + From 2331691fa29321e971d4c2699187f3af9e89f449 Mon Sep 17 00:00:00 2001 From: Bertrand Kerautret Date: Tue, 14 Nov 2023 01:16:49 +0100 Subject: [PATCH 11/27] remove mesh clean from dgtal --- visualisation/polyMeshEdit.cpp | 48 +--------------------------------- 1 file changed, 1 insertion(+), 47 deletions(-) diff --git a/visualisation/polyMeshEdit.cpp b/visualisation/polyMeshEdit.cpp index 067b32d..2639ec7 100644 --- a/visualisation/polyMeshEdit.cpp +++ b/visualisation/polyMeshEdit.cpp @@ -125,46 +125,7 @@ void noisify(double scale = 0.01){ addSurfaceInPolyscope(currentPolysurf); } - -DGtal::Mesh -meshFixVertexUnity(DGtal::Mesh &aMesh){ - DGtal::Mesh res; - std::map mapPt; - std::vector vertexUsed (aMesh.nbVertex(), false); - for ( unsigned int f = 0; f< aMesh.nbFaces(); f++ ){ - auto face = aMesh.getFace(f); - for (unsigned int i = 0; i translateIndexId; - int currentIndex = 0; - for(unsigned int i = 0; i < aMesh.nbVertex(); i++ ){ - if (vertexUsed[i]){ - res.addVertex(aMesh.getVertex(i)); - translateIndexId.push_back(currentIndex); - currentIndex++; - }else{ - translateIndexId.push_back(-1); - } - } - vertexUsed = std::vector (aMesh.nbVertex(), false); - - for ( unsigned int f = 0; f< aMesh.nbFaces(); f++ ){ - auto face = aMesh.getFace(f); - for (unsigned int i = 0; i Date: Fri, 17 Nov 2023 14:36:05 +0100 Subject: [PATCH 12/27] edit indent and doc --- visualisation/polyMeshEdit.cpp | 170 +++++++++++++++++++++++++-------- 1 file changed, 130 insertions(+), 40 deletions(-) diff --git a/visualisation/polyMeshEdit.cpp b/visualisation/polyMeshEdit.cpp index 2639ec7..0b0f0ea 100644 --- a/visualisation/polyMeshEdit.cpp +++ b/visualisation/polyMeshEdit.cpp @@ -1,3 +1,34 @@ +/** + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 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 for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + **/ + +/** + * @file + * @ingroup visualisation + * @author Bertrand Kerautret (\c bertrand.kerautret@univ-lyon2.fr ) + * + * + * @date 2023/11/17 + * + * Source file of the tool polyMeshEdit + * + * This file is part of the DGtal library/DGtalTools-contrib Project. + */ + +/////////////////////////////////////////////////////////////////////////////// + #include #include #include @@ -13,9 +44,40 @@ #include "CLI11.hpp" - +/////////////////////////////////////////////////////////////////////////////// +using namespace std; using namespace DGtal; -using namespace Z3i; +/////////////////////////////////////////////////////////////////////////////// + + +/** + @page polyMeshEdit polyMeshEdit + + @brief Description of the tool... + + @b Usage: polyMeshEdit [input] + + @b Allowed @b options @b are : + + @code + -h [ --help ] display this message + -i [ --input ] arg an input file... + -p [ --parameter] arg a double parameter... + @endcode + + @b Example: + + @code + polyMeshEdit -i $DGtal/examples/samples/.... + @endcode + + @image html respolyMeshEdit.png "Example of result. " + + @see + @ref polyMeshEdit.cpp + + */ + typedef PolygonalSurface PolySurface; @@ -27,9 +89,8 @@ static float paintRad = 1.0; static float noiseLevel = 1.0; static int partialF = 1; static int randLarge = 100000; - -static const int labelSelect = 200; -static const int labelRef = 50; +static const int unselectFlag = 200; +static const int selectFlag = 50; static std::string outputFileName {"result.obj"}; @@ -40,7 +101,7 @@ void addSurfaceInPolyscope(PolySurface &psurf){ vectSelection.clear(); for(auto &face: psurf.allFaces()){ faces.push_back(psurf.verticesAroundFace( face )); - vectSelection.push_back(labelSelect); + vectSelection.push_back(unselectFlag); } auto digsurf = polyscope::registerSurfaceMesh("InputMesh", @@ -67,22 +128,29 @@ std::vector faceAround(PolySurface &polysurff, std::map fVisited; std::map vVisited; - for (auto const &v : polysurff.verticesAroundFace(faceId) ){ + for (auto const &v : polysurff.verticesAroundFace(faceId) ) + { q.push(v); } fVisited[faceId] = true; bool addNewFaces = true; - while (!q.empty() ) { + while (!q.empty() ) + { PolySurface::Vertex v = q.front(); q.pop(); auto listFace = polysurff.facesAroundVertex(v); - for (auto const & f : listFace){ - if (fVisited.count(f)==0){ + for (auto const & f : listFace) + { + if (fVisited.count(f)==0) + { if((getFaceBarycenter(polysurff, f) - - getFaceBarycenter(polysurff, faceId)).norm() < radius){ + getFaceBarycenter(polysurff, faceId)).norm() < radius) + { fVisited[f]=true; result.push_back(f); - for (auto const & v : polysurff.verticesAroundFace(f)){ - if (vVisited.count(v)==0){ + for (auto const & v : polysurff.verticesAroundFace(f)) + { + if (vVisited.count(v)==0) + { vVisited[v]=true; q.push(v); } @@ -95,14 +163,17 @@ std::vector faceAround(PolySurface &polysurff, return result; } /** - * Remove face from selectio with a probability of 1/selFreq + * Select faces from selection with a probability of 1/selFreq */ void partialSelect(int selFreq=1){ srand((unsigned) time(NULL)); - for ( unsigned int i = 0; i< currentPolysurf.nbFaces(); i++ ){ - if (vectSelection[i]==labelRef){ - if (rand()%selFreq==0){ - vectSelection[i]=labelSelect; + for ( unsigned int i = 0; i< currentPolysurf.nbFaces(); i++ ) + { + if (vectSelection[i]==selectFlag) + { + if (rand()%selFreq==0) + { + vectSelection[i]=unselectFlag; } } } @@ -110,12 +181,15 @@ void partialSelect(int selFreq=1){ void noisify(double scale = 0.01){ srand((unsigned) time(NULL)); - for ( unsigned int i = 0; i< currentPolysurf.nbFaces(); i++ ){ + for ( unsigned int i = 0; i< currentPolysurf.nbFaces(); i++ ) + { Z3i::RealPoint pDep((((double)(rand()%randLarge)-randLarge/2.0)/randLarge)*scale, (((double)(rand()%randLarge)-randLarge/2.0)/randLarge)*scale, (((double)(rand()%randLarge)-randLarge/2.0)/randLarge)*scale); - if (vectSelection[i]==labelRef){ - for (auto f: currentPolysurf.verticesAroundFace(i)){ + if (vectSelection[i]==selectFlag) + { + for (auto f: currentPolysurf.verticesAroundFace(i)) + { currentPolysurf.positions()[f][0] += pDep[0]; currentPolysurf.positions()[f][1] += pDep[1]; currentPolysurf.positions()[f][2] += pDep[2]; @@ -132,7 +206,7 @@ void deleteSelectedFaces(){ PolySurface newSur; std::vector vertexUsed (currentPolysurf.nbVertices(), false); for ( unsigned int i = 0; i< currentPolysurf.nbFaces(); i++ ){ - if (vectSelection[i]==labelSelect){ + if (vectSelection[i]==unselectFlag){ auto face = currentPolysurf.verticesAroundFace( i ); for (auto v: face){ vertexUsed[v] = true; @@ -156,7 +230,7 @@ void deleteSelectedFaces(){ } } for ( unsigned int f = 0; f< currentPolysurf.nbFaces(); f++ ){ - if (vectSelection[f]==labelSelect){ + if (vectSelection[f]==unselectFlag){ auto face = currentPolysurf.verticesAroundFace( f ); for (unsigned int i = 0; i= currentPolysurf.nbVertices()){ + if (indexSelect >= currentPolysurf.nbVertices()) + { nb = (unsigned long) polyscope::pick::getSelection().second - currentPolysurf.nbVertices(); - }else{ + } + else + { // vertex selected (selecting a face connected to it) if(currentPolysurf.facesAroundVertex(polyscope::pick::getSelection().second) .size()> 0){ @@ -243,11 +329,15 @@ void callbackFaceID() { auto fVois = faceAround(currentPolysurf, nb, paintRad); vectSelection[nb] = 0; srand((unsigned) time(NULL)); - for (auto f: fVois){ - if (rand()%partialF==0){ - vectSelection[f]=labelRef; - }else{ - vectSelection[f]=labelSelect; + for (auto f: fVois) + { + if (rand()%partialF==0) + { + vectSelection[f]=selectFlag; + } + else + { + vectSelection[f]=unselectFlag; } } } From 2b40e6ed5d8000c18d618bdd5e8577747a192ca7 Mon Sep 17 00:00:00 2001 From: Bertrand Kerautret Date: Fri, 17 Nov 2023 17:31:55 +0100 Subject: [PATCH 13/27] description and doc --- visualisation/polyMeshEdit.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/visualisation/polyMeshEdit.cpp b/visualisation/polyMeshEdit.cpp index 0b0f0ea..db17402 100644 --- a/visualisation/polyMeshEdit.cpp +++ b/visualisation/polyMeshEdit.cpp @@ -53,7 +53,7 @@ using namespace DGtal; /** @page polyMeshEdit polyMeshEdit - @brief Description of the tool... + @brief polyMeshEdit tools to edit a mesh (add local noise remove selected faces). Note that the process rely on half edge data structure that can fails if the input is not topological consistant. If you want use other type of mesh, you can use meshViewerEdit that is based on the simple soup of triangles process (slower selection process). @b Usage: polyMeshEdit [input] @@ -353,16 +353,15 @@ void callbackFaceID() { int main(int argc, char** argv) { std::string inputFileName {""}; - std::string colorFileName; // The file containing the index to be colored in the colors // parse command line using CLI ---------------------------------------------- CLI::App app; - app.description("polyMeshEdit \n" - " polyMeshEdit -i file.obj \n"); + app.description("polyMeshEdit tools to edit a mesh (add local noise remove selected faces). Note that the process rely on half edge data structure that can fails if the input is not topological consistant. If you want use other type of mesh, you can use meshViewerEdit that is based on the simple soup of triangles process (slower selection process). \n" + " polyMeshEdit file.obj editedMesh.obj \n"); app.add_option("-i,--input,1", inputFileName, "an input mesh file in .obj or .off format." ) ->required() ->check(CLI::ExistingFile); - app.add_option("-o,--output,2", outputFileName, "an output mesh file in .obj or .off format." ) + app.add_option("-o,--output,2", outputFileName, "an output mesh file in .obj or .off format.", true ) ->check(CLI::ExistingFile); @@ -379,6 +378,7 @@ int main(int argc, char** argv) polyscope::state::userCallback = callbackFaceID; addSurfaceInPolyscope(currentPolysurf); firstPolysurf = currentPolysurf; + polyscope::options::buildGui=false; polyscope::show(); return 0; From 60609661a1d93b8b2f8b6ca1920522384b1c64c2 Mon Sep 17 00:00:00 2001 From: Bertrand Kerautret Date: Fri, 17 Nov 2023 17:34:55 +0100 Subject: [PATCH 14/27] changelog and edit --- ChangeLog.md | 8 ++++++-- README.md | 1 + visualisation/polyMeshEdit.cpp | 2 +- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/ChangeLog.md b/ChangeLog.md index 0e185e1..45ae31d 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -15,8 +15,12 @@ - *Geometry3d* - basicMorphoFilter: fix a bug on the dilate/erode options. (Bertrand Kerautret [#74](https://github.com/DGtal-team/DGtalTools-contrib/pull/74)) - - # DGtalTools-contrib 1.3 + - *visualisation* + - polyMeshEdit: tool to edit a mesh (add local noise remove selected faces). + (Bertrand Kerautret [#78](https://github.com/DGtal-team/DGtalTools-contrib/pull/78)) + + +# DGtalTools-contrib 1.3 - *global* - Continuous integration does not use Travis anymore but Github Actions. diff --git a/README.md b/README.md index ce9b6ae..e07b65f 100644 --- a/README.md +++ b/README.md @@ -91,6 +91,7 @@ This section, can contain all tools related to visualisation: - displayTgtCoverAlphaTS: to display alpha-thick segment given on a simple contour. - meshViewerEdit: tool to visualize a mesh and to apply simple edits (face removal, color edits...). - graphViewer: tool to display graphs from a list of edges, a list of vertex and an optionnal list of radius for each edge. + - polyMeshEdit: tool to edit a mesh (add local noise remove selected faces). |![](https://cloud.githubusercontent.com/assets/772865/12538777/cd8c2d28-c2e2-11e5-93ab-cb4a6cfadc8e.png)| ![](https://cloud.githubusercontent.com/assets/772865/12523276/22205f46-c156-11e5-827d-ec788baf7029.png) |capture d ecran 2016-03-04 a 19 46 54| diff --git a/visualisation/polyMeshEdit.cpp b/visualisation/polyMeshEdit.cpp index db17402..094bf6f 100644 --- a/visualisation/polyMeshEdit.cpp +++ b/visualisation/polyMeshEdit.cpp @@ -356,7 +356,7 @@ int main(int argc, char** argv) // parse command line using CLI ---------------------------------------------- CLI::App app; - app.description("polyMeshEdit tools to edit a mesh (add local noise remove selected faces). Note that the process rely on half edge data structure that can fails if the input is not topological consistant. If you want use other type of mesh, you can use meshViewerEdit that is based on the simple soup of triangles process (slower selection process). \n" + app.description("polyMeshEdit tool to edit a mesh (add local noise remove selected faces). Note that the process rely on half edge data structure that can fails if the input is not topological consistant. If you want use other type of mesh, you can use meshViewerEdit that is based on the simple soup of triangles process (slower selection process). \n" " polyMeshEdit file.obj editedMesh.obj \n"); app.add_option("-i,--input,1", inputFileName, "an input mesh file in .obj or .off format." ) ->required() From 0f10efe5f91b625e15739c2054344d1843ac0337 Mon Sep 17 00:00:00 2001 From: Bertrand Kerautret Date: Fri, 17 Nov 2023 17:50:59 +0100 Subject: [PATCH 15/27] readme --- README.md | 3 +++ visualisation/polyMeshEdit.cpp | 3 ++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index e07b65f..3cd2325 100644 --- a/README.md +++ b/README.md @@ -97,3 +97,6 @@ This section, can contain all tools related to visualisation: |![](https://cloud.githubusercontent.com/assets/772865/12538777/cd8c2d28-c2e2-11e5-93ab-cb4a6cfadc8e.png)| ![](https://cloud.githubusercontent.com/assets/772865/12523276/22205f46-c156-11e5-827d-ec788baf7029.png) |capture d ecran 2016-03-04 a 19 46 54| | :-: | :-: | :-: | |displayTgtCoverAlphaTS|meshViewerEdit|graphViewer| +|![](![Capture d’écran 2023-11-17 à 17 47 26](https://github.com/DGtal-team/DGtalTools-contrib/assets/772865/5da7e052-d332-4c1e-95bd-bfd06d4cd1e7))| | | +| :-: | :-: | :-: | +|polyMeshEdit | || diff --git a/visualisation/polyMeshEdit.cpp b/visualisation/polyMeshEdit.cpp index 094bf6f..cd3bcc5 100644 --- a/visualisation/polyMeshEdit.cpp +++ b/visualisation/polyMeshEdit.cpp @@ -245,7 +245,7 @@ void deleteSelectedFaces(){ void callbackFaceID() { srand((unsigned) time(NULL)); - + ImGui::Begin("Editing tools"); ImGui::Text("Setting selection size:"); ImGui::SliderFloat("radius values", &paintRad, 0.01f, 10.0f, "size = %.3f"); @@ -342,6 +342,7 @@ void callbackFaceID() { } } } + ImGui::End(); digsurf -> removeQuantity("selection"); digsurf -> addFaceScalarQuantity("selection", vectSelection); } From 3c12b0c46b798ebebe140e3656281b2d3821e4b5 Mon Sep 17 00:00:00 2001 From: Bertrand Kerautret Date: Fri, 17 Nov 2023 23:04:18 +0100 Subject: [PATCH 16/27] github action --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 1add0a7..b19c196 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -29,7 +29,7 @@ jobs: if: matrix.os == 'ubuntu-latest' run: | sudo apt-get update - sudo apt-get install libqglviewer-dev-qt5 libboost-dev libeigen3-dev ninja-build libhdf5-serial-dev libboost-dev libcairo2-dev libgmp-dev libgraphicsmagick++1-dev libfftw3-dev + sudo apt-get install libqglviewer-dev-qt5 libboost-dev libeigen3-dev ninja-build libhdf5-serial-dev libboost-dev libcairo2-dev libgmp-dev libgraphicsmagick++1-dev libfftw3-dev xorg-dev libglu1-mesa-dev freeglut3-dev mesa-common-dev - name: Install macOS deps if: matrix.os == 'macOS-latest' From 72a6a2554d15346fd6ef089c31528024b4f6886b Mon Sep 17 00:00:00 2001 From: Bertrand Kerautret Date: Fri, 17 Nov 2023 23:55:31 +0100 Subject: [PATCH 17/27] github action windows --- visualisation/polyMeshEdit.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/visualisation/polyMeshEdit.cpp b/visualisation/polyMeshEdit.cpp index cd3bcc5..06c73e4 100644 --- a/visualisation/polyMeshEdit.cpp +++ b/visualisation/polyMeshEdit.cpp @@ -28,6 +28,7 @@ */ /////////////////////////////////////////////////////////////////////////////// +#define STB_IMAGE_IMPLEMENTATION #include #include From c60a1b36228dc443d9114e4eba2888b769c3182f Mon Sep 17 00:00:00 2001 From: Bertrand Kerautret Date: Sat, 18 Nov 2023 12:31:53 +0100 Subject: [PATCH 18/27] stbimage windows fix --- visualisation/polyMeshEdit.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/visualisation/polyMeshEdit.cpp b/visualisation/polyMeshEdit.cpp index 06c73e4..527f869 100644 --- a/visualisation/polyMeshEdit.cpp +++ b/visualisation/polyMeshEdit.cpp @@ -28,8 +28,7 @@ */ /////////////////////////////////////////////////////////////////////////////// -#define STB_IMAGE_IMPLEMENTATION - +#define NO_ADD_STBIMAGE_IMPLEMENT #include #include #include From 85a82c96d3e988cfacc808262b969f57aef43713 Mon Sep 17 00:00:00 2001 From: Bertrand Kerautret Date: Sat, 18 Nov 2023 12:52:49 +0100 Subject: [PATCH 19/27] param and doc --- visualisation/polyMeshEdit.cpp | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/visualisation/polyMeshEdit.cpp b/visualisation/polyMeshEdit.cpp index 527f869..a54d87a 100644 --- a/visualisation/polyMeshEdit.cpp +++ b/visualisation/polyMeshEdit.cpp @@ -28,7 +28,7 @@ */ /////////////////////////////////////////////////////////////////////////////// -#define NO_ADD_STBIMAGE_IMPLEMENT +#define NO_ADD_STBIMAGE_IMPLEMENT //To avoid duplicated linking errors (like LNK2005 in MSVC) #include #include #include @@ -55,20 +55,28 @@ using namespace DGtal; @brief polyMeshEdit tools to edit a mesh (add local noise remove selected faces). Note that the process rely on half edge data structure that can fails if the input is not topological consistant. If you want use other type of mesh, you can use meshViewerEdit that is based on the simple soup of triangles process (slower selection process). - @b Usage: polyMeshEdit [input] + @b Usage: polyMeshEdit [OPTIONS] 1 [2] + @b Allowed @b options @b are : @code - -h [ --help ] display this message - -i [ --input ] arg an input file... - -p [ --parameter] arg a double parameter... + + Positionals: + 1 TEXT:FILE REQUIRED an input mesh file in .obj or .off format. + 2 TEXT:FILE=result.obj an output mesh file in .obj or .off format. + + + Options: + -h,--help Print this help message and exit + -i,--input TEXT:FILE REQUIRED an input mesh file in .obj or .off format. + -o,--output TEXT:FILE=result.obj an output mesh file in .obj or .off format. @endcode @b Example: @code - polyMeshEdit -i $DGtal/examples/samples/.... + polyMeshEdit $DGtal/examples/samples/bunnyhead.obj bunnyEdited.obj @endcode @image html respolyMeshEdit.png "Example of result. " @@ -358,12 +366,11 @@ int main(int argc, char** argv) // parse command line using CLI ---------------------------------------------- CLI::App app; app.description("polyMeshEdit tool to edit a mesh (add local noise remove selected faces). Note that the process rely on half edge data structure that can fails if the input is not topological consistant. If you want use other type of mesh, you can use meshViewerEdit that is based on the simple soup of triangles process (slower selection process). \n" - " polyMeshEdit file.obj editedMesh.obj \n"); + " polyMeshEdit $DGtal/examples/samples/bunnyhead.obj bunnyEdited.obj \n"); app.add_option("-i,--input,1", inputFileName, "an input mesh file in .obj or .off format." ) ->required() ->check(CLI::ExistingFile); - app.add_option("-o,--output,2", outputFileName, "an output mesh file in .obj or .off format.", true ) - ->check(CLI::ExistingFile); + app.add_option("-o,--output,2", outputFileName, "an output mesh file in .obj or .off format.", true ); app.get_formatter()->column_width(40); From a25abbd6c82f7c961939d2d605f9c8e8d9fe01c6 Mon Sep 17 00:00:00 2001 From: Bertrand Kerautret Date: Sun, 19 Nov 2023 00:48:04 +0100 Subject: [PATCH 20/27] improve selection --- visualisation/polyMeshEdit.cpp | 34 ++++++++++++++++++++++------------ 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/visualisation/polyMeshEdit.cpp b/visualisation/polyMeshEdit.cpp index a54d87a..486da0b 100644 --- a/visualisation/polyMeshEdit.cpp +++ b/visualisation/polyMeshEdit.cpp @@ -99,9 +99,18 @@ static int partialF = 1; static int randLarge = 100000; static const int unselectFlag = 200; static const int selectFlag = 50; +static const int cursorFlag = 1; static std::string outputFileName {"result.obj"}; +void updateSelection(){ + polyscope::removeStructure("selection"); + auto digsurf = polyscope::getSurfaceMesh("InputMesh"); + digsurf->addFaceScalarQuantity("selection", vectSelection) + ->setMapRange(std::pair{cursorFlag,unselectFlag}); + digsurf->setAllQuantitiesEnabled(true); +} + void addSurfaceInPolyscope(PolySurface &psurf){ polyscope::removeStructure("InputMesh"); @@ -111,24 +120,22 @@ void addSurfaceInPolyscope(PolySurface &psurf){ faces.push_back(psurf.verticesAroundFace( face )); vectSelection.push_back(unselectFlag); } - auto digsurf = polyscope::registerSurfaceMesh("InputMesh", psurf.positions(), faces); - digsurf->addFaceScalarQuantity("selection", vectSelection); - digsurf->setAllQuantitiesEnabled(true); + updateSelection(); } static Z3i::RealPoint -getFaceBarycenter(PolySurface &polysurff, const PolySurface::Face &aFace){ +getFaceBarycenter(const PolySurface &polysurff, const PolySurface::Face &aFace) { Z3i::RealPoint res(0.0, 0.0, 0.0); for(auto const &v: polysurff.verticesAroundFace(aFace)){ - res += polysurff.positions()[v]; + res += polysurff.position(v); } return res/polysurff.verticesAroundFace(aFace).size(); } // Helper function -std::vector faceAround(PolySurface &polysurff, +std::vector faceAround(const PolySurface &polysurff, PolySurface::Face faceId, double radius){ std::vector result; @@ -182,7 +189,12 @@ void partialSelect(int selFreq=1){ if (rand()%selFreq==0) { vectSelection[i]=unselectFlag; + }else + { + vectSelection[i]=selectFlag; } + }else{ + vectSelection[i]=unselectFlag; } } } @@ -332,10 +344,10 @@ void callbackFaceID() { nb = currentPolysurf.facesAroundVertex(polyscope::pick::getSelection().second)[0]; } } - + if (nb > 0 && nb < vectSelection.size()){ auto fVois = faceAround(currentPolysurf, nb, paintRad); - vectSelection[nb] = 0; + vectSelection[nb] = cursorFlag; srand((unsigned) time(NULL)); for (auto f: fVois) { @@ -351,8 +363,7 @@ void callbackFaceID() { } } ImGui::End(); - digsurf -> removeQuantity("selection"); - digsurf -> addFaceScalarQuantity("selection", vectSelection); + updateSelection(); } @@ -375,8 +386,8 @@ int main(int argc, char** argv) app.get_formatter()->column_width(40); CLI11_PARSE(app, argc, argv); + polyscope::options::programName = "PolyMeshEdit - (DGtalToolsContrib)"; polyscope::init(); - polyscope::options::programName = "PolyMeshEdit"; polyscope::options::buildGui=false; // read input mesh DGtal::Mesh aMesh(true); @@ -386,7 +397,6 @@ int main(int argc, char** argv) polyscope::state::userCallback = callbackFaceID; addSurfaceInPolyscope(currentPolysurf); firstPolysurf = currentPolysurf; - polyscope::options::buildGui=false; polyscope::show(); return 0; From 8388f7852880a5e13bd446ddbdc4622ef4dac037 Mon Sep 17 00:00:00 2001 From: Bertrand Kerautret Date: Sun, 19 Nov 2023 01:16:06 +0100 Subject: [PATCH 21/27] noise scale auto --- visualisation/polyMeshEdit.cpp | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/visualisation/polyMeshEdit.cpp b/visualisation/polyMeshEdit.cpp index 486da0b..4c34c75 100644 --- a/visualisation/polyMeshEdit.cpp +++ b/visualisation/polyMeshEdit.cpp @@ -93,6 +93,12 @@ static PolySurface currentPolysurf; static PolySurface firstPolysurf; static std::vector vectSelection; +static float minPaintRad = 1.0; +static float maxPaintRad = 100.0; +static float minNoiseLevel = 1.0; +static float maxNoiseLevel = 100.0; + + static float paintRad = 1.0; static float noiseLevel = 1.0; static int partialF = 1; @@ -101,6 +107,7 @@ static const int unselectFlag = 200; static const int selectFlag = 50; static const int cursorFlag = 1; + static std::string outputFileName {"result.obj"}; void updateSelection(){ @@ -267,15 +274,13 @@ void callbackFaceID() { srand((unsigned) time(NULL)); ImGui::Begin("Editing tools"); ImGui::Text("Setting selection size:"); - ImGui::SliderFloat("radius values", &paintRad, 0.01f, 10.0f, "size = %.3f"); - + ImGui::SliderFloat("radius values", &paintRad, minPaintRad, maxPaintRad, "size = %.3f"); ImGui::Separator(); - ImGui::Text("Set selection freq:"); ImGui::SliderInt(" freq (1=select all, 2=select 1over2)", &partialF, 1, 10, "freq = %i"); ImGui::Separator(); ImGui::Text("Noise parameters:"); - ImGui::SliderFloat("noise scale", &noiseLevel, 0.001, 2, "scale = %f"); + ImGui::SliderFloat("noise scale", &noiseLevel, minNoiseLevel, maxNoiseLevel, "scale = %f"); ImGui::Separator(); ImGui::Text("Action:"); @@ -393,6 +398,14 @@ int main(int argc, char** argv) DGtal::Mesh aMesh(true); aMesh << inputFileName; aMesh.removeIsolatedVertices(); + auto bb = aMesh.getBoundingBox(); + minPaintRad = (bb.second - bb.first).norm()/1000.0; + maxPaintRad = (bb.second - bb.first).norm()/2.0; + minNoiseLevel = (bb.second - bb.first).norm()/10000.0; + maxNoiseLevel = (bb.second - bb.first).norm()/100.0; + noiseLevel = (bb.second - bb.first).norm()/1000.0; + + paintRad = (bb.second - bb.first).norm()/50.0; DGtal::MeshHelpers::mesh2PolygonalSurface(aMesh, currentPolysurf); polyscope::state::userCallback = callbackFaceID; addSurfaceInPolyscope(currentPolysurf); From 5e6c7d31f67c24e311412135b7669d546841a75b Mon Sep 17 00:00:00 2001 From: Bertrand Kerautret Date: Sun, 19 Nov 2023 12:03:19 +0100 Subject: [PATCH 22/27] minor edit --- visualisation/polyMeshEdit.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/visualisation/polyMeshEdit.cpp b/visualisation/polyMeshEdit.cpp index 4c34c75..0ccb456 100644 --- a/visualisation/polyMeshEdit.cpp +++ b/visualisation/polyMeshEdit.cpp @@ -226,7 +226,6 @@ void noisify(double scale = 0.01){ addSurfaceInPolyscope(currentPolysurf); } - void deleteSelectedFaces(){ @@ -345,7 +344,8 @@ void callbackFaceID() { { // vertex selected (selecting a face connected to it) if(currentPolysurf.facesAroundVertex(polyscope::pick::getSelection().second) - .size()> 0){ + .size()> 0) + { nb = currentPolysurf.facesAroundVertex(polyscope::pick::getSelection().second)[0]; } } @@ -399,13 +399,14 @@ int main(int argc, char** argv) aMesh << inputFileName; aMesh.removeIsolatedVertices(); auto bb = aMesh.getBoundingBox(); + // Setting scale mesh dependant parameters minPaintRad = (bb.second - bb.first).norm()/1000.0; maxPaintRad = (bb.second - bb.first).norm()/2.0; minNoiseLevel = (bb.second - bb.first).norm()/10000.0; maxNoiseLevel = (bb.second - bb.first).norm()/100.0; noiseLevel = (bb.second - bb.first).norm()/1000.0; - paintRad = (bb.second - bb.first).norm()/50.0; + DGtal::MeshHelpers::mesh2PolygonalSurface(aMesh, currentPolysurf); polyscope::state::userCallback = callbackFaceID; addSurfaceInPolyscope(currentPolysurf); From 90c7c01525092877d025991941013d4133a736c3 Mon Sep 17 00:00:00 2001 From: Bertrand Kerautret Date: Sat, 23 Dec 2023 00:32:53 +0100 Subject: [PATCH 23/27] Update ChangeLog.md Co-authored-by: David Coeurjolly --- ChangeLog.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ChangeLog.md b/ChangeLog.md index 45ae31d..1aadf09 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -16,7 +16,7 @@ - basicMorphoFilter: fix a bug on the dilate/erode options. (Bertrand Kerautret [#74](https://github.com/DGtal-team/DGtalTools-contrib/pull/74)) - *visualisation* - - polyMeshEdit: tool to edit a mesh (add local noise remove selected faces). + - polyMeshEdit: tool to edit a mesh (add local noise, remove selected faces). (Bertrand Kerautret [#78](https://github.com/DGtal-team/DGtalTools-contrib/pull/78)) From e9bb998b4cecff2df7a609f1005ef04eeef139db Mon Sep 17 00:00:00 2001 From: Bertrand Kerautret Date: Sat, 23 Dec 2023 00:33:15 +0100 Subject: [PATCH 24/27] Update visualisation/polyMeshEdit.cpp thanks ;) Co-authored-by: David Coeurjolly --- visualisation/polyMeshEdit.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/visualisation/polyMeshEdit.cpp b/visualisation/polyMeshEdit.cpp index 0ccb456..77fb9bd 100644 --- a/visualisation/polyMeshEdit.cpp +++ b/visualisation/polyMeshEdit.cpp @@ -53,7 +53,7 @@ using namespace DGtal; /** @page polyMeshEdit polyMeshEdit - @brief polyMeshEdit tools to edit a mesh (add local noise remove selected faces). Note that the process rely on half edge data structure that can fails if the input is not topological consistant. If you want use other type of mesh, you can use meshViewerEdit that is based on the simple soup of triangles process (slower selection process). + @brief polyMeshEdit tools to edit a mesh (add local noise and remove selected faces). Note that the process relies on the halfedge data structure that can fail if the input is not topologically consistant. If you want use other type of mesh, you can use meshViewerEdit that is based on the simple soup of triangles process (slower selection process). @b Usage: polyMeshEdit [OPTIONS] 1 [2] From ca6299ea63713be81381c50c8079cc163e183823 Mon Sep 17 00:00:00 2001 From: Bertrand Kerautret Date: Sat, 23 Dec 2023 00:36:41 +0100 Subject: [PATCH 25/27] Update README.md Co-authored-by: David Coeurjolly --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3cd2325..329e01e 100644 --- a/README.md +++ b/README.md @@ -91,7 +91,7 @@ This section, can contain all tools related to visualisation: - displayTgtCoverAlphaTS: to display alpha-thick segment given on a simple contour. - meshViewerEdit: tool to visualize a mesh and to apply simple edits (face removal, color edits...). - graphViewer: tool to display graphs from a list of edges, a list of vertex and an optionnal list of radius for each edge. - - polyMeshEdit: tool to edit a mesh (add local noise remove selected faces). + - polyMeshEdit: tool to edit a mesh (add local noise, remove selected faces). |![](https://cloud.githubusercontent.com/assets/772865/12538777/cd8c2d28-c2e2-11e5-93ab-cb4a6cfadc8e.png)| ![](https://cloud.githubusercontent.com/assets/772865/12523276/22205f46-c156-11e5-827d-ec788baf7029.png) |capture d ecran 2016-03-04 a 19 46 54| From 99d5bd17e045a7866aac8b9f24d02207916863d1 Mon Sep 17 00:00:00 2001 From: Bertrand Kerautret Date: Sat, 23 Dec 2023 00:36:48 +0100 Subject: [PATCH 26/27] Update visualisation/polyMeshEdit.cpp Co-authored-by: David Coeurjolly --- visualisation/polyMeshEdit.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/visualisation/polyMeshEdit.cpp b/visualisation/polyMeshEdit.cpp index 77fb9bd..df71b3c 100644 --- a/visualisation/polyMeshEdit.cpp +++ b/visualisation/polyMeshEdit.cpp @@ -381,7 +381,7 @@ int main(int argc, char** argv) // parse command line using CLI ---------------------------------------------- CLI::App app; - app.description("polyMeshEdit tool to edit a mesh (add local noise remove selected faces). Note that the process rely on half edge data structure that can fails if the input is not topological consistant. If you want use other type of mesh, you can use meshViewerEdit that is based on the simple soup of triangles process (slower selection process). \n" + app.description("polyMeshEdit tool to edit a mesh (add local noise and remove selected faces). Note that the process relies on the halfedge data structure that can fail if the input is not topologically consistant. If you want use other type of mesh, you can use meshViewerEdit that is based on the simple soup of triangles process (slower selection process). \n" " polyMeshEdit $DGtal/examples/samples/bunnyhead.obj bunnyEdited.obj \n"); app.add_option("-i,--input,1", inputFileName, "an input mesh file in .obj or .off format." ) ->required() From 28d4d952b929cbee0dc9db86c725d344193d13f3 Mon Sep 17 00:00:00 2001 From: Bertrand Kerautret Date: Sat, 23 Dec 2023 10:59:28 +0100 Subject: [PATCH 27/27] Update README.md --- README.md | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 329e01e..dc3ebaf 100644 --- a/README.md +++ b/README.md @@ -93,10 +93,21 @@ This section, can contain all tools related to visualisation: - graphViewer: tool to display graphs from a list of edges, a list of vertex and an optionnal list of radius for each edge. - polyMeshEdit: tool to edit a mesh (add local noise, remove selected faces). - -|![](https://cloud.githubusercontent.com/assets/772865/12538777/cd8c2d28-c2e2-11e5-93ab-cb4a6cfadc8e.png)| ![](https://cloud.githubusercontent.com/assets/772865/12523276/22205f46-c156-11e5-827d-ec788baf7029.png) |capture d ecran 2016-03-04 a 19 46 54| -| :-: | :-: | :-: | -|displayTgtCoverAlphaTS|meshViewerEdit|graphViewer| -|![](![Capture d’écran 2023-11-17 à 17 47 26](https://github.com/DGtal-team/DGtalTools-contrib/assets/772865/5da7e052-d332-4c1e-95bd-bfd06d4cd1e7))| | | -| :-: | :-: | :-: | -|polyMeshEdit | || + + + + + + + + + + + + + + + + + +
displayTgtCoverAlphaTSmeshViewerEditgraphViewer
polyMeshEdit