1、代码
#pragma once
#include <vtkActor.h>
#include <vtkCamera.h>
#include <vtkClipPolyData.h>
#include <vtkDataSetMapper.h>
#include <vtkFeatureEdges.h>
#include <vtkNamedColors.h>
#include <vtkNew.h>
#include <vtkPlane.h>
#include <vtkPolyData.h>
#include <vtkPolyDataMapper.h>
#include <vtkProperty.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkRenderer.h>
#include <vtkSmartPointer.h>
#include <vtkSphereSource.h>
#include <vtkStripper.h>
#include <vtkXMLPolyDataReader.h>
#include <vtkMassProperties.h>
#include < vtkTriangleFilter.h>
// Readers
#include <vtkBYUReader.h>
#include <vtkOBJReader.h>
#include <vtkPLYReader.h>
#include <vtkPolyDataReader.h>
#include <vtkSTLReader.h>
#include <vtkXMLPolyDataReader.h>
namespace {
vtkSmartPointer<vtkPolyData> ReadPolyData(std::string const& fileName)
{
vtkSmartPointer<vtkPolyData> polyData;
std::string extension = "";
if (fileName.find_last_of(".") != std::string::npos){
extension = fileName.substr(fileName.find_last_of("."));
}
// Make the extension lowercase
std::transform(extension.begin(), extension.end(), extension.begin(),::tolower);
if (extension == ".ply"){
vtkNew<vtkPLYReader> reader;
reader->SetFileName(fileName.c_str());
reader->Update();
polyData = reader->GetOutput();
}
else if (extension == ".vtp"){
vtkNew<vtkXMLPolyDataReader> reader;
reader->SetFileName(fileName.c_str());
reader->Update();
polyData = reader->GetOutput();
}
else if (extension == ".obj"){
vtkNew<vtkOBJReader> reader;
reader->SetFileName(fileName.c_str());
reader->Update();
polyData = reader->GetOutput();
}
else if (extension == ".stl"){
vtkNew<vtkSTLReader> reader;
reader->SetFileName(fileName.c_str());
reader->Update();
polyData = reader->GetOutput();
}
else if (extension == ".vtk"){
vtkNew<vtkPolyDataReader> reader;
reader->SetFileName(fileName.c_str());
reader->Update();
polyData = reader->GetOutput();
}
else if (extension == ".g"){
vtkNew<vtkBYUReader> reader;
reader->SetGeometryFileName(fileName.c_str());
reader->Update();
polyData = reader->GetOutput();
}
else{
// Return a polydata sphere if the extension is unknown.
vtkNew<vtkSphereSource> source;
source->SetThetaResolution(20);
source->SetPhiResolution(11);
source->Update();
polyData = source->GetOutput();
}
return polyData;
}
} // namespace
class Test_Clip_cow {
public:
static void Test() {
vtkNew<vtkNamedColors> colors;
auto backgroundColor = colors->GetColor3d("steel_blue");
auto boundaryColor = colors->GetColor3d("banana");
auto clipColor = colors->GetColor3d("tomato");
// PolyData to process
auto polyData = ReadPolyData("cow.g");
vtkNew<vtkPlane> plane;
plane->SetOrigin(polyData->GetCenter());
plane->SetNormal(1.0, -1.0, -1.0);
vtkNew<vtkClipPolyData> clipper;
clipper->SetInputData(polyData);
clipper->SetClipFunction(plane);
clipper->GenerateClipScalarsOn();
clipper->GenerateClippedOutputOn();
clipper->SetValue(0.5);
clipper->Update();
polyData = clipper->GetOutput();
vtkNew<vtkDataSetMapper> clipMapper;
clipMapper->SetInputData(polyData);
clipMapper->ScalarVisibilityOff();
vtkNew<vtkActor> clipActor;
clipActor->SetMapper(clipMapper);
clipActor->GetProperty()->SetDiffuseColor(clipColor.GetData());
clipActor->GetProperty()->SetInterpolationToFlat();
clipActor->GetProperty()->EdgeVisibilityOn();
// Now extract feature edges
vtkNew<vtkFeatureEdges> boundaryEdges;
boundaryEdges->SetInputData(polyData);
boundaryEdges->BoundaryEdgesOn();
boundaryEdges->FeatureEdgesOff();
boundaryEdges->NonManifoldEdgesOff();
boundaryEdges->ManifoldEdgesOff();
vtkNew<vtkStripper> boundaryStrips;
boundaryStrips->SetInputConnection(boundaryEdges->GetOutputPort());
boundaryStrips->Update();
// Change the polylines into polygons
vtkNew<vtkPolyData> boundaryPoly;
boundaryPoly->SetPoints(boundaryStrips->GetOutput()->GetPoints());
boundaryPoly->SetPolys(boundaryStrips->GetOutput()->GetLines());
vtkNew<vtkPolyDataMapper> boundaryMapper;
boundaryMapper->SetInputData(boundaryPoly);
vtkNew<vtkActor> boundaryActor;
boundaryActor->SetMapper(boundaryMapper);
boundaryActor->GetProperty()->SetDiffuseColor(boundaryColor.GetData());
vtkNew<vtkTriangleFilter> triFilter;
triFilter->SetInputData(boundaryPoly);
triFilter->Update();
vtkSmartPointer<vtkMassProperties> massProp =
vtkSmartPointer<vtkMassProperties>::New();
massProp->SetInputData(triFilter->GetOutput());
float vol = massProp->GetVolume();
float area = massProp->GetSurfaceArea();
std::cout << "Surface Area:" << area << std::endl;
vtkNew<vtkPolyDataMapper> restMapper;
restMapper->SetInputConnection(clipper->GetClippedOutputPort());
restMapper->ScalarVisibilityOff();
vtkNew<vtkActor> restActor;
restActor->SetMapper(restMapper);
restActor->GetProperty()->SetRepresentationToWireframe();
// Create graphics stuff
vtkNew<vtkRenderer> renderer;
renderer->SetBackground(backgroundColor.GetData());
renderer->UseHiddenLineRemovalOn();
vtkNew<vtkRenderWindow> renderWindow;
renderWindow->AddRenderer(renderer);
renderWindow->SetSize(640, 480);
vtkNew<vtkRenderWindowInteractor> interactor;
interactor->SetRenderWindow(renderWindow);
// Add the actors to the renderer, set the background and size
renderer->AddActor(clipActor);
renderer->AddActor(boundaryActor);
renderer->AddActor(restActor);
// Generate an interesting view
renderer->ResetCamera();
renderer->GetActiveCamera()->Azimuth(30);
renderer->GetActiveCamera()->Elevation(30);
renderer->GetActiveCamera()->Dolly(1.2);
renderer->ResetCameraClippingRange();
renderWindow->Render();
renderWindow->SetWindowName("CapClip");
renderWindow->Render();
interactor->Start();
}
};
int main()
{
Test_Clip_cow::Test();
return 0;
}
2、CMakeLists.txt
cmake_minimum_required(VERSION 3.3 FATAL_ERROR)
project(testfilter)
set(VTK_DIR D:/ProgramFiles/vtk-9.0/lib/cmake/vtk-9.0)
find_package(VTK COMPONENTS
vtkCommonColor
vtkCommonCore
vtkCommonDataModel
vtkFiltersSources
vtkIOImage
vtkImagingStencil
vtkFiltersCore
vtkRenderingCore
vtkFiltersHybrid
vtkInteractionStyle
vtkRenderingFreeType
vtkRenderingOpenGL2
vtkRenderingVolumeOpenGL2
vtkImagingCore
vtkImagingColor
vtkImagingSources
vtkInteractionStyle
vtkRenderingContextOpenGL2
vtkRenderingGL2PSOpenGL2
vtkRenderingCore
vtkIOGeometry
vtkIOXML
vtkIOPLY
QUIET
)
if (NOT VTK_FOUND)
message("Skipping testfilter: ${VTK_NOT_FOUND_MESSAGE}")
return()
endif()
message (STATUS "VTK_VERSION: ${VTK_VERSION}")
if (VTK_VERSION VERSION_LESS "8.90.0")
# old system
include(${VTK_USE_FILE})
endif()
file(GLOB_RECURSE mains ${CMAKE_CURRENT_SOURCE_DIR} *.cpp)
message(STATUS ${mains})
foreach(mainfile IN LISTS mains)
# Get file name without directory
get_filename_component(mainname ${mainfile} NAME_WE)
Message("mainname:", ${mainname})
add_executable(${mainname} ${mainfile})
target_link_libraries (${mainname} ${VTK_LIBRARIES})
# vtk_module_autoinit is needed
if (NOT VTK_VERSION VERSION_LESS "8.90.0")
# vtk_module_autoinit is needed
vtk_module_autoinit(
TARGETS ${mainname}
MODULES ${VTK_LIBRARIES}
)
endif()
endforeach()
3、运行输出
Surface Area:13.0365
4、面积正确性验证
从上面的例子不容易知道面积计算是否正确,下面换一个数据测试
4.1、代码
#pragma once
#include <vtkActor.h>
#include <vtkCamera.h>
#include <vtkClipPolyData.h>
#include <vtkDataSetMapper.h>
#include <vtkFeatureEdges.h>
#include <vtkNamedColors.h>
#include <vtkNew.h>
#include <vtkPlane.h>
#include <vtkPolyData.h>
#include <vtkPolyDataMapper.h>
#include <vtkProperty.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkRenderer.h>
#include <vtkSmartPointer.h>
#include <vtkSphereSource.h>
#include <vtkStripper.h>
#include <vtkXMLPolyDataReader.h>
#include <vtkMassProperties.h>
#include < vtkTriangleFilter.h>
#include <vtkCubeSource.h>
// Readers
#include <vtkBYUReader.h>
#include <vtkOBJReader.h>
#include <vtkPLYReader.h>
#include <vtkPolyDataReader.h>
#include <vtkSTLReader.h>
#include <vtkXMLPolyDataReader.h>
namespace {
vtkSmartPointer<vtkPolyData> ReadPolyData(std::string const& fileName)
{
vtkSmartPointer<vtkPolyData> polyData;
std::string extension = "";
if (fileName.find_last_of(".") != std::string::npos){
extension = fileName.substr(fileName.find_last_of("."));
}
// Make the extension lowercase
std::transform(extension.begin(), extension.end(), extension.begin(),::tolower);
if (extension == ".ply"){
vtkNew<vtkPLYReader> reader;
reader->SetFileName(fileName.c_str());
reader->Update();
polyData = reader->GetOutput();
}
else if (extension == ".vtp"){
vtkNew<vtkXMLPolyDataReader> reader;
reader->SetFileName(fileName.c_str());
reader->Update();
polyData = reader->GetOutput();
}
else if (extension == ".obj"){
vtkNew<vtkOBJReader> reader;
reader->SetFileName(fileName.c_str());
reader->Update();
polyData = reader->GetOutput();
}
else if (extension == ".stl"){
vtkNew<vtkSTLReader> reader;
reader->SetFileName(fileName.c_str());
reader->Update();
polyData = reader->GetOutput();
}
else if (extension == ".vtk"){
vtkNew<vtkPolyDataReader> reader;
reader->SetFileName(fileName.c_str());
reader->Update();
polyData = reader->GetOutput();
}
else if (extension == ".g"){
vtkNew<vtkBYUReader> reader;
reader->SetGeometryFileName(fileName.c_str());
reader->Update();
polyData = reader->GetOutput();
}
else{
// Return a polydata sphere if the extension is unknown.
vtkNew<vtkSphereSource> source;
source->SetThetaResolution(20);
source->SetPhiResolution(11);
source->Update();
polyData = source->GetOutput();
}
return polyData;
}
} // namespace
class Test_Clip_cow {
public:
static void Test() {
vtkNew<vtkNamedColors> colors;
auto backgroundColor = colors->GetColor3d("steel_blue");
auto boundaryColor = colors->GetColor3d("banana");
auto clipColor = colors->GetColor3d("tomato");
// PolyData to process
//auto polyData = ReadPolyData("cow.g");
vtkSmartPointer<vtkCubeSource> cubeSource =
vtkSmartPointer<vtkCubeSource>::New();
cubeSource->Update();
auto polyData = cubeSource->GetOutput();
vtkNew<vtkPlane> plane;
plane->SetOrigin(polyData->GetCenter());
plane->SetNormal(1.0, -1.0, -1.0);
vtkNew<vtkClipPolyData> clipper;
clipper->SetInputData(polyData);
clipper->SetClipFunction(plane);
clipper->GenerateClipScalarsOn();
clipper->GenerateClippedOutputOn();
clipper->SetValue(0.5);
clipper->Update();
polyData = clipper->GetOutput();
vtkNew<vtkDataSetMapper> clipMapper;
clipMapper->SetInputData(polyData);
clipMapper->ScalarVisibilityOff();
vtkNew<vtkActor> clipActor;
clipActor->SetMapper(clipMapper);
clipActor->GetProperty()->SetDiffuseColor(clipColor.GetData());
clipActor->GetProperty()->SetInterpolationToFlat();
clipActor->GetProperty()->EdgeVisibilityOn();
// Now extract feature edges
vtkNew<vtkFeatureEdges> boundaryEdges;
boundaryEdges->SetInputData(polyData);
boundaryEdges->BoundaryEdgesOn();
boundaryEdges->FeatureEdgesOff();
boundaryEdges->NonManifoldEdgesOff();
boundaryEdges->ManifoldEdgesOff();
vtkNew<vtkStripper> boundaryStrips;
boundaryStrips->SetInputConnection(boundaryEdges->GetOutputPort());
boundaryStrips->Update();
// Change the polylines into polygons
vtkNew<vtkPolyData> boundaryPoly;
boundaryPoly->SetPoints(boundaryStrips->GetOutput()->GetPoints());
boundaryPoly->SetPolys(boundaryStrips->GetOutput()->GetLines());
vtkNew<vtkPolyDataMapper> boundaryMapper;
boundaryMapper->SetInputData(boundaryPoly);
vtkNew<vtkActor> boundaryActor;
boundaryActor->SetMapper(boundaryMapper);
boundaryActor->GetProperty()->SetDiffuseColor(boundaryColor.GetData());
vtkNew<vtkTriangleFilter> triFilter;
triFilter->SetInputData(boundaryPoly);
triFilter->Update();
vtkSmartPointer<vtkMassProperties> massProp =
vtkSmartPointer<vtkMassProperties>::New();
massProp->SetInputData(triFilter->GetOutput());
float vol = massProp->GetVolume();
float area = massProp->GetSurfaceArea();
std::cout << "Surface Area:" << area << std::endl;
vtkNew<vtkPolyDataMapper> restMapper;
restMapper->SetInputConnection(clipper->GetClippedOutputPort());
restMapper->ScalarVisibilityOff();
vtkNew<vtkActor> restActor;
restActor->SetMapper(restMapper);
restActor->GetProperty()->SetRepresentationToWireframe();
// Create graphics stuff
vtkNew<vtkRenderer> renderer;
renderer->SetBackground(backgroundColor.GetData());
renderer->UseHiddenLineRemovalOn();
vtkNew<vtkRenderWindow> renderWindow;
renderWindow->AddRenderer(renderer);
renderWindow->SetSize(640, 480);
vtkNew<vtkRenderWindowInteractor> interactor;
interactor->SetRenderWindow(renderWindow);
// Add the actors to the renderer, set the background and size
renderer->AddActor(clipActor);
renderer->AddActor(boundaryActor);
renderer->AddActor(restActor);
// Generate an interesting view
renderer->ResetCamera();
renderer->GetActiveCamera()->Azimuth(30);
renderer->GetActiveCamera()->Elevation(30);
renderer->GetActiveCamera()->Dolly(1.2);
renderer->ResetCameraClippingRange();
renderWindow->Render();
renderWindow->SetWindowName("CapClip");
renderWindow->Render();
interactor->Start();
}
};
int main()
{
Test_Clip_cow::Test();
return 0;
}
4.2、执行结果
Surface Area:0.866025
正方体过三个顶点的截面,截面面积 0.866025 0.866025 0.866025
根据计算三角形面积的海伦公式
S = p ( p − a ) ( p − b ) ( p − c ) S = \sqrt{p(p-a)(p-b)(p-c)} S=p(p−a)(p−b)(p−c)
其中
a = b = c = 2 a = b = c = \sqrt{2} a=b=c=2
p = a + b + c 2 p = \frac{a+b+c}{2} p=2a+b+c
代入海伦公式,可以求得三角形面积为 3 2 = 0.866025 \frac{\sqrt{3}}{2} = 0.866025 23=0.866025