VTK 三角剖分 Delaunay2D(六)—— 改进的折线裁剪封闭曲面

65 篇文章 10 订阅
39 篇文章 7 订阅

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();

裁剪结果:

1

提取截面上下两条折线点集

另辟蹊径,采用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();

如图所示:

2

截面的填补

经过尝试各种方式,采用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();

结果如图所示:

3

合并显示

 vtkSmartPointer<vtkAppendPolyData> appendFilter = vtkSmartPointer<vtkAppendPolyData>::New();
  appendFilter->AddInputData(clipper->GetOutput());
  appendFilter->AddInputData(Mesh);
  appendFilter->Update();

结果如下:

4

构建 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})

文件结构:

5

参考

  1. VTK 三角剖分 Delaunay2D (一)
  2. VTK 三角剖分 Delaunay2D (二)
  3. VTK 三角剖分 Delaunay2D (三)—— 自定义Filter类
  4. VTK 三角剖分 Delaunay2D(四)—— 切面(cut)与切割(clip)
  5. VTK 三角剖分 Delaunay2D(五)—— 折线裁剪封闭曲面
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值