这篇笔记和之前的一篇笔记,VTK笔记——多边形剪切(vtkClipPolyData),都是关于多边形处理的,但不同的是后者是用封闭的点线来剪切。点线剪切可以在多边形上任意剪切掉一部分,显得比较灵活,就像下面示意这样。A)可以在多边形的中间剪出一个洞,B)也可在多边形边缘剪掉一块。
我们知道,多边形是由点(points)和面片(cells)组成的。剪切的本身就是对多边形的这些数据进行处理。而在实际应用中,还有更多问题需要考虑。比如,切线是是否是任意的,需不需要过顶点,如果没在顶点上,那是否又需要拆分三角形等等。
vtkSelectPolyData
vtk中,vtkSelectPolyData,有一个用于多边形剪切的类
关于它的描述:
select portion of polygonal mesh; generate selection scalars
vtkSelectPolyData is a filter that selects polygonal data based on defining a “loop” and indicating the region inside of the loop. The mesh within the loop consists of complete cells (the cells are not cut). Alternatively, this filter can be used to generate scalars. These scalar values, which are a distance measure to the loop, can be used to clip, contour. or extract data (i.e., anything that an implicit function can do).
The loop is defined by an array of x-y-z point coordinates. (Coordinates should be in the same coordinate space as the input polygonal data.) The loop can be concave and non-planar, but not self-intersecting. The input to the filter is a polygonal mesh (only surface primitives such as triangle strips and polygons); the output is either a) a portion of the original mesh laying within the selection loop (GenerateSelectionScalarsOff); or b) the same polygonal mesh with the addition of scalar values (GenerateSelectionScalarsOn).
The algorithm works as follows. For each point coordinate in the loop, the closest point in the mesh is found. The result is a loop of closest point ids from the mesh. Then, the edges in the mesh connecting the closest points (and laying along the lines forming the loop) are found. A greedy edge tracking procedure is used as follows. At the current point, the mesh edge oriented in the direction of and whose end point is closest to the line is chosen. The edge is followed to the new end point, and the procedure is repeated. This process continues until the entire loop has been created.
To determine what portion of the mesh is inside and outside of the loop, three options are possible. 1) the smallest connected region, 2) the largest connected region, and 3) the connected region closest to a user specified point. (Set the ivar SelectionMode.)
Once the loop is computed as above, the GenerateSelectionScalars controls the output of the filter. If on, then scalar values are generated based on distance to the loop lines. Otherwise, the cells laying inside the selection loop are output. By default, the mesh laying within the loop is output; however, if InsideOut is on, then the portion of the mesh laying outside of the loop is output.
The filter can be configured to generate the unselected portions of the mesh as output by setting GenerateUnselectedOutput. Use the method GetUnselectedOutput to access this output. (Note: this flag is pertinent only when GenerateSelectionScalars is off.)
简单总结一下:
- 选择多边形网格的一部分,输出部分多边形网格或标量,由GenerateSelectionScalarsOn/Off决定
- 网格的选取是通过一个环(loop)来指定的,可以是凹的和非平面的,但不能自相交
- 要确定选择网格的那个部分,有三种方式:1)最小连通区域,2)最大连通区域,3)最接近用户选取的连通区域。通过SelectionMode设置
- 默认是输出环内的网格,不过,可以通过InsideOut设置输出环外的网格
- 也可以输出未选取的部分,由GenerateUnselectedOutput决定
- 确保选取的点在一个连通的表面上,否则结果将为空。另外,自相交的结果不可预料
主要代码
构造点
vtkSmartPointer<vtkPoints> loopPoints =
vtkSmartPointer<vtkPoints>::New();
loopPoints->InsertNextPoint(-0.16553, 0.135971, 0.451972);
loopPoints->InsertNextPoint(-0.0880123, -0.134952, 0.4747);
设置剪切
vtkSmartPointer<vtkSelectPolyData> selectPolyData =
vtkSmartPointer<vtkSelectPolyData>::New();
selectPolyData->SetInputConnection(sphereSource->GetOutputPort());
selectPolyData->SetLoop(loopPoints);
selectPolyData->GenerateUnselectedOutputOn();
selectPolyData->SetSelectionModeToSmallestRegion(); //negative scalars inside
selectPolyData->Update();
获取剪切数据
selectPolyData->GetOutputPort();
selectPolyData->GetUnselectedOutput()
效果
实际使用过程中,loop的点可能是通过交互进行拾取的。
示例代码
#include <vtkSmartPointer.h>
#include <vtkProperty.h>
#include <vtkSelectPolyData.h>
#include <vtkSphereSource.h>
#include <vtkClipPolyData.h>
#include <vtkProperty.h>
#include <vtkPolyDataMapper.h>
#include <vtkLODActor.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkRenderWindow.h>
#include <vtkRenderer.h>
#include <vtkNamedColors.h>
int main(int, char *[])
{
vtkSmartPointer<vtkNamedColors> colors =
vtkSmartPointer<vtkNamedColors>::New();
vtkSmartPointer<vtkSphereSource> sphereSource =
vtkSmartPointer<vtkSphereSource>::New();
sphereSource->SetPhiResolution(50);
sphereSource->SetThetaResolution(100);
sphereSource->Update();
vtkSmartPointer<vtkPoints> loopPoints =
vtkSmartPointer<vtkPoints>::New();
loopPoints->InsertNextPoint(-0.16553, 0.135971, 0.451972);
loopPoints->InsertNextPoint(-0.0880123, -0.134952, 0.4747);
loopPoints->InsertNextPoint(0.00292618, -0.134604, 0.482459);
loopPoints->InsertNextPoint(0.0641941, 0.067112, 0.490947);
loopPoints->InsertNextPoint(0.15577, 0.0734765, 0.469245);
loopPoints->InsertNextPoint(0.166667, -0.129217, 0.454622);
loopPoints->InsertNextPoint(0.241259, -0.123363, 0.420581);
loopPoints->InsertNextPoint(0.240334, 0.0727106, 0.432555);
loopPoints->InsertNextPoint(0.308529, 0.0844311, 0.384357);
loopPoints->InsertNextPoint(0.32672, -0.121674, 0.359187);
loopPoints->InsertNextPoint( 0.380721, -0.117342, 0.302527);
loopPoints->InsertNextPoint( 0.387804, 0.0455074, 0.312375);
loopPoints->InsertNextPoint( 0.43943, -0.111673, 0.211707);
loopPoints->InsertNextPoint( 0.470984, -0.0801913, 0.147919);
loopPoints->InsertNextPoint( 0.436777, 0.0688872, 0.233021);
loopPoints->InsertNextPoint( 0.44874, 0.188852, 0.109882);
loopPoints->InsertNextPoint( 0.391352, 0.254285, 0.176943);
loopPoints->InsertNextPoint( 0.373274, 0.154162, 0.294296);
loopPoints->InsertNextPoint( 0.274659, 0.311654, 0.276609);
loopPoints->InsertNextPoint( 0.206068, 0.31396, 0.329702);
loopPoints->InsertNextPoint( 0.263789, 0.174982, 0.387308);
loopPoints->InsertNextPoint( 0.213034, 0.175485, 0.417142);
loopPoints->InsertNextPoint( 0.169113, 0.261974, 0.390286);
loopPoints->InsertNextPoint( 0.102552, 0.25997, 0.414814);
loopPoints->InsertNextPoint( 0.131512, 0.161254, 0.454705);
loopPoints->InsertNextPoint( 0.000192443, 0.156264, 0.475307);
loopPoints->InsertNextPoint( -0.0392091, 0.000251724, 0.499943);
loopPoints->InsertNextPoint( -0.096161, 0.159646, 0.46438);
vtkSmartPointer<vtkSelectPolyData> selectPolyData =
vtkSmartPointer<vtkSelectPolyData>::New();
selectPolyData->SetInputConnection(sphereSource->GetOutputPort());
selectPolyData->SetLoop(loopPoints);
selectPolyData->GenerateUnselectedOutputOn();
selectPolyData->SetSelectionModeToSmallestRegion(); //negative scalars inside
selectPolyData->Update();
vtkSmartPointer<vtkProperty> backProp =
vtkSmartPointer<vtkProperty>::New();
backProp->SetColor(colors->GetColor3d("tomato").GetData());
vtkSmartPointer<vtkPolyDataMapper> selectMapper =
vtkSmartPointer<vtkPolyDataMapper>::New();
selectMapper->SetInputData(selectPolyData->GetUnselectedOutput());
//selectMapper->ScalarVisibilityOff();
vtkSmartPointer<vtkLODActor> selectActor =
vtkSmartPointer<vtkLODActor>::New();
selectActor->SetMapper(selectMapper);
selectActor->SetBackfaceProperty(backProp);
selectActor->GetProperty()->SetColor(colors->GetColor3d("banana").GetData());
vtkSmartPointer<vtkPolyDataMapper> unselectMapper =
vtkSmartPointer<vtkPolyDataMapper>::New();
unselectMapper->SetInputConnection(selectPolyData->GetOutputPort());
//unselectMapper->ScalarVisibilityOff();
vtkSmartPointer<vtkLODActor> unselectActor =
vtkSmartPointer<vtkLODActor>::New();
unselectActor->SetMapper(unselectMapper);
unselectActor->SetBackfaceProperty(backProp);
unselectActor->GetProperty()->SetColor(colors->GetColor3d("banana").GetData());
vtkSmartPointer<vtkRenderer> renderer1 =
vtkSmartPointer<vtkRenderer>::New();
vtkSmartPointer<vtkRenderer> renderer2 =
vtkSmartPointer<vtkRenderer>::New();
vtkSmartPointer<vtkRenderWindow> renderWindow =
vtkSmartPointer<vtkRenderWindow>::New();
renderWindow->AddRenderer(renderer1);
renderWindow->AddRenderer(renderer2);
vtkSmartPointer<vtkRenderWindowInteractor> interactor =
vtkSmartPointer<vtkRenderWindowInteractor>::New();
interactor->SetRenderWindow(renderWindow);
// Add the actors to the renderer, set the background and size
renderer1->AddActor (selectActor);
renderer1->SetBackground (colors->GetColor3d("slate_grey").GetData());
renderer1->SetViewport(0, 0, 0.5, 1);
renderer2->AddActor(unselectActor);
renderer2->SetBackground(colors->GetColor3d("slate_blue").GetData());
renderer2->SetViewport(0.5, 0, 1, 1);
renderWindow->SetSize (800, 400);
renderWindow->Render();
interactor->Start();
return EXIT_SUCCESS;
}