VTK 三角剖分 Delaunay2D(九)—— 籬笆圖(等距切割)

VTK 三角剖分 Delaunay2D(九)—— 籬笆圖(等距切割)

Description

對輸入的三維模型在某個方向等間距提取模型的切面輪廓線,並分別提取輪廓線生成截面。
關鍵點:

  • 計算切割的Range(num,min,max)
  • 分離輪廓線
  • 輪廓線的三角剖分(等高線的三角剖分)vtkContourTriangulator

Code

Create Test Model

/*
 構建封閉表面(上下三角網和側面三角網)
*/
vtkSmartPointer<vtkPolyData> createBody() {

	//生成第一個三角網
	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 + vtkMath::Random(.1, .2),
				y + vtkMath::Random(.1, .2), 
				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<vtkFeatureEdges> featureEdges1 = vtkSmartPointer<vtkFeatureEdges>::New();
	featureEdges1->SetInputConnection(delaunay1->GetOutputPort());
	featureEdges1->BoundaryEdgesOn();
	featureEdges1->FeatureEdgesOff();
	featureEdges1->ManifoldEdgesOff();
	featureEdges1->NonManifoldEdgesOff();
	featureEdges1->Update();

	//條帶化
	vtkSmartPointer<vtkStripper> stripper1 = vtkSmartPointer<vtkStripper>::New();
	stripper1->SetInputConnection(featureEdges1->GetOutputPort());

	vtkSmartPointer<vtkCleanPolyData> cleanPolyData1 =
		vtkSmartPointer<vtkCleanPolyData>::New();
	cleanPolyData1->SetInputConnection(stripper1->GetOutputPort());
	cleanPolyData1->Update();

	//拷貝到邊界點集中
	vtkSmartPointer<vtkPoints> boundary = vtkSmartPointer<vtkPoints>::New();
	vtkPoints *pt = cleanPolyData1->GetOutput()->GetPoints();
	int num = pt->GetNumberOfPoints();
	for (int i = 0; i < num; ++i) {
		double *p = pt->GetPoint(i);
		boundary->InsertNextPoint(p);
	}


	//生成第二個三角網
	vtkSmartPointer<vtkPoints> pts2 = vtkSmartPointer<vtkPoints>::New();
	for (unsigned int x = 0; x < GridSize; x++)
	{
		for (unsigned int y = 0; y < GridSize; y++)
		{
			pts2->InsertNextPoint(
				x + vtkMath::Random(.1, .2),
				y + vtkMath::Random(.1, .2), 
				vtkMath::Random(.5, .75)
			);
		}
	}
	vtkSmartPointer<vtkPolyData> polydata2 = vtkSmartPointer<vtkPolyData>::New();
	polydata2->SetPoints(pts2);
	vtkSmartPointer<vtkDelaunay2D> delaunay2 = vtkSmartPointer<vtkDelaunay2D>::New();
	delaunay2->SetInputData(polydata2);
	delaunay2->Update();


	vtkSmartPointer<vtkFeatureEdges> featureEdges2 = vtkSmartPointer<vtkFeatureEdges>::New();
	featureEdges2->SetInputConnection(delaunay2->GetOutputPort());
	featureEdges2->BoundaryEdgesOn();
	featureEdges2->FeatureEdgesOff();
	featureEdges2->ManifoldEdgesOff();
	featureEdges2->NonManifoldEdgesOff();
	featureEdges2->Update();

	vtkSmartPointer<vtkStripper> stripper2 = vtkSmartPointer<vtkStripper>::New();
	stripper2->SetInputConnection(featureEdges2->GetOutputPort());

	vtkSmartPointer<vtkCleanPolyData> cleanPolyData2 = vtkSmartPointer<vtkCleanPolyData>::New();
	cleanPolyData2->SetInputConnection(stripper2->GetOutputPort());
	cleanPolyData2->Update();
	//將第二個邊界點集拷貝到邊界點集中

	pt = cleanPolyData2->GetOutput()->GetPoints();
	num = pt->GetNumberOfPoints();
	for (int i = 0; i < num; ++i) {
		double *p = pt->GetPoint(i);
		boundary->InsertNextPoint(p);
	}

	//邊界點集生成新的拓撲單元
	vtkCellArray* cells = vtkCellArray::New();
	vtkTriangle* vtkTriangle;

	for (int i = 0; i < num; ++i) {

		vtkTriangle = vtkTriangle::New();
		vtkTriangle->GetPointIds()->SetId(0, i);
		vtkTriangle->GetPointIds()->SetId(1, ((i + 1) % num));
		vtkTriangle->GetPointIds()->SetId(2, (num + i));

		cells->InsertNextCell(vtkTriangle);

		vtkTriangle = vtkTriangle::New();
		vtkTriangle->GetPointIds()->SetId(0, ((i + 1) % num));
		vtkTriangle->GetPointIds()->SetId(1, ((i + 1) % num + num));
		vtkTriangle->GetPointIds()->SetId(2, (num + i));

		cells->InsertNextCell(vtkTriangle);
	}
	vtkPolyData* trianglePolyData = vtkPolyData::New();

	trianglePolyData->SetPoints(boundary);
	trianglePolyData->SetPolys(cells);

	// combine two poly data
	// 上下三角網和側面三角網組合
	vtkSmartPointer<vtkAppendPolyData> appendFilter = vtkSmartPointer<vtkAppendPolyData>::New();
	appendFilter->AddInputData(delaunay1->GetOutput());
	appendFilter->AddInputData(delaunay2->GetOutput());
	appendFilter->AddInputData(trianglePolyData);
	appendFilter->Update();
	return appendFilter->GetOutput();
}

