vtkAppendPolyData将两条线连接合并为一条连通线
将两条单独的vtkLineSource连接合并为一条线,合并后的线能够顶点与顶点是连通的,连通分区为1。
效果预览
方法介绍
vtkLineSource的数据实际上也是vtkPolyData,合并vtkPolyData自然要用到vtkAppendPolyData工具,但是只使用vtkAppendPolyData工具的话,只是简单把模型数据堆在一个vtkPolyData里作为整体包装,实际上检查后发现结果vtkPolyData还是由多个连通分区组成,意思是合并后多个vtkPolyData并没有连接在一起。
所以关键一步是使用vtkAppendPolyData后,还需要使用vtkCleanPolyData工具去处理连接结果。
要使得模型直接真正连通,需要vtkPolyData之间存在相同坐标的顶点(例如两个模型是分开的,那vtk并不会自动帮你增加连接线将模型连接起来,换句话说,连接线需要自己准备),因为vtkCleanPolyData的作用是去掉模型上重复坐标的顶点,去掉后会把断开的cell接上。
要确认是否连接成为一个连通的模型,可以用vtkPolyDataConnectivityFilter检查vtkPolyData有多少个连通分区,如果连通分区为1,表示模型所有顶点都是连接起来的。
源代码
源代码完整,可以直接复制粘贴编译运行。支持更多顶点的vtkLineSource。想对两个三维模型连接的话,需要改造一下源代码。
//两线段连接
#include <vtkPolyDataConnectivityFilter.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkPolyDataMapper.h>
#include <vtkAppendPolyData.h>
#include <vtkCleanPolyData.h>
#include <vtkRenderWindow.h>
#include <vtkSmartPointer.h>
#include <vtkLineSource.h>
#include <vtkPolyData.h>
#include <vtkRenderer.h>
#include <vtkActor.h>
#include <vtkNew.h>
vtkSmartPointer<vtkPolyData> CombineLineData(vtkSmartPointer<vtkPolyData> source1, vtkSmartPointer<vtkPolyData> source2)
{
cout << "开始连接" << endl;
//找出距离最小点对,画一条连接线,然后合并
vtkIdType a = -1, b = -1;
double minDist = VTK_DOUBLE_MAX;
for (vtkIdType i = 0; i < source1->GetNumberOfPoints(); i++)
{
for (vtkIdType j = 0; j < source2->GetNumberOfPoints(); j++)
{
double p[3], q[3];
source1->GetPoint(i, p);
source2->GetPoint(j, q);
double dist2 = vtkMath::Distance2BetweenPoints(p, q);
if (dist2 < minDist)
{
a = i;
b = j;
minDist = dist2;
}
}
}
//验证a,b确实是两路径的端点
vtkNew<vtkIdList> aCells, bCells;
source1->GetPointCells(a, aCells);
source2->GetPointCells(b, bCells);
if (aCells->GetNumberOfIds() != 1 || bCells->GetNumberOfIds() != 1)
{
cout << "非端点" << endl;
return source1->GetNumberOfCells() > source2->GetNumberOfCells() ? source1 : source2;
}
//创建两输入模型之间的连接线
double p[3], q[3];
source1->GetPoint(a, p);
source2->GetPoint(b, q);
vtkSmartPointer<vtkLineSource> line = vtkSmartPointer<vtkLineSource>::New();
line->SetPoint1(p);
line->SetPoint2(q);
line->Update();
//连接操作
vtkSmartPointer<vtkAppendPolyData> append = vtkSmartPointer<vtkAppendPolyData>::New();
append->AddInputData(source1);
append->AddInputData(line->GetOutput());
append->AddInputData(source2);
vtkSmartPointer<vtkCleanPolyData> clean = vtkSmartPointer <vtkCleanPolyData>::New();
clean->SetInputConnection(append->GetOutputPort());
clean->Update();
clean->GetOutput()->BuildLinks();
vtkNew<vtkPolyDataConnectivityFilter> temp;
temp->SetInputData(clean->GetOutput());
temp->SetExtractionModeToAllRegions();
temp->Update();
cout << "连接后连通分区数量:" << temp->GetNumberOfExtractedRegions() << endl;
cout << "连接前source1顶点数量:" << source1->GetNumberOfPoints() << ",Cell数量:" << source1->GetNumberOfCells() << endl;
cout << "连接前source2顶点数量:" << source2->GetNumberOfPoints() << ",Cell数量:" << source2->GetNumberOfCells() << endl;
cout << "连接后result顶点数量:" << clean->GetOutput()->GetNumberOfPoints() << ",Cell数量:" << clean->GetOutput()->GetNumberOfCells() << endl;
return clean->GetOutput();
}
int main()
{
//创建两条分开的线
vtkSmartPointer<vtkLineSource> line1 = vtkSmartPointer<vtkLineSource>::New();
line1->SetPoint1(-2, 0, 1);
line1->SetPoint2(-1, 1, 1);
line1->Update();
vtkSmartPointer<vtkLineSource> line2 = vtkSmartPointer<vtkLineSource>::New();
line2->SetPoint1(2, 0, 1);
line2->SetPoint2(1, 1, 1);
line2->Update();
vtkSmartPointer<vtkPolyData> result = CombineLineData(line1->GetOutput(), line2->GetOutput());
vtkNew<vtkPolyDataMapper> mapper;
mapper->SetInputData(result);
vtkNew<vtkActor> actor;
actor->SetMapper(mapper);
vtkNew<vtkRenderer> renderer;
renderer->AddActor(actor);
vtkNew<vtkRenderWindow> rw;
rw->AddRenderer(renderer);
vtkNew<vtkRenderWindowInteractor> renderWindowInteractor;
renderWindowInteractor->SetRenderWindow(rw);
rw->Render();
renderWindowInteractor->Start();
}