We have a model looks like in the following scene. It has been cut by a plane but the shape changed after that. So its surface become not flat.
I got the cut plane information and planed to project all points on the cut part to the plane.
The code snippet:
UPolyDataSurfaceToPlane.h
#pragma once
#include <vtkPolyDataAlgorithm.h>
#include <vtkPlane.h>
#include <vtkCell.h>
#include <vtkPlane.h>
class CUPolyDataSurfaceToPlane : public vtkPolyDataAlgorithm
{
public:
vtkTypeMacro(CUPolyDataSurfaceToPlane, vtkPolyDataAlgorithm);
static CUPolyDataSurfaceToPlane* New();
void SetClipPlane(vtkPlane *plane);
protected:
CUPolyDataSurfaceToPlane(vtkPlane* cf = nullptr);
~CUPolyDataSurfaceToPlane() override;
vtkSmartPointer<vtkPlane> GetCellPlane(vtkSmartPointer<vtkCell> cell, bool &outOfPlane);
int RequestData(vtkInformation*, vtkInformationVector**, vtkInformationVector*) override;
vtkPlane* m_ClipFunction;
private:
CUPolyDataSurfaceToPlane(const CUPolyDataSurfaceToPlane&) = delete;
void operator=(const CUPolyDataSurfaceToPlane&) = delete;
};
UPolyDataSurfaceToPlane.cpp
#include "UPolyDataSurfaceToPlane.h"
#include "tool.h"
#include <vtkInformationVector.h>
#include <vtkInformation.h>
#include <vtkMath.h>
vtkStandardNewMacro(CUPolyDataSurfaceToPlane);
CUPolyDataSurfaceToPlane::CUPolyDataSurfaceToPlane(vtkPlane *cf)
{
m_ClipFunction = cf;
}
CUPolyDataSurfaceToPlane::~CUPolyDataSurfaceToPlane()
{
m_ClipFunction = nullptr;
}
void CUPolyDataSurfaceToPlane::SetClipPlane(vtkPlane *plane)
{
m_ClipFunction = plane;
}
vtkSmartPointer<vtkPlane> CUPolyDataSurfaceToPlane::GetCellPlane(vtkSmartPointer<vtkCell> cell, bool &outOfPlane)
{
auto points = cell->GetPoints();
if( points->GetNumberOfPoints() != 3 )
{
cout << "not triangle!\n";
return nullptr;
}
PointStruct center, pts[3];
outOfPlane = false;
for( int i = 0; i < points->GetNumberOfPoints(); ++i )
{
PointStruct pt( points->GetPoint( i ) );
center = center + pt;
pts[i] = pt;
if( m_ClipFunction->EvaluateFunction(pt.point) < 0 )
{
outOfPlane = true;
}
}
center /= 3;
PointStruct normal = ( pts[0] - pts[1] ) ^ ( pts[0] - pts[2] );
normal.Unit();
vtkSmartPointer<vtkPlane> plane = vtkSmartPointer<vtkPlane>::New();
plane->SetOrigin( center.point );
plane->SetNormal( normal.point );
return plane;
}
int CUPolyDataSurfaceToPlane::RequestData
(
vtkInformation* vtkNotUsed(request),
vtkInformationVector** inputVector,
vtkInformationVector* outputVector
)
{
// get the info objects
vtkInformation* inInfo = inputVector[0]->GetInformationObject(0);
vtkInformation* outInfo = outputVector->GetInformationObject(0);
// get the input and output
vtkPolyData* input = vtkPolyData::SafeDownCast(inInfo->Get(vtkDataObject::DATA_OBJECT()));
vtkPolyData* output = vtkPolyData::SafeDownCast(outInfo->Get(vtkDataObject::DATA_OBJECT()));
double funcValueLimit = 1, normalAngleDiffLimit = 10;
vtkSmartPointer<vtkIdList> surfaceCells = vtkSmartPointer<vtkIdList>::New();
PointStruct clipNormal( m_ClipFunction->GetNormal() );
cout << "clipNormal: " << clipNormal[0] << ", " << clipNormal[1] << ", " << clipNormal[2] << endl;
for( int i = 0; i < input->GetNumberOfCells(); ++i )
{
vtkSmartPointer<vtkCell> cell = input->GetCell( i );
bool outOfPlane;
auto cellPlane = GetCellPlane( cell, outOfPlane );
PointStruct cellNormal( cellPlane->GetNormal() );
auto normalAngle = vtkMath::AngleBetweenVectors( clipNormal.point, cellNormal.point );
auto funcValue = m_ClipFunction->EvaluateFunction( cellPlane->GetOrigin() );
if( outOfPlane ||
( fabs( funcValue ) < funcValueLimit && fabs( normalAngle ) < normalAngleDiffLimit )
)
{
surfaceCells->InsertNextId( i );
}
}
vtkSmartPointer<vtkPoints> newPoints = vtkSmartPointer<vtkPoints>::New();
newPoints->DeepCopy( input->GetPoints() );
for( int i = 0; i < surfaceCells->GetNumberOfIds(); ++i )
{
auto cellId = surfaceCells->GetId( i );
vtkIdType npts;
vtkIdType *pts;
input->GetCell( cellId, pts );
for( int j = 0; j < 3; ++j )
{
PointStruct pt( input->GetPoint( pts[j] ) );
m_ClipFunction->ProjectPoint( pt.point, pt.point );
newPoints->SetPoint( pts[j], pt.point );
}
}
vtkSmartPointer<vtkCellArray> newCells = vtkSmartPointer<vtkCellArray>::New();
newCells->DeepCopy( input->GetPolys() );
output->SetPoints( newPoints );
output->SetPolys( newCells );
return 1;
}
main.cpp
#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 <vtkTransform.h>
#include <vtkPlaneSource.h>
#include <string>
#include <iostream>
#include <vtkProperty.h>
#include "tool.h"
#include "UPolyDataSurfaceToPlane.h"
#define vtkSPtr vtkSmartPointer
#define vtkSPtrNew(Var, Type) vtkSPtr<Type> Var = vtkSPtr<Type>::New();
using namespace std;
void ShowBigPlane(vtkSPtr<vtkRenderer> renderer, vtkSPtr<vtkPlane> plane)
{
vtkSmartPointer<vtkPlaneSource> planeSource =
vtkSmartPointer<vtkPlaneSource>::New();
planeSource->SetCenter( plane->GetOrigin() );
planeSource->SetNormal( plane->GetNormal() );
planeSource->Update();
vtkSmartPointer<vtkPolyDataMapper> planeMapper =
vtkSmartPointer<vtkPolyDataMapper>::New();
planeMapper->SetInputData( planeSource->GetOutput() );
planeMapper->Update();
int scaleValue = 40;
vtkSmartPointer<vtkActor> planeActor =
vtkSmartPointer<vtkActor>::New();
planeActor->SetMapper( planeMapper );
planeActor->GetProperty()->SetColor( 0, 1, 1 );
PointStruct originPt( plane->GetOrigin() );
vtkSPtrNew( trans, vtkTransform );
trans->Translate( originPt.point );
trans->Scale( scaleValue, scaleValue, scaleValue );
trans->Translate( (-originPt).point );
planeActor->SetUserTransform( trans );
renderer->AddActor( planeActor );
}
int main()
{
std::string filePath = "origin_surface.stl";
vtkSPtrNew( reader, vtkSTLReader );
reader->SetFileName( filePath.c_str() );
reader->Update();
auto data = reader->GetOutput();
PointStruct origin( -1.78958, -22.5648, 20.2123 );
PointStruct normal( 0.00056659, -0.10854, -0.994092 );
vtkSmartPointer<vtkPlane> cutPlane = vtkSmartPointer<vtkPlane>::New();
cutPlane->SetOrigin( origin.point );
cutPlane->SetNormal( normal.point );
vtkSmartPointer<CUPolyDataSurfaceToPlane> surfaceToPlane = vtkSmartPointer<CUPolyDataSurfaceToPlane>::New();
surfaceToPlane->SetInputData( data );
surfaceToPlane->SetClipPlane( cutPlane );
surfaceToPlane->Update();
vtkSPtrNew( mapper, vtkPolyDataMapper );
mapper->SetInputData( surfaceToPlane->GetOutput() );
vtkSPtrNew( actor, vtkActor );
actor->SetMapper( mapper );
vtkSPtrNew( mapper0, vtkPolyDataMapper );
mapper0->SetInputData( data );
vtkSPtrNew( actor0, vtkActor );
actor0->SetMapper( mapper0 );
actor0->GetProperty()->SetColor( 1, 0, 0 );
vtkSPtrNew( renderer, vtkRenderer );
renderer->AddActor( actor );
//renderer->AddActor( actor0 );
renderer->SetBackground( 0, 0, 0 );
ShowBigPlane( renderer, cutPlane );
vtkSPtrNew( renderWindow, vtkRenderWindow );
renderWindow->AddRenderer( renderer );
vtkSPtrNew( renderWindowInteractor, vtkRenderWindowInteractor );
renderWindowInteractor->SetRenderWindow( renderWindow );
renderer->ResetCamera();
renderWindow->Render();
renderWindowInteractor->Start();
return 0;
}
STL File:
origin_surface.stl
Output: