VTK绘制多边形的一般过程为:
vtkPoints可以视为多边形的顶点,而vtkCellArray存储vtkPoints的id(索引),同时也决定着细分多边形的胞元形状。例如一个简单的多边形——三角形的构成如下:
vtkNew<vtkPoints> points;
points->SetNumberOfPoints(3);
points->SetPoint(0,0,0,0);//id + position
points->SetPoint(1,1,0,0);
points->SetPoint(2,0,1,0);
vtkNew<vtkCellArray> poly;
poly->AllocateEstimate(1,3);//胞元数量+胞元大小
poly->InsertNextCell(3);//胞元大小
poly->InsertCellPoint(0);//id
poly->InsertCellPoint(1);//id
poly->InsertCellPoint(2);//id
运行结果如图:
同理,四边形的需要四个点,如下图,按顺序将点 0123 存入vtkPoints和vtkCellArray即可。
对于圆形,可以选择两种策略,一是将圆形分割为多个点围成的圈;二是将圆分为多个三角形。
第一种只需要存储 0123 的点序列即可。第二种需要存储多三角形顶点序列:102,203,304,401。
根据细分的思想,我们可以绘制任意形状的多边形。较为复杂的环形的绘制同理,以最基础的空心矩形环为例:
需要存储点序列为:0451,1562,2673,3740。可以看成四个梯形拼接而成,也就是说梯形是矩形环的胞元。需要注意的是,如果按照0123,4567的存储方式只能得到矩形,而非中空的效果。
如果将矩形特化为正方形,同时提高细分的程度,我们就能得到另一种常见的环形——圆环。圆环的胞元应该是扇面的形状,但如果细分程度够高,可以用梯形胞元替代。按照下图,将点序0132,2354,4576,6710存入,就能得到圆环。当然了,为了接近于圆形,需要更多的点。
vtkNew<vtkPoints> points;
points->SetNumberOfPoints(720);//内外圈顶点和
double center[3]{0,0,0};//圆环中心
double r[2]{20,10};//外半径,内半径
double x{0},y{0};
//外圈
for(int i=0;i<360;++i){
x = center[0]+r[0]*cos(2.0*i*vtkMath::Pi()/360);
y = center[0]+r[0]*sin(2.0*i*vtkMath::Pi()/360);
points->SetPoint(i,x,y,0);
}
//内圈
for(int i=0;i<360;++i){
x = center[0]+r[1]*cos(2.0*i*vtkMath::Pi()/360);
y = center[0]+r[1]*sin(2.0*i*vtkMath::Pi()/360);
points->SetPoint(i+360,x,y,0);
}
vtkNew<vtkCellArray> poly;
poly->AllocateEstimate(360,4);
vtkIdType id[4];
int tid{0};
for(int i=0;i<360;++i){
id[0] = i;
id[1] = 360+i;
tid = 361+i;
id[2] = tid<720?tid:360;
tid = i+1;
id[3] = tid<360?tid:0;
poly->InsertNextCell(4,id);
}
vtkNew<vtkPolyData> data;
data->SetPoints(points);
data->SetPolys(poly);
vtkNew<vtkPolyDataMapper>mapper;
mapper->SetInputData(data);
vtkNew<vtkActor>actor;
actor->SetMapper(mapper);
vtkNew<vtkRenderer> ren;
ren->AddActor(actor);
vtkNew<vtkRenderWindow> renw;
renw->AddRenderer(ren);
vtkNew<vtkRenderWindowInteractor> reni;
reni->SetRenderWindow(renw);
renw->Render();
reni->Initialize();
reni->Start();
上述代码运行结果如下:
我们将代码稍加修改,使得代码能输出三角环,四角环,N环,乃至圆环,也就是vtkDiskSource的基本原理了。代码如下,numCells为胞元的数量,顶点数量为胞元的两倍。通过numCells可以空控制环的类型:
vtkNew<vtkPoints> points;
int numCells = 3;
if(numCells<3) return 0;
int numPoints = numCells*2;
points->SetNumberOfPoints(numPoints);//内外圈顶点和
double center[3]{0,0,0};//圆环中心
double r[2]{20,10};//外半径,内半径
double x{0},y{0};
//外圈
for(int i=0;i<numCells;++i){
double rad = 6.28318531*i/numCells;
x = center[0]+r[0]*cos(rad);
y = center[0]+r[0]*sin(rad);
points->SetPoint(i,x,y,0);
}
//内圈
for(int i=0;i<numCells;++i){
double rad = 6.28318531*i/numCells;
x = center[0]+r[1]*cos(rad);
y = center[0]+r[1]*sin(rad);
points->SetPoint(i+numCells,x,y,0);
}
vtkNew<vtkCellArray> poly;
poly->AllocateEstimate(numCells,4);
vtkIdType id[4];
int tid{0};
for(int i=0;i<numCells;++i){
id[0] = i;
id[1] = numCells+i;
tid = numCells+1+i;
id[2] = tid<numPoints?tid:numCells;
tid = i+1;
id[3] = tid<numCells?tid:0;
poly->InsertNextCell(4,id);
}
vtkNew<vtkPolyData> data;
data->SetPoints(points);
data->SetPolys(poly);
vtkNew<vtkPolyDataMapper>mapper;
mapper->SetInputData(data);
vtkNew<vtkActor>actor;
actor->SetMapper(mapper);
vtkNew<vtkRenderer> ren;
ren->AddActor(actor);
vtkNew<vtkRenderWindow> renw;
renw->AddRenderer(ren);
vtkNew<vtkRenderWindowInteractor> reni;
reni->SetRenderWindow(renw);
renw->Render();
reni->Initialize();
reni->Start();
部分示例如下: