The post shows a way to remesh a model to make uneven triangles on the mesh to be more uniform.
#include <iostream>
#include <vtkSmartPointer.h>
#include <vtkSphereSource.h>
#include <vtkActor.h>
#include <vtkConeSource.h>
#include <vtkRenderer.h>
#include <vtkRenderWindow.h>
#include <vtkPolyDataMapper.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkSTLReader.h>
#include <vtkCleanPolyData.h>
#include <vtkPolyDataToImageStencil.h>
#include <vtkImageData.h>
#include <vtkImageStencil.h>
#include <vtkImageMarchingCubes.h>
#include <vtkFillHolesFilter.h>
#include <vtkPolyDataNormals.h>
#include <vtkPointData.h>
#include <vtkXMLPolyDataWriter.h>
#define vtkSPtr vtkSmartPointer
#define vtkSPtrNew(Var, Type) vtkSPtr<Type> Var = vtkSPtr<Type>::New();
using namespace std;
vtkSPtr<vtkPolyData> GetRemeshPd(vtkSPtr<vtkPolyData> polydata)
{
if( nullptr == polydata )
{
return nullptr;
}
// --------------------- polydata to image -----------------------
double spacingVal = 0.2;
int togetherExtentSize = 3;
unsigned char imageInVal = 255;
unsigned char imageOutVal = 0;
double bounds[6];
polydata->GetBounds(bounds);
int dim[3];
for (int i = 0; i < 3; i++)
{
dim[i] = static_cast<int>( ceil((bounds[2 * i + 1] - bounds[2 * i]) / spacingVal) ) + togetherExtentSize;
}
double origin[3];
origin[0] = bounds[0] - spacingVal * togetherExtentSize / 2;
origin[1] = bounds[2] - spacingVal * togetherExtentSize / 2;
origin[2] = bounds[4] - spacingVal * togetherExtentSize / 2;
vtkSPtrNew(imageData, vtkImageData);
imageData->SetSpacing(spacingVal, spacingVal, spacingVal);
imageData->SetDimensions(dim);
imageData->SetOrigin(origin);
imageData->AllocateScalars(VTK_UNSIGNED_CHAR, 1);
imageData->GetPointData()->GetScalars()->Fill(imageInVal);
// polygonal data --> imageData stencil:
vtkSPtrNew(pd2stenc, vtkPolyDataToImageStencil);
pd2stenc->SetInputData(polydata);
pd2stenc->SetOutputOrigin(origin);
pd2stenc->SetOutputSpacing(spacingVal, spacingVal, spacingVal);
pd2stenc->SetOutputWholeExtent(imageData->GetExtent());
pd2stenc->Update();
// cut the corresponding white imageData and set the background:
vtkSPtrNew(imgstenc, vtkImageStencil);
imgstenc->SetInputData(imageData);
imgstenc->SetStencilConnection(pd2stenc->GetOutputPort());
imgstenc->ReverseStencilOff();
imgstenc->SetBackgroundValue( imageOutVal );
imgstenc->Update();
imageData->DeepCopy(imgstenc->GetOutput());
// -------------------------- image to polydata --------------------------------
vtkSPtrNew( marchingCubes, vtkImageMarchingCubes );
marchingCubes->SetInputData( imageData );
marchingCubes->SetValue( 0, (imageInVal + imageOutVal)/2 );
marchingCubes->SetComputeNormals(0);
marchingCubes->SetComputeGradients(0);
marchingCubes->SetNumberOfContours( 1 );
marchingCubes->Update();
// Fill the holes
vtkSPtrNew( fillHoles, vtkFillHolesFilter );
fillHoles->SetInputData( marchingCubes->GetOutput() );
fillHoles->SetHoleSize( 1000000 );
fillHoles->Update();
vtkSPtrNew( cleanFilter, vtkCleanPolyData );
cleanFilter->SetInputData( fillHoles->GetOutput() );
cleanFilter->Update();
// Make the triangle winding order consistent
vtkSPtrNew( normals, vtkPolyDataNormals );
normals->SetInputData( cleanFilter->GetOutput() );
normals->ConsistencyOn();
normals->SplittingOff();
normals->GetOutput()->GetPointData()->SetNormals(
marchingCubes->GetOutput()->GetPointData()->GetNormals());
normals->Update();
vtkSPtrNew( result, vtkPolyData );
result->DeepCopy( normals->GetOutput() );
return result;
}
int main()
{
vtkSPtrNew( reader, vtkSTLReader );
reader->SetFileName( "locker.stl" );
reader->Update();
auto inputData = reader->GetOutput();
auto newData = GetRemeshPd( inputData );
vtkSPtrNew(writer1, vtkXMLPolyDataWriter);
writer1->SetInputData( newData );
writer1->SetFileName("newData.vtp");
writer1->Write();
return 0;
}
The 3D model file locker.stl can be downloaded at the page:
https://www.weiy.city/downloads/3d-model-simple-lock/ .
Compare the original mesh and the new data in paraview: