VTK修炼之道50:图形基本操作进阶_网格模型的特征边 与 封闭性检测
生活随笔
收集整理的這篇文章主要介紹了
VTK修炼之道50:图形基本操作进阶_网格模型的特征边 与 封闭性检测
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
1.封閉性檢測
由于受原始數據、重建方法的限制,得到的網格模型并不是封閉的。有時為了顯示或者處理某些要求,需要網格必須是封閉的。 封閉性網格應該比較好理解,比如一個球形網格。1.1網格模型邊的分類
之前也有提到過邊界邊的概念:如果一條邊只被一個多邊形包含,那么這條邊就是邊界邊。是否存在邊界邊是檢測一個網格模型是否封閉的重要特征。 vtkFeatureEdges是一個非常重要的類,該類能夠提取多邊形網格模型中四種類型的邊。- 邊界邊:只被一個多邊形或者一條邊包圍的邊。
- 非流形邊:被三個或者三個以上多邊形包圍的邊;
- 特征邊:需要設置一個特征角的閾值,當包含同一條邊的兩個三角形的法向量的夾角大于該閾值時,即為一個特征邊。
- 流行邊:只被兩個多邊形包含的邊。
1.2 網格封閉性判斷
可以通過使用vtkFeatureEdges類檢測是否存在邊界邊,潔兒判斷網格是否封閉。 示例代碼如下: #include <vtkAutoInit.h> VTK_MODULE_INIT(vtkRenderingOpenGL); VTK_MODULE_INIT(vtkRenderingFreeType); VTK_MODULE_INIT(vtkInteractionStyle);#include <vtkSmartPointer.h> #include <vtkSphereSource.h> #include <vtkIdTypeArray.h> #include <vtkSelectionNode.h> #include <vtkSelection.h> #include <vtkExtractSelection.h> #include <vtkDataSetSurfaceFilter.h> #include <vtkInformation.h> #include <vtkProperty.h> //生成帶孔洞的網格球 void GenerateData(vtkSmartPointer<vtkPolyData> input) {vtkSmartPointer<vtkSphereSource> sphereSource =vtkSmartPointer<vtkSphereSource>::New();sphereSource->Update();//提供了插入和檢索值的方法,并會自動調整大小以保存新數據vtkSmartPointer<vtkIdTypeArray> ids =vtkSmartPointer<vtkIdTypeArray>::New();ids->SetNumberOfComponents(1);ids->InsertNextValue(2);ids->InsertNextValue(10);//選擇樹中的節,用于存儲選擇結果vtkSmartPointer<vtkSelectionNode> selectionNode =vtkSmartPointer<vtkSelectionNode>::New();selectionNode->SetFieldType(vtkSelectionNode::CELL);selectionNode->SetContentType(vtkSelectionNode::INDICES);selectionNode->SetSelectionList(ids);selectionNode->GetProperties()->Set(vtkSelectionNode::INVERSE(), 1);vtkSmartPointer<vtkSelection> selection =vtkSmartPointer<vtkSelection>::New();selection->AddNode(selectionNode);//從vtkdataset提取子集,刪除操作vtkSmartPointer<vtkExtractSelection> extractSelection =vtkSmartPointer<vtkExtractSelection>::New();extractSelection->SetInputData(0, sphereSource->GetOutput());extractSelection->SetInputData(1, selection);extractSelection->Update();//vtkDataSetSurfaceFilter是更快版本的vtkgeometry濾波器//但它沒有一個選擇范圍。比vtkGeometryFilter使用更多的內存//只有一個選擇:輸入結構類型時是否使用三角形條vtkSmartPointer<vtkDataSetSurfaceFilter> surfaceFilter =vtkSmartPointer<vtkDataSetSurfaceFilter>::New();surfaceFilter->SetInputConnection(extractSelection->GetOutputPort());surfaceFilter->Update();input->ShallowCopy(surfaceFilter->GetOutput()); } #include <vtkPolyData.h> #include <vtkFeatureEdges.h> #include <vtkPolyDataMapper.h> #include <vtkFillHolesFilter.h> #include <vtkPolyDataNormals.h> #include <vtkActor.h> #include <vtkCamera.h> #include <vtkRenderer.h> #include <vtkRenderWindow.h> #include <vtkRenderWindowInteractor.h>int main() {vtkSmartPointer<vtkPolyData> input =vtkSmartPointer<vtkPolyData>::New();GenerateData(input);vtkSmartPointer<vtkFeatureEdges> featureEdges =vtkSmartPointer<vtkFeatureEdges>::New();featureEdges->SetInputData(input);featureEdges->BoundaryEdgesOn();featureEdges->FeatureEdgesOff();featureEdges->ManifoldEdgesOff();featureEdges->NonManifoldEdgesOff();featureEdges->Update();int numberOfOpenEdges = featureEdges->GetOutput()->GetNumberOfCells();if (numberOfOpenEdges){std::cout << "該網格模型不是封閉的..." << std::endl;}else{std::cout << "該網格模型是封閉的..." << std::endl;return EXIT_SUCCESS;}vtkSmartPointer<vtkFillHolesFilter> fillHolesFilter =vtkSmartPointer<vtkFillHolesFilter>::New();fillHolesFilter->SetInputData(input);fillHolesFilter->Update();vtkSmartPointer<vtkPolyDataNormals> normals =vtkSmartPointer<vtkPolyDataNormals>::New();normals->SetInputConnection(fillHolesFilter->GetOutputPort());normals->ConsistencyOn(); //很重要,根據其他單元點的順序調整補充點的順序normals->SplittingOff();normals->Update();/double leftViewport[4] = { 0.0, 0.0, 0.5, 1.0 };double rightViewport[4] = { 0.5, 0.0, 1.0, 1.0 };vtkSmartPointer<vtkPolyDataMapper> originalMapper =vtkSmartPointer<vtkPolyDataMapper>::New();originalMapper->SetInputData(input);vtkSmartPointer<vtkProperty> backfaceProp =vtkSmartPointer<vtkProperty>::New();backfaceProp->SetDiffuseColor(0.89, 0.81, 0.34);vtkSmartPointer<vtkActor> originalActor =vtkSmartPointer<vtkActor>::New();originalActor->SetMapper(originalMapper);originalActor->SetBackfaceProperty(backfaceProp);originalActor->GetProperty()->SetDiffuseColor(1.0, 0.3882, 0.2784);vtkSmartPointer<vtkPolyDataMapper> edgeMapper =vtkSmartPointer<vtkPolyDataMapper>::New();edgeMapper->SetInputData(featureEdges->GetOutput());vtkSmartPointer<vtkActor> edgeActor =vtkSmartPointer<vtkActor>::New();edgeActor->SetMapper(edgeMapper);edgeActor->GetProperty()->SetEdgeColor(0., 0., 1.0);edgeActor->GetProperty()->SetEdgeVisibility(1);edgeActor->GetProperty()->SetLineWidth(5);vtkSmartPointer<vtkPolyDataMapper> filledMapper =vtkSmartPointer<vtkPolyDataMapper>::New();filledMapper->SetInputData(normals->GetOutput());vtkSmartPointer<vtkActor> filledActor =vtkSmartPointer<vtkActor>::New();filledActor->SetMapper(filledMapper);filledActor->GetProperty()->SetDiffuseColor(1.0, 0.3882, 0.2784);///vtkSmartPointer<vtkRenderer> leftRenderer =vtkSmartPointer<vtkRenderer>::New();leftRenderer->SetViewport(leftViewport);leftRenderer->AddActor(originalActor);leftRenderer->AddActor(edgeActor);leftRenderer->SetBackground(1.0, 1.0, 1.0);vtkSmartPointer<vtkRenderer> rightRenderer =vtkSmartPointer<vtkRenderer>::New();rightRenderer->SetViewport(rightViewport);rightRenderer->AddActor(filledActor);rightRenderer->SetBackground(0, 0, 0);vtkSmartPointer<vtkRenderWindow> renderWindow =vtkSmartPointer<vtkRenderWindow>::New();renderWindow->AddRenderer(leftRenderer);renderWindow->AddRenderer(rightRenderer);renderWindow->SetSize(640, 320);renderWindow->Render();renderWindow->SetWindowName("Poly Data Closed");vtkSmartPointer<vtkRenderWindowInteractor> renderWindowInteractor =vtkSmartPointer<vtkRenderWindowInteractor>::New();renderWindowInteractor->SetRenderWindow(renderWindow);leftRenderer->GetActiveCamera()->SetPosition(0, -1, 0);leftRenderer->GetActiveCamera()->SetFocalPoint(0, 0, 0);leftRenderer->GetActiveCamera()->SetViewUp(0, 0, 1);leftRenderer->GetActiveCamera()->Azimuth(30);leftRenderer->GetActiveCamera()->Elevation(30);leftRenderer->ResetCamera();rightRenderer->SetActiveCamera(leftRenderer->GetActiveCamera()); //同步響應renderWindowInteractor->Start();return 0; }為了方便看到效果,我建立了一個球面網格,并去除樂其中另個三角面片(單元)。結果如下:將該數據作為vtkFeatureEdges的輸入,vtkBoundaryOn()函數設置提取邊界邊,本例無需考慮其他類型的邊。執行完畢后,其輸出GetOutput()為一個包含邊信息的vtkPolyData數據。可以通過判斷邊界邊的數目來確定網格是否封閉: int numberOfOpenEdges = featureEdges->GetOutput()->GetNumberOfCells();
1.3 漏洞填補
很多情況下,檢測出是否封閉還是不夠的,還需將這些漏洞填補起來。VTK中有現成的類來完成這個功能——vtkFillHolesFilter。 其內部執行過程是首先檢測出網格中的所有邊界邊,然后找出這些邊界邊中的每一個閉合回路,最后將這些閉合回路進行三角化(即生成三角網格)以實現填補的目的。這個類也是非常簡單的,只需要設置需要填補的網格數據即可。 需要注意的是,有些邊界的閉合回路是不需要三角化的,例如一個平面網格,若填補其四周的邊界邊,則會與原網格產生覆蓋。vtkFillHolesFilters()中的SetHoleSize()函數可用于控制需要修補的漏洞面積的最大值,大于該值的漏洞則不需要填補處理。 現在,我們需要討論的一個重要的問題是為什么要使用vtkPolyDataNormals? 這個事之前也提到過,在這里復習一遍。法向量這個東西和光照與陰影的計算密切相關。單元的法向量朝向則與單元的點順序相關!只有保持所有的單元的點順序一致才能得到正確的法向量,否則在網格模型顯示時會得到意外的結果!如下所示:由于經過漏洞填充,模型的所有單元的點順序并不一致,因此使用vtkPolyDataNormals::ConsisitencyOn()進行調整。這樣才能避免上面的問題。
2.參看資料
1.《C++ primer》2.《The VTK User’s Guide – 11thEdition》
3. ?張曉東, 羅火靈. VTK圖形圖像開發進階[M]. 機械工業出版社, 2015.
總結
以上是生活随笔為你收集整理的VTK修炼之道50:图形基本操作进阶_网格模型的特征边 与 封闭性检测的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 要玩就玩大的 夏普展示1,000,000
- 下一篇: VTK修炼之道51:图形基本操作进阶_连