Realized

/*
* 對輸入的三維模型在某個方向等間距提取模型的切面輪廓線,並生成截面
* @param inputdata 輸入模型
* @param origin 切割起點
* @param dest 切割終點
* @param direction 切割方向
* @param count 切割個數
*/
vtkSmartPointer<vtkPolyData> equidistanceCut(vtkSmartPointer<vtkPolyData>inputPolyData,
	double* origin, double* dest, double * direction, int count) {

	//得到輸入的模型的最小座標
	double minBound[3];

	minBound[0] = inputPolyData->GetBounds()[0];
	minBound[1] = inputPolyData->GetBounds()[2];
	minBound[2] = inputPolyData->GetBounds()[4];

	//創建切割平面
	vtkSmartPointer<vtkPlane> plane = vtkSmartPointer<vtkPlane>::New();
	//設置切割平面起點
	plane->SetOrigin(origin);
	//設置切割方向
	plane->SetNormal(direction);

	double result[3];
	vtkMath::Subtract(origin, minBound, result);
	//計算座標在平面法向量上的最大最小距離
	double distanceMin = vtkMath::Dot(result, plane->GetNormal());
	vtkMath::Subtract(dest, minBound, result);
	double distanceMax = vtkMath::Dot(result, plane->GetNormal());
	//創建模型切割器
	vtkSmartPointer<vtkCutter> cutter = vtkSmartPointer<vtkCutter>::New();
	cutter->SetCutFunction(plane);//設置切割平面
	cutter->SetInputData(inputPolyData);//設置模型
	cutter->GenerateValues(count, distanceMin, distanceMax);

	vtkSmartPointer<vtkStripper> stripper = vtkSmartPointer<vtkStripper>::New();
	stripper->SetInputConnection(cutter->GetOutputPort());
	stripper->JoinContiguousSegmentsOn();
	stripper->Update();

	vtkSmartPointer<vtkCleanPolyData> cleanPolyData = vtkSmartPointer<vtkCleanPolyData>::New();
	cleanPolyData->SetInputConnection(stripper->GetOutputPort());
	cleanPolyData->Update();

	vtkIdType numberOfLines = cutter->GetOutput()->GetNumberOfLines();


	/*std::cout << "-----------Lines without using vtkStripper" << std::endl;
	std::cout << "There are "
	<< numberOfLines
	<< " lines in the polydata" << std::endl;*/

	numberOfLines = cleanPolyData->GetOutput()->GetNumberOfLines();
	vtkPoints *points = cleanPolyData->GetOutput()->GetPoints();
	vtkCellArray *cells = cleanPolyData->GetOutput()->GetLines();

	/*std::cout << "-----------Lines using vtkStripper" << std::endl;
	std::cout << "There are "
	<< numberOfLines
	<< " lines in the polydata" << std::endl;*/

    // 循環提取輪廓線
	vtkIdType *indices;
	vtkIdType numberOfPoints;
	unsigned int lineCount = 0;

	vtkNew<vtkAppendPolyData> appendPolydata;
	for (cells->InitTraversal();
		cells->GetNextCell(numberOfPoints, indices);
		lineCount++)
	{
		vtkNew<vtkCellArray>lineCells;
		vtkNew<vtkPoints>linePoints;
		vtkNew<vtkPolyLine>contourLine;
		vtkNew<vtkPolyData>polydata;
		for (vtkIdType i = 0; i < numberOfPoints; i++)
		{
			double point[3];
			points->GetPoint(indices[i], point);
			/*std::cout << "\t("
			<< point[0] << ", "
			<< point[1] << ", "
			<< point[2] << ")" << std::endl;*/
			linePoints->InsertPoint(i, point);
			contourLine->GetPointIds()->InsertNextId(i);
		}

		lineCells->InsertNextCell(contourLine);
		polydata->SetPoints(linePoints);
		polydata->SetLines(lineCells);
        //輪廓線三角化
		vtkSmartPointer<vtkContourTriangulator> poly =
			vtkSmartPointer<vtkContourTriangulator>::New();
		poly->SetInputData(polydata);
		poly->Update();
		appendPolydata->AddInputData(poly->GetOutput());
	}
	appendPolydata->Update();
	return appendPolydata->GetOutput();
}

