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