How to decimate a PolyData without changing pointData’s scalar’s position? Two classes vtkQuadricDecimation and vtkDecimatePro are worth discussing.
vtkQuadricDecimation can decimate pointdata’s scalar.
We have to set AttributeErrorMetric true to handle it.
#include <iostream>
#include <vtkSmartPointer.h>
#include <vtkSphereSource.h>
#include <vtkActor.h>
#include <vtkConeSource.h>
#include <vtkRenderer.h>
#include <vtkRenderWindow.h>
#include <vtkPolyDataMapper.h>
#include <vtkProperty.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkLight.h>
#include <vtkCamera.h>
#include <vtkActor2D.h>
#include <vtkLineSource.h>
#include <vtkAppendPolyData.h>
#include <vtkPointData.h>
#include <vtkFloatArray.h>
#include <vtkQuadricDecimation.h>
#include <vtkTriangleFilter.h>
#include <vtkPlaneSource.h>
using namespace std;
int main()
{
vtkSmartPointer<vtkSphereSource> sphereSource =
vtkSmartPointer<vtkSphereSource>::New();
sphereSource->SetPhiResolution( 50 );
sphereSource->SetThetaResolution( 50 );
sphereSource->Update();
vtkPolyData *spherePd = sphereSource->GetOutput();
vtkFloatArray *sphereScalars = vtkFloatArray::New();
for( int i = 0; i < spherePd->GetNumberOfPoints(); ++i )
{
sphereScalars->InsertNextTuple1( 1.0 * i / spherePd->GetNumberOfPoints() );
}
spherePd->GetPointData()->SetScalars( sphereScalars );
sphereScalars->FastDelete();
vtkSmartPointer<vtkPolyDataMapper> sphereMapper =
vtkSmartPointer<vtkPolyDataMapper>::New();
sphereMapper->SetInputData( spherePd );
vtkSmartPointer<vtkActor> sphereActor =
vtkSmartPointer<vtkActor>::New();
sphereActor->SetMapper( sphereMapper );
// Define viewport ranges
// (xmin, ymin, xmax, ymax) left-top and right-bottom point
double leftViewport[4] = {0.0, 0.0, 0.5, 1.0};
double rightViewport[4] = {0.5, 0.0, 1.0, 1.0};
// Setup renderers
vtkSmartPointer<vtkRenderer> leftRenderer =
vtkSmartPointer<vtkRenderer>::New();
leftRenderer->SetViewport(leftViewport);
leftRenderer->SetBackground(0, 0, 0);
vtkSmartPointer<vtkRenderer> rightRenderer =
vtkSmartPointer<vtkRenderer>::New();
rightRenderer->SetViewport(rightViewport);
rightRenderer->SetBackground(0, 0, 0);
leftRenderer->AddActor( sphereActor );
vtkSmartPointer<vtkQuadricDecimation> decimation
= vtkSmartPointer<vtkQuadricDecimation>::New();
decimation->SetTargetReduction( 0.3 );
decimation->AttributeErrorMetricOn();
decimation->ScalarsAttributeOn();
decimation->SetInputData( sphereActor->GetMapper()->GetInput() );
decimation->Update();
vtkSmartPointer<vtkPolyDataMapper> decimatedSphereMapper =
vtkSmartPointer<vtkPolyDataMapper>::New();
decimatedSphereMapper->SetInputData( decimation->GetOutput() );
vtkSmartPointer<vtkActor> decimatedSphereActor =
vtkSmartPointer<vtkActor>::New();
decimatedSphereActor->SetMapper( decimatedSphereMapper );
rightRenderer->AddActor( decimatedSphereActor );
leftRenderer->ResetCamera();
rightRenderer->ResetCamera();
vtkSmartPointer<vtkRenderWindow> renderWindow =
vtkSmartPointer<vtkRenderWindow>::New();
renderWindow->SetSize(600, 300);
renderWindow->AddRenderer( leftRenderer );
renderWindow->AddRenderer( rightRenderer );
vtkSmartPointer<vtkRenderWindowInteractor> renderWindowInteractor =
vtkSmartPointer<vtkRenderWindowInteractor>::New();
renderWindowInteractor->SetRenderWindow( renderWindow );
renderWindow->Render();
renderWindowInteractor->Start();
return 0;
}
Display:
But I found the scalar may change pointData’s scalar’s position in the way.
double decimatePercent = 0.5;
vtkSmartPointer<vtkQuadricDecimation> decimation
= vtkSmartPointer<vtkQuadricDecimation>::New();
decimation->SetTargetReduction( decimatePercent );
decimation->AttributeErrorMetricOn();
decimation->ScalarsAttributeOn();
decimation->SetInputData( polydata );
decimation->Update();
I can’t just change attributes’ proportion such as ScalarsWeight or VectorsWeight to fix the issue.
Then I find vtkDecimatePro may help me to get what I want.
double decimatePercent = 0.5;
vtkSmartPointer<vtkDecimatePro> decimation =
vtkSmartPointer<vtkDecimatePro>::New();
decimation->SetTargetReduction( decimatePercent );
decimation->PreserveTopologyOn();
decimation->SetInputData( polydata );
decimation->Update();
Test code:
actorCollection
#include <iostream>
#include <vtkSmartPointer.h>
#include <vtkSphereSource.h>
#include <vtkActor.h>
#include <vtkConeSource.h>
#include <vtkRenderer.h>
#include <vtkRenderWindow.h>
#include <vtkPolyDataMapper.h>
#include <vtkProperty.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkLight.h>
#include <vtkCamera.h>
#include <vtkActor2D.h>
#include <vtkLineSource.h>
#include <vtkAppendPolyData.h>
#include <vtkPointData.h>
#include <vtkFloatArray.h>
#include <vtkCamera.h>
#include <vtkSTLReader.h>
#include <vtkDecimatePro.h>
#include <vtkFloatArray.h>
#include "vtkSetGet.h"
#include "myQuadricDecimation.h"
#include "UMacroDefinition.h"
#include <vtkTriangleFilter.h>
#include <vtkPlaneSource.h>
#include <vtkQuadricDecimation.h>
#include <QString>
using namespace std;
bool LoadOldArchdataFile( vtkPolyData *archData )
{
QString filePath = "/Users/weiyang/Desktop/archData_l.ad";
ifstream iStream;
iStream.open(filePath.toStdString(), ios::binary);
if (iStream.is_open() == false)
return false;
int archType;
iStream.read((char*)&archType, sizeof(archType));
vtkIdType numberOfPoints;
char cNumberOfPoints[8];
iStream.read(cNumberOfPoints, sizeof(cNumberOfPoints));
BYTEARRAY_TO_VTKIDTYPE(cNumberOfPoints, numberOfPoints);
vSPNew(points, vtkPoints);
for (vtkIdType i = 0; i < numberOfPoints; i++)
{
double pointPos[3];
iStream.read((char*)pointPos, sizeof(pointPos));
points->InsertNextPoint(pointPos);
}
char cNumberOfCells[8];
iStream.read(cNumberOfCells, sizeof(cNumberOfCells));
vtkIdType numberOfCells;
BYTEARRAY_TO_VTKIDTYPE(cNumberOfCells, numberOfCells);
vSPNew(cells, vtkCellArray);
for (vtkIdType i = 0; i < numberOfCells; i++)
{
vtkIdType nPoints;
char cNPoints[8];
iStream.read(cNPoints, sizeof(cNPoints));
BYTEARRAY_TO_VTKIDTYPE(cNPoints, nPoints);
vtkIdType *pts = new vtkIdType[nPoints];
for (vtkIdType j = 0; j < nPoints; j++)
{
char cPts[8];
iStream.read(cPts, sizeof(cPts));
BYTEARRAY_TO_VTKIDTYPE(cPts, pts[j]);
}
cells->InsertNextCell(nPoints);
for (int j = 0; j < nPoints; j++)
cells->InsertCellPoint(pts[j]);
delete[]pts;
}
vtkIdType numberOfPointTypeArray = 0;
char cNumberOfPointTypeArray[8];
iStream.read(cNumberOfPointTypeArray, sizeof(cNumberOfPointTypeArray));
BYTEARRAY_TO_VTKIDTYPE(cNumberOfPointTypeArray, numberOfPointTypeArray);
if (numberOfPointTypeArray == 0)
{
iStream.close();
return false;
}
vSPNew(pointTypeArray, vtkIntArray);
for (vtkIdType i = 0; i < numberOfPointTypeArray; i++)
{
int pointType;
iStream.read((char*)&pointType, sizeof(pointType));
pointTypeArray->InsertNextValue(pointType);
}
vSPNew( floatArray, vtkIntArray ); //vtkFloatArray);
for (vtkIdType i = 0; i < numberOfPointTypeArray; i++)
{
int value = pointTypeArray->GetValue( i );
value = value % 3;
floatArray->InsertNextValue( value ); //1.0 * value / 13
}
archData->SetPoints(points);
archData->SetPolys(cells);
//archData->GetPointData()->SetScalars( pointTypeArray );
archData->GetPointData()->SetScalars( floatArray );
archData->Modified();
archData->BuildCells();
archData->BuildLinks();
vtkIdType numberOfSeedPointList;
char cNumberOfSeedPointList[8];
iStream.read(cNumberOfSeedPointList, sizeof(cNumberOfSeedPointList));
BYTEARRAY_TO_VTKIDTYPE(cNumberOfSeedPointList, numberOfSeedPointList);
vSP<vtkIdList> seedPointList = vSP<vtkIdList>::New(); //m_ZipsAndEMs->Getm_SeedPointList();
seedPointList->Reset();
for (vtkIdType i = 0; i < numberOfSeedPointList; i++)
{
vtkIdType pointId;
char cPointId[8];
iStream.read(cPointId, sizeof(cPointId));
BYTEARRAY_TO_VTKIDTYPE(cPointId, pointId);
seedPointList->InsertNextId(pointId);
}
iStream.close();
return true;
}
int main()
{
setbuf( stdout, nullptr );
double decimatePercent = 0.5;
/*
vtkSmartPointer<vtkSphereSource> sphereSource =
vtkSmartPointer<vtkSphereSource>::New();
sphereSource->SetPhiResolution( 50 );
sphereSource->SetThetaResolution( 50 );
sphereSource->Update();
*/
//vtkPolyData *spherePd = stlReader->GetOutput(); //sphereSource->GetOutput();
vSPNew( spherePd, vtkPolyData );
LoadOldArchdataFile( spherePd );
/* vtkFloatArray *sphereScalars = vtkFloatArray::New();
for( int i = 0; i < spherePd->GetNumberOfPoints(); ++i )
{
sphereScalars->InsertNextTuple1( 1.0 * i / spherePd->GetNumberOfPoints() );
}
spherePd->GetPointData()->SetScalars( sphereScalars );
sphereScalars->FastDelete(); */
vtkSmartPointer<vtkPolyDataMapper> sphereMapper =
vtkSmartPointer<vtkPolyDataMapper>::New();
sphereMapper->SetInputData( spherePd );
vtkSmartPointer<vtkActor> sphereActor =
vtkSmartPointer<vtkActor>::New();
sphereActor->SetMapper( sphereMapper );
// Define viewport ranges
// (xmin, ymin, xmax, ymax) left-top and right-bottom point
double leftViewport[4] = {0.0, 0.0, 0.5, 1.0};
double rightViewport[4] = {0.5, 0.0, 1.0, 1.0};
// Setup renderers
vtkSmartPointer<vtkRenderer> leftRenderer =
vtkSmartPointer<vtkRenderer>::New();
leftRenderer->SetViewport(leftViewport);
leftRenderer->SetBackground(0, 0, 0);
vtkSmartPointer<vtkRenderer> rightRenderer =
vtkSmartPointer<vtkRenderer>::New();
rightRenderer->SetViewport(rightViewport);
rightRenderer->SetBackground(0, 0, 0);
leftRenderer->AddActor( sphereActor );
// vtkSmartPointer<vtkQuadricDecimation> decimation
// = vtkSmartPointer<vtkQuadricDecimation>::New();
// decimation->SetTargetReduction( decimatePercent );
// decimation->AttributeErrorMetricOn();
// decimation->ScalarsAttributeOn();
vtkSmartPointer<vtkDecimatePro> decimation =
vtkSmartPointer<vtkDecimatePro>::New();
//decimation->SetInputData(inputPolyData);
decimation->SetTargetReduction( decimatePercent );
//decimation->PreserveTopologyOn();
decimation->SetInputData( sphereActor->GetMapper()->GetInput() );
decimation->Update();
decimation->PrintSelf( std::cout, *vtkIndent::New() );
vtkSmartPointer<vtkPolyDataMapper> decimatedSphereMapper =
vtkSmartPointer<vtkPolyDataMapper>::New();
decimatedSphereMapper->SetInputData( decimation->GetOutput() );
vtkSmartPointer<vtkActor> decimatedSphereActor =
vtkSmartPointer<vtkActor>::New();
decimatedSphereActor->SetMapper( decimatedSphereMapper );
rightRenderer->AddActor( decimatedSphereActor );
vtkSmartPointer<vtkCamera> camera =
vtkSmartPointer<vtkCamera>::New();
leftRenderer->SetActiveCamera( camera );
rightRenderer->SetActiveCamera( camera );
leftRenderer->ResetCamera();
rightRenderer->ResetCamera();
vtkSmartPointer<vtkRenderWindow> renderWindow =
vtkSmartPointer<vtkRenderWindow>::New();
renderWindow->SetSize(600, 300);
renderWindow->AddRenderer( leftRenderer );
renderWindow->AddRenderer( rightRenderer );
vtkSmartPointer<vtkRenderWindowInteractor> renderWindowInteractor =
vtkSmartPointer<vtkRenderWindowInteractor>::New();
renderWindowInteractor->SetRenderWindow( renderWindow );
renderWindow->Render();
renderWindowInteractor->Start();
return 0;
}