應用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); }
本方法效率不高,但是能夠滿足刪除點的要求,目前沒有其他更有效的方法。