diff --git a/.gitignore b/.gitignore index 6f31401f787928dc3bb3e2622578f889336d1d92..e2cada25c8d93d46f14f0c8dee5e054448782189 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ build/ .vscode/ +obj/ \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index f1e000179f2f10b09282afceaa17117670207e5b..b02cc5f987538c917e7339b21aef2cfb67bea464 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,7 +7,7 @@ set(CMAKE_CXX_STANDARD 11) find_package(TTKVTK REQUIRED) -add_executable(projet-stage main.cpp) +add_executable(projet-stage main.cpp isTriangulate.cpp) target_link_libraries(projet-stage PUBLIC diff --git a/isTriangulate.cpp b/isTriangulate.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9e0a153a297f617b0b578a3bdf2705ddbde2ed46 --- /dev/null +++ b/isTriangulate.cpp @@ -0,0 +1,35 @@ +#include <vtkTriangleFilter.h> +#include "isTriangulate.h" + +// Fonction pour construire une triangulation valide à partir d'un vtkPolyData contenant des quadrilatères +vtkSmartPointer<vtkPolyData> triangulate::buildValidTriangulation(vtkSmartPointer<vtkPolyData> polyData) +{ + vtkSmartPointer<vtkPolyData> triPolyData = vtkSmartPointer<vtkPolyData>::New(); + + // Si le maillage en entrée est composé de quadrilatères, on construit une triangulation valide + if (polyData->GetMaxCellSize() > 3) + { + std::cout << "maillage composé de quads"; + // On utilise un filtre vtkQuadToTriangle pour convertir les quadrilatères en triangles + vtkSmartPointer<vtkTriangleFilter> quadToTri = vtkSmartPointer<vtkTriangleFilter>::New(); + quadToTri->SetInputData(polyData); + quadToTri->Update(); + + triPolyData = quadToTri->GetOutput(); + } + else if (polyData->GetMaxCellSize() == 3) // Si le maillage en entrée est déjà triangulé, on renvoie le vtkPolyData d'origine + { + triPolyData = polyData; + } + else + { + std::cout << "Ce maillage n'est pas géré par ce programme, sont acceptés les maillages triangulés et quadrilatérisés"; + } + + // On ajoute un filtre vtkTriangleFilter pour garantir que la sortie est bien un maillage triangulé + vtkSmartPointer<vtkTriangleFilter> triangleFilter = vtkSmartPointer<vtkTriangleFilter>::New(); + triangleFilter->SetInputData(triPolyData); + triangleFilter->Update(); + + return triangleFilter->GetOutput(); +} \ No newline at end of file diff --git a/isTriangulate.h b/isTriangulate.h new file mode 100644 index 0000000000000000000000000000000000000000..0c25de8e766454d17bba159d95f54888efb07552 --- /dev/null +++ b/isTriangulate.h @@ -0,0 +1,9 @@ +#ifndef IS_TRIANGULATE_H // Vérification d'inclusion multiple +#define IS_TRIANGULATE_H + +namespace triangulate +{ + vtkSmartPointer<vtkPolyData> buildValidTriangulation(vtkSmartPointer<vtkPolyData> polyData); // Prototype de la fonction +} + +#endif // Fin de vérification d'inclusion multiple diff --git a/main.cpp b/main.cpp index 889dd4c3b6ff5cad68f18874b1bfb641f1b46034..057a5371a996aa16ab22b4041c30677f535e1747 100644 --- a/main.cpp +++ b/main.cpp @@ -32,13 +32,16 @@ #include <vtkExtractSurface.h> #include <ttkGeometrySmoother.h> - #include <vtkDataSetSurfaceFilter.h> #include <ttkUtils.h> #include <vtkThresholdPoints.h> #include <vtkAppendPolyData.h> #include <vtkSortDataArray.h> -int main(int argc, char* argv[]) { + +#include "isTriangulate.h" + +int main(int argc, char *argv[]) +{ if (argc != 2) { std::cout << "Required arguments: Filename(.obj)" << std::endl; @@ -48,128 +51,127 @@ int main(int argc, char* argv[]) { // Read the input file std::string filename = argv[1]; vtkSmartPointer<vtkPolyData> source; - + std::string extension = vtksys::SystemTools::GetFilenameLastExtension(filename); std::transform(extension.begin(), extension.end(), extension.begin(), ::tolower); - - if(extension == ".obj") + + if (extension == ".obj") { vtkNew<vtkOBJReader> reader; reader->SetFileName(filename.c_str()); reader->Update(); - source = reader->GetOutput(); + + source = triangulate::buildValidTriangulation(reader->GetOutput()); } else { std::cout << "Required arguments: Filename(.obj)" << std::endl; return EXIT_FAILURE; } - - // Compute Max and Min curvature + + // Compute Max and Min curvature vtkSmartPointer<vtkCurvatures> maxCurvaturesFilter = vtkSmartPointer<vtkCurvatures>::New(); maxCurvaturesFilter->SetInputData(source); maxCurvaturesFilter->SetCurvatureTypeToMaximum(); // Set curvature type to maximum (k1) maxCurvaturesFilter->Update(); - auto k1 = maxCurvaturesFilter->GetOutput(); - + auto k1 = maxCurvaturesFilter->GetOutput(); + vtkSmartPointer<vtkCurvatures> minCurvaturesFilter = vtkSmartPointer<vtkCurvatures>::New(); minCurvaturesFilter->SetInputData(source); minCurvaturesFilter->SetCurvatureTypeToMinimum(); // Set curvature type to minimum (k2) minCurvaturesFilter->Update(); auto k2 = minCurvaturesFilter->GetOutput(); - - - // Shape Index computation + + // Shape Index computation k1->GetPointData()->SetActiveScalars("Maximum_Curvature"); - auto k1Array = k1->GetPointData()->GetAbstractArray("Maximum_Curvature"); + auto k1Array = k1->GetPointData()->GetAbstractArray("Maximum_Curvature"); k2->GetPointData()->SetActiveScalars("Minimum_Curvature"); - auto k2Array = k2->GetPointData()->GetAbstractArray("Minimum_Curvature"); - + auto k2Array = k2->GetPointData()->GetAbstractArray("Minimum_Curvature"); + vtkNew<vtkDoubleArray> shapeIndex; shapeIndex->SetName("Shape_Index"); - + for (vtkIdType i = 0; i < k1->GetNumberOfPoints(); ++i) - { + { double kmax = k1Array->GetVariantValue(i).ToDouble(); double kmin = k2Array->GetVariantValue(i).ToDouble(); - - if( kmax == kmin) + + if (kmax == kmin) { - shapeIndex->InsertNextTuple1(0.5); + shapeIndex->InsertNextTuple1(0.5); } else { - //double si = (2/M_PI)*atan((kmin+kmax)/(kmin-kmax)); //KOENDERIK ET VAN DOORN [-1,1] - double si = 0.5 - (1/M_PI)*atan((kmax+kmin)/(kmin-kmax)); // [0, 1] - + // double si = (2/M_PI)*atan((kmin+kmax)/(kmin-kmax)); //KOENDERIK ET VAN DOORN [-1,1] + double si = 0.5 - (1 / M_PI) * atan((kmax + kmin) / (kmin - kmax)); // [0, 1] + shapeIndex->InsertNextTuple1(si); } } source->GetPointData()->AddArray(shapeIndex); source->GetPointData()->SetActiveScalars("Shape_Index"); - -/* - double pourcent = 0.8; - - // Create a vtkThresholdPoints filter for each threshold value - vtkNew<vtkThresholdPoints> threshold1; - threshold1->SetInputData(source); - threshold1->ThresholdBetween(0.0, 0.0 + pourcent*0.25); // Scalar values near 0 - threshold1->Update(); - - vtkNew<vtkThresholdPoints> threshold2; - threshold2->SetInputData(source); - threshold2->ThresholdBetween(0.5 - pourcent*0.25, 0.5 + pourcent*0.25); // Scalar values near 1 - threshold2->Update(); - - vtkNew<vtkThresholdPoints> threshold3; - threshold3->SetInputData(source); - threshold3->ThresholdBetween(1.0 - pourcent*0.25, 1.0); // Scalar values near 1 - threshold3->Update(); - - // Create a vtkFTRGraph for each thresholded dataset - vtkNew<ttkFTRGraph> graph1; - graph1->SetInputData(threshold1->GetOutput()); - graph1->SetInputArrayToProcess(0, 0, 0, vtkDataObject::FIELD_ASSOCIATION_POINTS, "Shape_Index"); - graph1->Update(); - - vtkNew<ttkFTRGraph> graph2; - graph2->SetInputData(threshold2->GetOutput()); - graph2->SetInputArrayToProcess(0, 0, 0, vtkDataObject::FIELD_ASSOCIATION_POINTS, "Shape_Index"); - graph2->Update(); - - vtkNew<ttkFTRGraph> graph3; - graph3->SetInputData(threshold3->GetOutput()); - graph3->SetInputArrayToProcess(0, 0, 0, vtkDataObject::FIELD_ASSOCIATION_POINTS, "Shape_Index"); - graph3->Update(); - - // Merge the thresholded datasets together into a single polydata - vtkNew<vtkAppendPolyData> appendFilter; - appendFilter->AddInputData(threshold1->GetOutput()); - appendFilter->AddInputData(threshold2->GetOutput()); - appendFilter->AddInputData(threshold3->GetOutput()); - appendFilter->Update(); -*/ + + /* + double pourcent = 0.8; + + // Create a vtkThresholdPoints filter for each threshold value + vtkNew<vtkThresholdPoints> threshold1; + threshold1->SetInputData(source); + threshold1->ThresholdBetween(0.0, 0.0 + pourcent*0.25); // Scalar values near 0 + threshold1->Update(); + + vtkNew<vtkThresholdPoints> threshold2; + threshold2->SetInputData(source); + threshold2->ThresholdBetween(0.5 - pourcent*0.25, 0.5 + pourcent*0.25); // Scalar values near 1 + threshold2->Update(); + + vtkNew<vtkThresholdPoints> threshold3; + threshold3->SetInputData(source); + threshold3->ThresholdBetween(1.0 - pourcent*0.25, 1.0); // Scalar values near 1 + threshold3->Update(); + + // Create a vtkFTRGraph for each thresholded dataset + vtkNew<ttkFTRGraph> graph1; + graph1->SetInputData(threshold1->GetOutput()); + graph1->SetInputArrayToProcess(0, 0, 0, vtkDataObject::FIELD_ASSOCIATION_POINTS, "Shape_Index"); + graph1->Update(); + + vtkNew<ttkFTRGraph> graph2; + graph2->SetInputData(threshold2->GetOutput()); + graph2->SetInputArrayToProcess(0, 0, 0, vtkDataObject::FIELD_ASSOCIATION_POINTS, "Shape_Index"); + graph2->Update(); + + vtkNew<ttkFTRGraph> graph3; + graph3->SetInputData(threshold3->GetOutput()); + graph3->SetInputArrayToProcess(0, 0, 0, vtkDataObject::FIELD_ASSOCIATION_POINTS, "Shape_Index"); + graph3->Update(); + + // Merge the thresholded datasets together into a single polydata + vtkNew<vtkAppendPolyData> appendFilter; + appendFilter->AddInputData(threshold1->GetOutput()); + appendFilter->AddInputData(threshold2->GetOutput()); + appendFilter->AddInputData(threshold3->GetOutput()); + appendFilter->Update(); + */ // Compute the Reeb Graph of the input dataset vtkNew<ttkFTRGraph> reebGraph; - //reebGraph->SetInputData(appendFilter->GetOutput()); // ttkFTRGraph for the merged polydata + // reebGraph->SetInputData(appendFilter->GetOutput()); // ttkFTRGraph for the merged polydata reebGraph->SetInputData(source); reebGraph->SetInputArrayToProcess(0, 0, 0, vtkDataObject::FIELD_ASSOCIATION_POINTS, "Shape_Index"); reebGraph->Update(); - // Create Icospheres to represent nodes in the Reeb Graph vtkNew<ttkIcospheresFromPoints> ttkIcospheresFromPoints{}; ttkIcospheresFromPoints->SetInputData(0, reebGraph->GetOutput()); ttkIcospheresFromPoints->SetRadius(0.008); - ttkIcospheresFromPoints->SetNumberOfSubdivisions(1); + ttkIcospheresFromPoints->SetNumberOfSubdivisions(1); ttkIcospheresFromPoints->Update(); // Filters dependencies with Tubes : applies smooth to the geometry of the Reeb Graph vtkNew<ttkGeometrySmoother> ttkGeometrySmoother{}; ttkGeometrySmoother->SetInputConnection(reebGraph->GetOutputPort(1)); - ttkGeometrySmoother->Update(); + ttkGeometrySmoother->Update(); vtkNew<vtkGeometryFilter> geometryFilter{}; geometryFilter->SetInputConnection(ttkGeometrySmoother->GetOutputPort()); @@ -180,12 +182,11 @@ int main(int argc, char* argv[]) { // Create Tubes to represent edges in the Reeb Graph vtkNew<vtkTubeFilter> tube{}; - tube->SetInputData(polyData); //smoothed geometry of the Reeb graph + tube->SetInputData(polyData); // smoothed geometry of the Reeb graph tube->SetRadius(0.004); - //tube->SetNumberOfSides(1); + // tube->SetNumberOfSides(1); tube->Update(); - // Save the graph nodes with IcospheresFromPoints vtkNew<vtkXMLPolyDataWriter> writerNodes{}; writerNodes->SetFileName("ReebGraphNodes.vtp"); @@ -210,20 +211,18 @@ int main(int argc, char* argv[]) { sWriter->SetInputConnection(reebGraph->GetOutputPort(0)); sWriter->SetFileName("outputNodes.vtp"); sWriter->Write(); - + // Save the graph edges vtkNew<vtkXMLUnstructuredGridWriter> sepWriter{}; sepWriter->SetInputConnection(reebGraph->GetOutputPort(1)); sepWriter->SetFileName("outputEdges.vtp"); sepWriter->Write(); - + // Save the graph coloration vtkNew<vtkXMLPolyDataWriter> segWriter{}; segWriter->SetInputConnection(reebGraph->GetOutputPort(2)); segWriter->SetFileName("outputColor.vtp"); segWriter->Write();*/ - return EXIT_SUCCESS; } -