VTK 图形基本操作进阶_网格模型的特征边 与 封闭性检测
作者:互联网
1.封闭性检测
由于受原始数据、重建方法的限制,得到的网格模型并不是封闭的。有时为了显示或者处理某些要求,需要网格必须是封闭的。 封闭性网格应该比较好理解,比如一个球形网格。1.1网格模型边的分类
之前也有提到过边界边的概念:如果一条边只被一个多边形包含,那么这条边就是边界边。是否存在边界边是检测一个网格模型是否封闭的重要特征。 vtkFeatureEdges是一个非常重要的类,该类能够提取多边形网格模型中四种类型的边。
- 边界边:只被一个多边形或者一条边包围的边。
- 非流形边:被三个或者三个以上多边形包围的边;
- 特征边:需要设置一个特征角的阈值,当包含同一条边的两个三角形的法向量的夹角大于该阈值时,即为一个特征边。
- 流行边:只被两个多边形包含的边。
1.2 网格封闭性判断
可以通过使用vtkFeatureEdges类检测是否存在边界边,洁儿判断网格是否封闭。 示例代码如下:1 #include <vtkAutoInit.h> 2 VTK_MODULE_INIT(vtkRenderingOpenGL); 3 VTK_MODULE_INIT(vtkRenderingFreeType); 4 VTK_MODULE_INIT(vtkInteractionStyle); 5 6 #include <vtkSmartPointer.h> 7 #include <vtkSphereSource.h> 8 #include <vtkIdTypeArray.h> 9 #include <vtkSelectionNode.h> 10 #include <vtkSelection.h> 11 #include <vtkExtractSelection.h> 12 #include <vtkDataSetSurfaceFilter.h> 13 #include <vtkInformation.h> 14 #include <vtkProperty.h> 15 //生成带孔洞的网格球 16 void GenerateData(vtkSmartPointer<vtkPolyData> input) 17 { 18 vtkSmartPointer<vtkSphereSource> sphereSource = 19 vtkSmartPointer<vtkSphereSource>::New(); 20 sphereSource->Update(); 21 22 //提供了插入和检索值的方法,并会自动调整大小以保存新数据 23 vtkSmartPointer<vtkIdTypeArray> ids = 24 vtkSmartPointer<vtkIdTypeArray>::New(); 25 ids->SetNumberOfComponents(1); 26 ids->InsertNextValue(2); 27 ids->InsertNextValue(10); 28 29 //选择树中的节,用于存储选择结果 30 vtkSmartPointer<vtkSelectionNode> selectionNode = 31 vtkSmartPointer<vtkSelectionNode>::New(); 32 selectionNode->SetFieldType(vtkSelectionNode::CELL); 33 selectionNode->SetContentType(vtkSelectionNode::INDICES); 34 selectionNode->SetSelectionList(ids); 35 selectionNode->GetProperties()->Set(vtkSelectionNode::INVERSE(), 1); 36 37 vtkSmartPointer<vtkSelection> selection = 38 vtkSmartPointer<vtkSelection>::New(); 39 selection->AddNode(selectionNode); 40 41 //从vtkdataset提取子集,删除操作 42 vtkSmartPointer<vtkExtractSelection> extractSelection = 43 vtkSmartPointer<vtkExtractSelection>::New(); 44 extractSelection->SetInputData(0, sphereSource->GetOutput()); 45 extractSelection->SetInputData(1, selection); 46 extractSelection->Update(); 47 48 //vtkDataSetSurfaceFilter是更快版本的vtkgeometry滤波器 49 //但它没有一个选择范围。比vtkGeometryFilter使用更多的内存 50 //只有一个选择:输入结构类型时是否使用三角形条 51 vtkSmartPointer<vtkDataSetSurfaceFilter> surfaceFilter = 52 vtkSmartPointer<vtkDataSetSurfaceFilter>::New(); 53 surfaceFilter->SetInputConnection(extractSelection->GetOutputPort()); 54 surfaceFilter->Update(); 55 56 input->ShallowCopy(surfaceFilter->GetOutput()); 57 } 58 #include <vtkPolyData.h> 59 #include <vtkFeatureEdges.h> 60 #include <vtkPolyDataMapper.h> 61 #include <vtkFillHolesFilter.h> 62 #include <vtkPolyDataNormals.h> 63 #include <vtkActor.h> 64 #include <vtkCamera.h> 65 #include <vtkRenderer.h> 66 #include <vtkRenderWindow.h> 67 #include <vtkRenderWindowInteractor.h> 68 69 int main() 70 { 71 vtkSmartPointer<vtkPolyData> input = 72 vtkSmartPointer<vtkPolyData>::New(); 73 GenerateData(input); 74 75 vtkSmartPointer<vtkFeatureEdges> featureEdges = 76 vtkSmartPointer<vtkFeatureEdges>::New(); 77 featureEdges->SetInputData(input); 78 featureEdges->BoundaryEdgesOn(); 79 featureEdges->FeatureEdgesOff(); 80 featureEdges->ManifoldEdgesOff(); 81 featureEdges->NonManifoldEdgesOff(); 82 featureEdges->Update(); 83 84 int numberOfOpenEdges = featureEdges->GetOutput()->GetNumberOfCells(); 85 if (numberOfOpenEdges) 86 { 87 std::cout << "该网格模型不是封闭的..." << std::endl; 88 } 89 else 90 { 91 std::cout << "该网格模型是封闭的..." << std::endl; 92 return EXIT_SUCCESS; 93 } 94 vtkSmartPointer<vtkFillHolesFilter> fillHolesFilter = 95 vtkSmartPointer<vtkFillHolesFilter>::New(); 96 fillHolesFilter->SetInputData(input); 97 fillHolesFilter->Update(); 98 99 vtkSmartPointer<vtkPolyDataNormals> normals = 100 vtkSmartPointer<vtkPolyDataNormals>::New(); 101 normals->SetInputConnection(fillHolesFilter->GetOutputPort()); 102 normals->ConsistencyOn(); //很重要,根据其他单元点的顺序调整补充点的顺序 103 normals->SplittingOff(); 104 normals->Update(); 105 / 106 double leftViewport[4] = { 0.0, 0.0, 0.5, 1.0 }; 107 double rightViewport[4] = { 0.5, 0.0, 1.0, 1.0 }; 108 109 vtkSmartPointer<vtkPolyDataMapper> originalMapper = 110 vtkSmartPointer<vtkPolyDataMapper>::New(); 111 originalMapper->SetInputData(input); 112 vtkSmartPointer<vtkProperty> backfaceProp = 113 vtkSmartPointer<vtkProperty>::New(); 114 backfaceProp->SetDiffuseColor(0.89, 0.81, 0.34); 115 vtkSmartPointer<vtkActor> originalActor = 116 vtkSmartPointer<vtkActor>::New(); 117 originalActor->SetMapper(originalMapper); 118 originalActor->SetBackfaceProperty(backfaceProp); 119 originalActor->GetProperty()->SetDiffuseColor(1.0, 0.3882, 0.2784); 120 121 vtkSmartPointer<vtkPolyDataMapper> edgeMapper = 122 vtkSmartPointer<vtkPolyDataMapper>::New(); 123 edgeMapper->SetInputData(featureEdges->GetOutput()); 124 vtkSmartPointer<vtkActor> edgeActor = 125 vtkSmartPointer<vtkActor>::New(); 126 edgeActor->SetMapper(edgeMapper); 127 edgeActor->GetProperty()->SetEdgeColor(0., 0., 1.0); 128 edgeActor->GetProperty()->SetEdgeVisibility(1); 129 edgeActor->GetProperty()->SetLineWidth(5); 130 131 vtkSmartPointer<vtkPolyDataMapper> filledMapper = 132 vtkSmartPointer<vtkPolyDataMapper>::New(); 133 filledMapper->SetInputData(normals->GetOutput()); 134 vtkSmartPointer<vtkActor> filledActor = 135 vtkSmartPointer<vtkActor>::New(); 136 filledActor->SetMapper(filledMapper); 137 filledActor->GetProperty()->SetDiffuseColor(1.0, 0.3882, 0.2784); 138 /// 139 vtkSmartPointer<vtkRenderer> leftRenderer = 140 vtkSmartPointer<vtkRenderer>::New(); 141 leftRenderer->SetViewport(leftViewport); 142 leftRenderer->AddActor(originalActor); 143 leftRenderer->AddActor(edgeActor); 144 leftRenderer->SetBackground(1.0, 1.0, 1.0); 145 146 vtkSmartPointer<vtkRenderer> rightRenderer = 147 vtkSmartPointer<vtkRenderer>::New(); 148 rightRenderer->SetViewport(rightViewport); 149 rightRenderer->AddActor(filledActor); 150 rightRenderer->SetBackground(0, 0, 0); 151 152 vtkSmartPointer<vtkRenderWindow> renderWindow = 153 vtkSmartPointer<vtkRenderWindow>::New(); 154 renderWindow->AddRenderer(leftRenderer); 155 renderWindow->AddRenderer(rightRenderer); 156 renderWindow->SetSize(640, 320); 157 renderWindow->Render(); 158 renderWindow->SetWindowName("Poly Data Closed"); 159 160 vtkSmartPointer<vtkRenderWindowInteractor> renderWindowInteractor = 161 vtkSmartPointer<vtkRenderWindowInteractor>::New(); 162 renderWindowInteractor->SetRenderWindow(renderWindow); 163 164 leftRenderer->GetActiveCamera()->SetPosition(0, -1, 0); 165 leftRenderer->GetActiveCamera()->SetFocalPoint(0, 0, 0); 166 leftRenderer->GetActiveCamera()->SetViewUp(0, 0, 1); 167 leftRenderer->GetActiveCamera()->Azimuth(30); 168 leftRenderer->GetActiveCamera()->Elevation(30); 169 leftRenderer->ResetCamera(); 170 rightRenderer->SetActiveCamera(leftRenderer->GetActiveCamera()); //同步响应 171 renderWindowInteractor->Start(); 172 173 return 0; 174 }为了方便看到效果,我建立了一个球面网格,并去除乐其中另个三角面片(单元)。结果如下: 将该数据作为vtkFeatureEdges的输入,vtkBoundaryOn()函数设置提取边界边,本例无需考虑其他类型的边。执行完毕后,其输出GetOutput()为一个包含边信息的vtkPolyData数据。可以通过判断边界边的数目来确定网格是否封闭:int numberOfOpenEdges = featureEdges->GetOutput()->GetNumberOfCells();1.3 漏洞填补
很多情况下,检测出是否封闭还是不够的,还需将这些漏洞填补起来。VTK中有现成的类来完成这个功能——vtkFillHolesFilter。 其内部执行过程是首先检测出网格中的所有边界边,然后找出这些边界边中的每一个闭合回路,最后将这些闭合回路进行三角化(即生成三角网格)以实现填补的目的。这个类也是非常简单的,只需要设置需要填补的网格数据即可。 需要注意的是,有些边界的闭合回路是不需要三角化的,例如一个平面网格,若填补其四周的边界边,则会与原网格产生覆盖。vtkFillHolesFilters()中的SetHoleSize()函数可用于控制需要修补的漏洞面积的最大值,大于该值的漏洞则不需要填补处理。 现在,我们需要讨论的一个重要的问题是为什么要使用vtkPolyDataNormals? 这个事之前也提到过,在这里复习一遍。法向量这个东西和光照与阴影的计算密切相关。单元的法向量朝向则与单元的点顺序相关!只有保持所有的单元的点顺序一致才能得到正确的法向量,否则在网格模型显示时会得到意外的结果!如下所示: 由于经过漏洞填充,模型的所有单元的点顺序并不一致,因此使用vtkPolyDataNormals::ConsisitencyOn()进行调整。这样才能避免上面的问题。
标签:进阶,VTK,网格,vtkSmartPointer,New,featureEdges,基本操作,include,leftRenderer 来源: https://www.cnblogs.com/ybqjymy/p/14241831.html