VTK 三角剖分 Delaunay2D(六)—— 改进的折线裁剪封闭曲面
引言
由vtkPolyLine
生成vtkPolyPlane
,作为vtkClipPolyData
的裁剪函数输入,对vtkPolyData
进行裁剪,并对截面进行填补。
截面的填补采用上下两条折线点的集合,依次比较形成的四边形对角线的长度来生成三角网。
具体步骤
裁剪数据源的生成
/*===========================================================================
* 模拟生成三角网
* 1. 随机生成点集
* 2. 获取生成三角网的边界环点集(有序)
*===========================================================================/
/*
第一三角剖分
*/
vtkSmartPointer<vtkPoints> ps1 =vtkSmartPointer<vtkPoints>::New();
unsigned int GridSize = 10;
for(unsigned int x = 0; x < GridSize; x++)
{
for(unsigned int y = 0; y < GridSize; y++)
{
ps1->InsertNextPoint(x, y, vtkMath::Random(-.25, .25));
}
}
vtkSmartPointer<vtkPolyData> polydata1 =vtkSmartPointer<vtkPolyData>::New();
polydata1->SetPoints(ps1);
vtkSmartPointer<vtkDelaunay2D> delaunay1 =vtkSmartPointer<vtkDelaunay2D>::New();
delaunay1->SetInputData(polydata1);
delaunay1->Update();
/*
第二个三角剖分
*/
vtkSmartPointer<vtkPoints> pts2 = vtkSmartPointer<vtkPoints>::New();
GridSize =9;
for (unsigned int x =1; x < GridSize; x++)
{
for (unsigned int y =1; y < GridSize; y++)
{
pts2->InsertNextPoint(x + vtkMath::Random(-.25, 1.25), y +
vtkMath::Random(-.25, 1.25), vtkMath::Random(1.5, 1.75));
}
}
vtkSmartPointer<vtkPolyData> polydata2 = vtkSmartPointer<vtkPolyData>::New();
polydata2->SetPoints(pts2);
vtkSmartPointer<vtkDelaunay2D> delaunay2 = vtkSmartPointer<vtkDelaunay2D>::New();
delaunay2->SetInputData(polydata2);
delaunay2->Update();
// 两个三角网的合并
vtkSmartPointer<vtkTestAlgorithmFilter>testAlgorithm = vtkSmartPointer<vtkTestAlgorithmFilter>::New();
testAlgorithm->SetInputData(0, delaunay1->GetOutput()); //输入第一个三角剖分的结果
testAlgorithm->SetInputData(1, delaunay2->GetOutput());//输入第二个三角剖分的结果
testAlgorithm->Update();
折线的生成
double pt0[3] = { -2.0, 2.0, 2.0 };
double pt1[3] = { 5.0, 2.0, 2.0 };
double pt2[3] = { 6.0,3.0, 2.0 };
double pt3[3] = { 8.0, 5.0, 2.0 };
double pt4[3] = { 8.0, 10.0, 2.0 };
vtkSmartPointer<vtkPoints>polyline_pts =vtkSmartPointer<vtkPoints>::New();
polyline_pts->InsertNextPoint(pt0);
polyline_pts->InsertNextPoint(pt1);
polyline_pts->InsertNextPoint(pt2);
polyline_pts->InsertNextPoint(pt3);
polyline_pts->InsertNextPoint(pt4);
vtkSmartPointer<vtkPolyLine> polyline =vtkSmartPointer<vtkPolyLine>::New();
polyline->GetPointIds()->SetNumberOfIds(5);
for (unsigned int i = 0; i < 5; i++)
{
polyline->GetPointIds()->SetId(i, i);
}
vtkSmartPointer<vtkCellArray> cells =vtkSmartPointer<vtkCellArray>::New();
cells->InsertNextCell(polyline);
vtkSmartPointer<vtkPolyData> polylineData =vtkSmartPointer<vtkPolyData>::New();
polylineData->SetPoints(polyline_pts);
polylineData->SetLines(cells);
//Visualization : Setup actor and mapper
vtkSmartPointer<vtkPolyDataMapper> polyline_mapper =vtkSmartPointer<vtkPolyDataMapper>::New();
polyline_mapper->SetInputData(polylineData);
vtkSmartPointer<vtkActor>polyline_actor =vtkSmartPointer<vtkActor>::New();
polyline_actor->SetMapper(polyline_mapper);
polyline_actor->GetProperty()->SetColor(10, 0, 0);
polyline_actor->GetProperty()->SetLineWidth(5);
进行裁剪
//提取折线并进行裁剪
vtkSmartPointer<vtkPolyLine> PolyLine = vtkSmartPointer<vtkPolyLine>::New();
PolyLine = vtkPolyLine::SafeDownCast(polylineData->GetCell(0));
//clip
vtkSmartPointer<vtkPolyPlane>polyPlane = vtkSmartPointer<vtkPolyPlane>::New();
polyPlane->SetPolyLine(PolyLine);
vtkSmartPointer<vtkClipPolyData>clipper = vtkSmartPointer<vtkClipPolyData>::New();
clipper->SetInputData(testAlgorithm->GetOutput());
clipper->SetClipFunction(polyPlane);
clipper->Update();
裁剪结果:
提取截面上下两条折线点集
另辟蹊径,采用vtkCutter
获取。
//cutter
vtkSmartPointer<vtkCutter> cutter1 =
vtkSmartPointer<vtkCutter>::New();
cutter1->SetCutFunction(polyPlane);
cutter1->SetInputData(delaunay1->GetOutput());
cutter1->Update();
vtkSmartPointer<vtkCutter> cutter2 =
vtkSmartPointer<vtkCutter>::New();
cutter2->SetCutFunction(polyPlane);
cutter2->SetInputData(delaunay2->GetOutput());
cutter2->Update();
vtkSmartPointer<vtkStripper> stripper1 = vtkSmartPointer<vtkStripper>::New();
stripper1->SetInputConnection(cutter1->GetOutputPort());
stripper1->Update();
vtkSmartPointer<vtkCleanPolyData> cleanPolyData1 = vtkSmartPointer<vtkCleanPolyData>::New();
cleanPolyData1->SetInputConnection(stripper1->GetOutputPort());
cleanPolyData1->Update();
vtkSmartPointer<vtkStripper> stripper2 = vtkSmartPointer<vtkStripper>::New();
stripper2->SetInputConnection(cutter2->GetOutputPort());
stripper2->Update();
vtkSmartPointer<vtkCleanPolyData> cleanPolyData2 = vtkSmartPointer<vtkCleanPolyData>::New();
cleanPolyData2->SetInputConnection(stripper2->GetOutputPort());
cleanPolyData2->Update();
如图所示:
截面的填补
经过尝试各种方式,采用VTK 三角剖分 Delaunay2D (二)中介绍的方法。
/*
* 由上下两个边界生成三角网
* 原则:按照最短对角线原则
* 方法:上下两个边界环,依次组成四边形,比较对角线的大小,生成三角形
*/
vtkPoints *boundary = vtkPoints::New();
double*p;
unsigned int num1, num2;
vtkSmartPointer<vtkPoints> boundary1 = cleanPolyData1->GetOutput()->GetPoints();
vtkSmartPointer<vtkPoints> boundary2 = cleanPolyData2->GetOutput()->GetPoints();
num1 = boundary1->GetNumberOfPoints();
num2 = boundary2->GetNumberOfPoints();
for (unsigned int i = 0; i < num1; ++i) {
p = boundary1->GetPoint(i);
boundary->InsertNextPoint(p);
}
for (unsigned int i = 0; i < num2; ++i) {
p = boundary2->GetPoint(i);
boundary->InsertNextPoint(p);
}
vtkIdType pts[3]; //保存三角形三个顶点的索引
vtkCellArray* triangles = vtkCellArray::New();
vtkPolyData* Mesh = vtkPolyData::New();
triangles->Allocate(triangles->EstimateSize(2 * (num1 + num2), 3));
Mesh->SetPoints(boundary);
Mesh->SetPolys(triangles);
double d0 = 0.0, d1 = 0.0; //保存四边形两条对角线的长度
double p1[3], p2[3], p3[3], p4[3]; //四边形的四个顶点
unsigned int n1 = 0, n2 = 0; //上下边界环当前遍历的位置
unsigned int start1 = 0, start2 = 0;//上下边界环遍历的起始位置
//寻找两条边的起始位置 start1,start2 (距离裁剪折线起点最近的点为起点)
d1 = VTK_DOUBLE_MAX;
polylineData->GetPoint(0, p1);
for (unsigned int i = 0; i < num1; ++i) {
boundary1->GetPoint(i, p2);
d0 = vtkMath::Distance2BetweenPoints(p1, p2);
if (d0 < d1) {
d1 = d0;
start1 = i;
}
}
d1 = VTK_DOUBLE_MAX;
for (unsigned int i = 0; i < num2; ++i) {
boundary2->GetPoint(i, p2);
d0 = vtkMath::Distance2BetweenPoints(p1, p2);
if (d0 < d1) {
d1 = d0;
start2 = i;
}
}
n2 = start2;
n1 = start1;
bool flag = false;
do {
// 组成四边形的四个点
// p1,p2 一条边界环的点
// p3,p4 另一条边界环的点
boundary1->GetPoint(n1, p1);
boundary1->GetPoint((n1 + 1) % num1, p2);
boundary2->GetPoint(n2, p3);
boundary2->GetPoint((n2 + 1) % num2, p4);
d0 = vtkMath::Distance2BetweenPoints(p1, p4);
d1 = vtkMath::Distance2BetweenPoints(p2, p3);
pts[0] = n1%num1;
pts[1] = n2%num2 + num1;
if (d0 <= d1) {
pts[2] = (n2 + 1) % num2 + num1;
n2 = (n2 + 1) % num2;
}
else {
pts[2] = (n1 + 1) % num1;
n1 = (n1 + 1) % num1;
}
triangles->InsertNextCell(3, pts);
flag = !(( (n1 + 1) % num1 == start1) && ( (n2 + 1) % num2 == start2));
} while (flag);
Mesh->BuildLinks();
结果如图所示:
合并显示
vtkSmartPointer<vtkAppendPolyData> appendFilter = vtkSmartPointer<vtkAppendPolyData>::New();
appendFilter->AddInputData(clipper->GetOutput());
appendFilter->AddInputData(Mesh);
appendFilter->Update();
结果如下:
构建 CMakeLists.txt
cmake_minimum_required(VERSION 3.3 FATAL_ERROR)
project(ClipSurfaceByPolyline)
find_package(VTK REQUIRED)
include(${VTK_USE_FILE})
add_executable(ClipSurfaceByPolyline ClipSurfaceByPolyline.cxx vtkTestAlgorithmFilter.h vtkTestAlgorithmFilter.cxx)
target_link_libraries(ClipSurfaceByPolyline ${VTK_LIBRARIES})
文件结构: