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 }
int numberOfOpenEdges = featureEdges->GetOutput()->GetNumberOfCells();
1.3 漏洞填补
很多情况下,检测出是否封闭还是不够的,还需将这些漏洞填补起来。VTK中有现成的类来完成这个功能——vtkFillHolesFilter。
其内部执行过程是首先检测出网格中的所有边界边,然后找出这些边界边中的每一个闭合回路,最后将这些闭合回路进行三角化(即生成三角网格)以实现填补的目的。这个类也是非常简单的,只需要设置需要填补的网格数据即可。
需要注意的是,有些边界的闭合回路是不需要三角化的,例如一个平面网格,若填补其四周的边界边,则会与原网格产生覆盖。vtkFillHolesFilters()中的SetHoleSize()函数可用于控制需要修补的漏洞面积的最大值,大于该值的漏洞则不需要填补处理。
现在,我们需要讨论的一个重要的问题是为什么要使用vtkPolyDataNormals?
这个事之前也提到过,在这里复习一遍。法向量这个东西和光照与阴影的计算密切相关。单元的法向量朝向则与单元的点顺序相关!只有保持所有的单元的点顺序一致才能得到正确的法向量,否则在网格模型显示时会得到意外的结果!如下所示:
由于经过漏洞填充,模型的所有单元的点顺序并不一致,因此使用vtkPolyDataNormals::ConsisitencyOn()进行调整。这样才能避免上面的问题。