diff --git a/vespa/PolygonMeshProcessing/CMakeLists.txt b/vespa/PolygonMeshProcessing/CMakeLists.txt index 7d5e743743b777b2a4eef325519c1a1ab1f0a610..b25c02ec98ca90d33f9f47679fa4b033f6dda5df 100644 --- a/vespa/PolygonMeshProcessing/CMakeLists.txt +++ b/vespa/PolygonMeshProcessing/CMakeLists.txt @@ -4,6 +4,7 @@ set(vtkcgalpmp_files vtkCGALBooleanOperation vtkCGALIsotropicRemesher vtkCGALMeshDeformation + vtkCGALMeshSubdivision vtkCGALPatchFilling vtkCGALRegionFairing ) diff --git a/vespa/PolygonMeshProcessing/Testing/CMakeLists.txt b/vespa/PolygonMeshProcessing/Testing/CMakeLists.txt index 890e383d7394d60fdec9978af7eb44dd30a8eb08..1666c1574b93323d6a60ce145382abf2f5bc0d17 100644 --- a/vespa/PolygonMeshProcessing/Testing/CMakeLists.txt +++ b/vespa/PolygonMeshProcessing/Testing/CMakeLists.txt @@ -40,6 +40,7 @@ vtk_add_test_cxx(vtkCGALCxxTests no_data_tests TestPMPFairExecution.cxx TestPMPFillExecution.cxx TestPMPIsotropicExecution.cxx + TestPMPSubdivisionExecution.cxx ${PROJECT_SOURCE_DIR}/Data/Testing/ ) diff --git a/vespa/PolygonMeshProcessing/Testing/TestPMPSubdivisionExecution.cxx b/vespa/PolygonMeshProcessing/Testing/TestPMPSubdivisionExecution.cxx new file mode 100644 index 0000000000000000000000000000000000000000..d65c8dc8b97b5857338ec345b702a9cf4c811950 --- /dev/null +++ b/vespa/PolygonMeshProcessing/Testing/TestPMPSubdivisionExecution.cxx @@ -0,0 +1,43 @@ +#include + +#include "vtkNew.h" +#include "vtkSphereSource.h" +#include "vtkTestUtilities.h" +#include "vtkXMLPolyDataWriter.h" + +#include "vtkCGALMeshSubdivision.h" + +int TestPMPSubdivisionExecution(int, char* argv[]) +{ + vtkNew sphere; + sphere->SetRadius(2.0); + sphere->SetThetaResolution(8); + sphere->SetPhiResolution(8); + + // Create subdivision filter + vtkNew subdivider; + subdivider->SetInputConnection(sphere->GetOutputPort()); + subdivider->SetUpdateAttributes(false); + + vtkNew writer; + writer->SetInputConnection(subdivider->GetOutputPort()); + writer->SetFileName("sphere_subdivision_sqrt3.vtp"); + writer->Write(); + + // Change to Catmull-Clark method + subdivider->SetSubdivisionType(vtkCGALMeshSubdivision::CATMULL_CLARK); + writer->SetFileName("sphere_subdivision_catmull_clark.vtp"); + writer->Write(); + + // Change to Loop method + subdivider->SetSubdivisionType(vtkCGALMeshSubdivision::LOOP); + writer->SetFileName("sphere_subdivision_loop.vtp"); + writer->Write(); + + // Change to Doo-Sabin method + subdivider->SetSubdivisionType(vtkCGALMeshSubdivision::DOO_SABIN); + writer->SetFileName("sphere_subdivision_doo_sabin.vtp"); + writer->Write(); + + return 0; +} diff --git a/vespa/PolygonMeshProcessing/vtkCGALMeshSubdivision.cxx b/vespa/PolygonMeshProcessing/vtkCGALMeshSubdivision.cxx new file mode 100644 index 0000000000000000000000000000000000000000..f8f77236f990d78140598e0a97fa331cc2c9f66d --- /dev/null +++ b/vespa/PolygonMeshProcessing/vtkCGALMeshSubdivision.cxx @@ -0,0 +1,119 @@ +#include "vtkCGALMeshSubdivision.h" + +// VTK related includes +#include "vtkInformation.h" +#include "vtkInformationVector.h" +#include "vtkNew.h" +#include "vtkObjectFactory.h" +#include "vtkTriangleFilter.h" + +// CGAL related includes +#include + +vtkStandardNewMacro(vtkCGALMeshSubdivision); + +//------------------------------------------------------------------------------ +void vtkCGALMeshSubdivision::PrintSelf(ostream& os, vtkIndent indent) +{ + switch (this->SubdivisionType) + { + case vtkCGALMeshSubdivision::CATMULL_CLARK: + os << indent << "SubdivisionType: " + << "Catmull-Clark" << std::endl; + break; + case vtkCGALMeshSubdivision::LOOP: + os << indent << "SubdivisionType: " + << "Loop" << std::endl; + break; + case vtkCGALMeshSubdivision::DOO_SABIN: + os << indent << "SubdivisionType: " + << "Doo-Sabin" << std::endl; + break; + case vtkCGALMeshSubdivision::SQRT3: + os << indent << "SubdivisionType: " + << "Sqrt3" << std::endl; + break; + default: + os << indent << "SubdivisionType: " + << "Unknown" << std::endl; + break; + } + + os << indent << "Iterations :" << this->Iterations << std::endl; + this->Superclass::PrintSelf(os, indent); +} + +//------------------------------------------------------------------------------ +int vtkCGALMeshSubdivision::RequestData( + vtkInformation*, vtkInformationVector** inputVector, vtkInformationVector* outputVector) +{ + // Get the input and output data objects. + vtkPolyData* input = vtkPolyData::GetData(inputVector[0]); + vtkPolyData* output = vtkPolyData::GetData(outputVector); + + if (!input || !output) + { + vtkErrorMacro(<< "Missing input or output!"); + return 0; + } + + // Create the triangle mesh for CGAL + // --------------------------------- + + std::unique_ptr cgalMesh = this->toCGAL(input); + + // CGAL Processing + // --------------- + + try + { + switch (this->SubdivisionType) + { + case vtkCGALMeshSubdivision::CATMULL_CLARK: + CGAL::Subdivision_method_3::CatmullClark_subdivision( + cgalMesh->surface, CGAL::parameters::number_of_iterations(this->Iterations)); + break; + case vtkCGALMeshSubdivision::LOOP: + CGAL::Subdivision_method_3::Loop_subdivision( + cgalMesh->surface, CGAL::parameters::number_of_iterations(this->Iterations)); + break; + case vtkCGALMeshSubdivision::DOO_SABIN: + CGAL::Subdivision_method_3::DooSabin_subdivision( + cgalMesh->surface, CGAL::parameters::number_of_iterations(this->Iterations)); + break; + case vtkCGALMeshSubdivision::SQRT3: + CGAL::Subdivision_method_3::Sqrt3_subdivision( + cgalMesh->surface, CGAL::parameters::number_of_iterations(this->Iterations)); + break; + default: + vtkErrorMacro("Unknown subdivision method!"); + break; + } + } + catch (std::exception& e) + { + vtkErrorMacro("CGAL Exception: " << e.what()); + return 0; + } + + // VTK Output + // ---------- + + // Triangulate if needed + if (this->SubdivisionType == vtkCGALMeshSubdivision::CATMULL_CLARK || + this->SubdivisionType == vtkCGALMeshSubdivision::DOO_SABIN) + { + vtkNew triangulator; + triangulator->SetInputData(this->toVTK(cgalMesh.get())); + triangulator->Update(); + output->ShallowCopy(triangulator->GetOutput()); + } + else + { + output->ShallowCopy(this->toVTK(cgalMesh.get())); + } + + this->interpolateAttributes(input, output); + + return 1; +} diff --git a/vespa/PolygonMeshProcessing/vtkCGALMeshSubdivision.h b/vespa/PolygonMeshProcessing/vtkCGALMeshSubdivision.h new file mode 100644 index 0000000000000000000000000000000000000000..6b469f28e0b94140c1732cfed2cb38cf22332f3d --- /dev/null +++ b/vespa/PolygonMeshProcessing/vtkCGALMeshSubdivision.h @@ -0,0 +1,72 @@ +/** + * @class vtkCGALMeshSubdivision + * @brief Refines a polygonal mesh through subdivision. + * + * This filter performs a surface mesh subdivision by creating new points + * to refine and smoothen a polygonal mesh. Several subdivision methods are + * available: + * - Catmull-Clark based on the PQQ pattern + * - Loop based on the PTQ pattern + * - Doo-Sabin based on the DQQ pattern + * - Sqrt3 based on the Sqrt3 pattern + */ + +#ifndef vtkCGALMeshSubdivision_h +#define vtkCGALMeshSubdivision_h + +#include "vtkCGALPolyDataAlgorithm.h" + +#include "vtkCGALPMPModule.h" // For export macro + +class VTKCGALPMP_EXPORT vtkCGALMeshSubdivision : public vtkCGALPolyDataAlgorithm +{ +public: + static vtkCGALMeshSubdivision* New(); + vtkTypeMacro(vtkCGALMeshSubdivision, vtkCGALPolyDataAlgorithm); + void PrintSelf(ostream& os, vtkIndent indent) override; + + /** + * List of available subdivision methods, each based on a specific refinement pattern. + **/ + enum SubdivisionMethod + { + CATMULL_CLARK = 0, + LOOP, + DOO_SABIN, + SQRT3 + }; + + ///@{ + /** + * Get/set the subdivision method. + * Default is SQRT3. + **/ + vtkGetMacro(SubdivisionType, int); + vtkSetClampMacro( + SubdivisionType, int, vtkCGALMeshSubdivision::CATMULL_CLARK, vtkCGALMeshSubdivision::SQRT3); + ///@} + + ///@{ + /** + * Get/set the number of iterations (subdivisions) used in the subdivision process. + * Default is 1. + **/ + vtkGetMacro(Iterations, double); + vtkSetMacro(Iterations, double); + ///@} + +protected: + vtkCGALMeshSubdivision() = default; + ~vtkCGALMeshSubdivision() override = default; + + int RequestData(vtkInformation*, vtkInformationVector**, vtkInformationVector*) override; + + int SubdivisionType = vtkCGALMeshSubdivision::SQRT3; + unsigned int Iterations = 1; + +private: + vtkCGALMeshSubdivision(const vtkCGALMeshSubdivision&) = delete; + void operator=(const vtkCGALMeshSubdivision&) = delete; +}; + +#endif