Test

int main()
{
	vtkSmartPointer<vtkPolyData> inputPolyData = createBody();

	//得到輸入的模型的最小座標
	double minBound[3];
	minBound[0] = inputPolyData->GetBounds()[0];
	minBound[1] = inputPolyData->GetBounds()[2];
	minBound[2] = inputPolyData->GetBounds()[4];

	//得到輸入的模型的最大座標
	double maxBound[3];
	maxBound[0] = inputPolyData->GetBounds()[1];
	maxBound[1] = inputPolyData->GetBounds()[3];
	maxBound[2] = inputPolyData->GetBounds()[5];
	//10 個切面
	int number = 10;
	//切割方向,即切割平面的法向量,沿X方向切割
	double normalX[3] = { 1,0,0 };
	//沿Y方向切割
	double normalY[3] = { 0,1,0 };

	vtkSmartPointer<vtkPolyData>resultPolyDataX = equidistanceCut(inputPolyData,
		minBound, maxBound, normalX, number);

	vtkSmartPointer<vtkPolyData>resultPolyDataY = equidistanceCut(inputPolyData,
		minBound, maxBound, normalY, number);

	vtkNew<vtkAppendPolyData>appendPolyData;
	appendPolyData->AddInputData(resultPolyDataX);
	appendPolyData->AddInputData(resultPolyDataY);
	appendPolyData->Update();

	vtkSmartPointer<vtkPolyDataMapper> cutterMapper =
		vtkSmartPointer<vtkPolyDataMapper>::New();
	cutterMapper->SetInputData(appendPolyData->GetOutput());
	cutterMapper->ScalarVisibilityOff();

	vtkSmartPointer<vtkActor> planeActor =
		vtkSmartPointer<vtkActor>::New();
	planeActor->GetProperty()->SetColor(1, 0, 0);
	planeActor->GetProperty()->SetLineWidth(5);
	planeActor->SetMapper(cutterMapper);

	vtkSmartPointer<vtkPolyDataMapper> inputMapper = vtkSmartPointer<vtkPolyDataMapper>::New();
	inputMapper->SetInputData(inputPolyData);

	vtkSmartPointer<vtkActor> inputActor =
		vtkSmartPointer<vtkActor>::New();
	inputActor->GetProperty()->SetColor(0, 1, 0);
	inputActor->SetMapper(inputMapper);


	vtkSmartPointer<vtkRenderer> rendererLeft =
		vtkSmartPointer<vtkRenderer>::New();
	rendererLeft->SetViewport(0, 0, 0.5, 1);
	vtkSmartPointer<vtkRenderer> rendererRight =
		vtkSmartPointer<vtkRenderer>::New();
	rendererRight->SetViewport(0.5, 0, 1, 1);
	rendererLeft->AddActor(inputActor);
	rendererRight->AddActor(planeActor);
	

	vtkSmartPointer<vtkRenderWindow> renderWindow =
		vtkSmartPointer<vtkRenderWindow>::New();
	renderWindow->AddRenderer(rendererLeft);
	renderWindow->AddRenderer(rendererRight);
	renderWindow->SetSize(800, 600);

	vtkSmartPointer<vtkRenderWindowInteractor> interactor =
		vtkSmartPointer<vtkRenderWindowInteractor>::New();
	interactor->SetRenderWindow(renderWindow);
	rendererLeft->SetBackground(0, 0, 0);
	rendererRight->SetBackground(0, 0, 0);
	renderWindow->Render();

	interactor->Start();
	return 0;

}

Result

左側:待切割三維模型
右側:切割結果
在這裏插入圖片描述

Reference

VTK 三角剖分 Delaunay2D (一)
VTK:對輸入的三維模型在某個方向等間距提取模型的切面輪廓線
ExtractPolyLinesFromPolyData
ContourTriangulator

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章