应用VTK处理网格数据,基本都要用到vtkPolyData,包括点数据信息和拓扑结构进行。点信息数据存储在vtkPoints数据结构中,拓扑结构信息可以包括顶点(verts),线(lines),多边形(polys)和三角面片(strips)。拓扑结构信息的数据类型是vtkCharArray,只存储顶点信息的索引值,本文以polys为例。
vtkPolyData提供便利数据添加功能,添加point和添加polys示例如下:
// 添加点 double p0[3] = {1.0,0.0,0.0}; double p1[3] = {0.0,1.0,0.0}; double p2[3] = {0.0,0.0,1.0}; vtkPoints *pPoint = vtkPoints::New(); pPoint->InsertNextPoint(p0); pPoint->InsertNextPoint(p1); pPoint->InsertNextPoint(p2); //添加多边形 vtkIdType pIds[3] = {0,1,2}; vtkCellArray *pPolys = vtkCellArray::New(); pPolys->InsertNextCell(pIds); vtkPolyData *pData = vtkPolyData::New(); pData->SetPoints(pPoint); pData->SetPolys(pPolys);
但是,vtkPolyData删除点或者拓扑信息就没有这么简单了,应为拓扑结构中存储的是点的索引信息,删除点必然会影响点的索引值,这时就要特别注意。
最近查了一些资料,总结了一下安全删除vtkPolyData数据中点和拓扑信息
(1)vtkPolyData提供一个DeletePoint()的接口,可以使用这个接口删除点,但是不能真正的删除点数据。因为DeletePoint()实际操作的是vtkPolyData内部定义的数据vtkCellLinks,这个数据结构是一个辅助类,使用前必须要调用BuildLinks()函数,如果只是可视化使用,这个函数是可以用的。但是如果要删除vtkPoints里面的数据,就没有这么简单了。
(2)vtkPolyData删除拓扑结构信息比较简单,因为拓扑信息只包括点的索引值,删除后不会影响其他数据,可以使用DeleteCell()方法。
本文将将给出三个实例来表示vtkPolyData中数据的删除操作,其中包括一个删除拓扑信息的实例,两个删除点的实例。
实例1:删除拓扑结构
vtkIdType cellId = 200;// 要删除的面片的索引值 pData->BuildCells(); pData->DeleteCell(cellId); // 标记要删除的cell结构,不会真正的删除 pData->RemoveDeleteCells(); // 实际删除cell结构 pData->Modified();
实例2:删除点数据,不能真正的删除点
vtkIdType pId = 100; // 要删除的顶点的索引值
pData->BuildLinks(); pData->DeletePoint(pId); pData->DeleteLinks();
pData->Modified();
实例3:真正的删除点数据,同时恢复拓扑结构中点的索引值
// 辅助类 struct Vertex { double p[3]; inline bool operator==(const Vertex &v ) const { return (p[0] == v.p[0])&&( p[1] == v.p[1])&&(p[2] == v.p[2]); } inline bool operator != (const Vertex &v) const { return (p[0] != v.p[0])&&( p[1] != v.p[1])&&(p[2] != v.p[2]); } } /* * pData 要处理的网格数据 * delPIds 要删除的点的索引值,可以是多个点,用vector表示 */ void RealDeletePoint(vtkPolyData *pData, std::vector<int> delPIds) {
vtkPoints *pPoints = vtkPoints::New(); vtkCellArray *PCell = vtkCellArray::New(); vtkIdType *newIds = nullptr; vtkIdType *pIds; vtkIdType nId; std::map<Vertex, int> pointMap; for(int i = 0; i < pData->GetNumberOfCells(); i++) { pData->GetCellPoints(i,nId,pIds); newIds = new vtkIdType[nId]; for(int j = 0; j < nId; j++) { double *p = pData->GetPoint(pIds[j]); Vertex tmpv; tmpv[0] = p[0]; tmpv[1] = p[1]; tmpv[2] = p[2]; auto it = pointMap.find(tmpv); if(it != pointMap.end()) { newIds[j] = it->second; } else { pPoints->InsertNextPoint(p); newIds[j] = pPoints->GetNumberOfPoints()-1; } } pCell->InsertNextCell(nId, newIds); delete []newIds; newIds = nullptr; } pData->SetPoints(pPoints); pData->SetPolys(pCell); }
本方法效率不高,但是能够满足删除点的要求,目前没有其他更有效的方法。