对比VTK中的不同Spline样条
Spline样条作用:
VTK中的Spline样条可以将顶点连接成平滑的线段,并且对线段重新采样。目前主要有vtkSCurveSpline、vtkKochanekSpline、vtkCardinalSpline和vtkParametricSpline四种Spline可以用,后文将对比这四种Spline的效果。
输入的点集
后文的示例都是用同样的四个单独顶点来完成,顶点的顺序可以更改,而Spline是严格根据点集中顶点的顺序来完成连接的,所以调换顶点顺序可以更改Spline的模样。
//定义点集
vtkPoints* ps = vtkPoints::New();
double a[3] = { 0,0,0 }; //插入顶点a
ps->InsertNextPoint(a);
double b[3] = { 1,0,0 }; //插入顶点b
ps->InsertNextPoint(b);
double c[3] = { 1,1,0 }; //插入顶点c
ps->InsertNextPoint(c);
double d[3] = { 0,1,0 }; //插入顶点d
ps->InsertNextPoint(d);
//将顶点插入到vtkPolyData中,没有定义拓扑
vtkNew<vtkPolyData> pointData;
pointData->SetPoints(ps);
vtkKochanekSpline:根据点集的顺序就能连接得到平滑曲线
//代码参考官方示例
vtkNew<vtkKochanekSpline> xSpline;
vtkNew<vtkKochanekSpline> ySpline;
vtkNew<vtkKochanekSpline> zSpline;
vtkNew<vtkParametricSpline> spline;
spline->SetXSpline(xSpline);
spline->SetYSpline(ySpline);
spline->SetZSpline(zSpline);
spline->SetPoints(ps);
vtkParametricFunctionSource* functionSource = vtkParametricFunctionSource::New();
functionSource->SetParametricFunction(spline);
functionSource->SetUResolution(50 * ps->GetNumberOfPoints());
functionSource->SetVResolution(50 * ps->GetNumberOfPoints());
functionSource->SetWResolution(50 * ps->GetNumberOfPoints());
functionSource->Update();
vtkPolyData* out = functionSource->GetOutput();
vtkKochanekSpline生成的曲线弯曲幅度会相对小一点。
vtkCardinalSpline
vtkSmartPointer<vtkCardinalSpline> xSpline =
vtkSmartPointer<vtkCardinalSpline>::New();
vtkSmartPointer<vtkCardinalSpline> ySpline =
vtkSmartPointer<vtkCardinalSpline>::New();
vtkSmartPointer<vtkCardinalSpline> zSpline =
vtkSmartPointer<vtkCardinalSpline>::New();
vtkSmartPointer<vtkParametricSpline> spline =
vtkSmartPointer<vtkParametricSpline>::New();
spline->SetXSpline(xSpline);
spline->SetYSpline(ySpline);
spline->SetZSpline(zSpline);
spline->SetPoints(ps);
vtkParametricFunctionSource* functionSource =
vtkParametricFunctionSource::New();
functionSource->SetParametricFunction(spline);
functionSource->SetUResolution(50 * ps->GetNumberOfPoints());
functionSource->SetVResolution(50 * ps->GetNumberOfPoints());
functionSource->SetWResolution(50 * ps->GetNumberOfPoints());
functionSource->Update();
vtkPolyData* out = functionSource->GetOutput();
vtkCardinalSpline生成曲线的弯曲幅度会相对更大一点。
vtkParametricSpline:更简单的构建曲线
vtkNew<vtkParametricSpline> spline;
spline->SetPoints(ps);
vtkParametricFunctionSource* functionSource =
vtkParametricFunctionSource::New();
functionSource->SetParametricFunction(spline);
functionSource->SetUResolution(50 * ps->GetNumberOfPoints());
functionSource->SetVResolution(50 * ps->GetNumberOfPoints());
functionSource->SetWResolution(50 * ps->GetNumberOfPoints());
functionSource->Update();
vtkPolyData* out = functionSource->GetOutput();
vtkParametricSpline生成曲线的效果目前看来和vtkCardinalSpline类似,实际上vtkParametricSpline默认使用的就是vtkCardinalSpline方法。
vtkSCurveSpline:直接就是用直线相连
vtkNew<vtkSCurveSpline> xSpline;
vtkNew<vtkSCurveSpline> ySpline;
vtkNew<vtkSCurveSpline> zSpline;
vtkNew<vtkParametricSpline> spline;
spline->SetXSpline(xSpline);
spline->SetYSpline(ySpline);
spline->SetZSpline(zSpline);
spline->SetPoints(ps);
vtkParametricFunctionSource* functionSource =
vtkParametricFunctionSource::New();
functionSource->SetParametricFunction(spline);
functionSource->Update();
vtkPolyData* out = functionSource->GetOutput();
如果需要用直线连接点集合的话,vtkSCurveSpline很合适。
注意点
如果你的顶点数量很大的话,要用以上Filter连接顶点前,注意要先对顶点排序,目前VTK还没有能直接用来对顶点集合排序的函数,因此基本需要自行实现。
vtkFrenetSerretFrame 弗莱纳框架
这个函数要使用的话需要额外的第三方依赖:
//在编译VTK时的CMakeList文件中或者CMAKE界面中设置
''Module_SplineDrivenImageSlicer:BOOL=ON'' or
''VTK_MODULE_ENABLE_VTK_SplineDrivenImageSlicer:STRING=WANT''
主要作用:能够输入一组线段(例如上文代码段中的数据输出out),然后经过该Filter的处理,能够得到该线段在各顶点处的法向量和切向量属性数据。
// Create the frame
vtkNew<vtkFrenetSerretFrame> frame;
//functionSource为上文代码段中的生成曲线的结果
frame->SetInputConnection(functionSource->GetOutputPort());
frame->ConsistentNormalsOn();
frame->Update();
vtkNew<vtkGlyph3D> glyph3DNormals;
vtkNew<vtkGlyph3D> glyph3DTangents;
vtkNew<vtkGlyph3D> glyph3DBinormals;
// for each vector, create a Glyph3D and DeepCopy the output
double radius = 0.05;
frame->GetOutput()->GetPointData()->SetActiveVectors("FSNormals");
MakeGlyphs(frame->GetOutput(), radius, glyph3DNormals.GetPointer());
vtkNew<vtkPolyData> normalsPolyData;
normalsPolyData->DeepCopy(glyph3DNormals->GetOutput());
frame->GetOutput()->GetPointData()->SetActiveVectors("FSTangents");
MakeGlyphs(frame->GetOutput(), radius, glyph3DTangents.GetPointer());
vtkNew<vtkPolyData> tangentsPolyData;
tangentsPolyData->DeepCopy(glyph3DTangents->GetOutput());
frame->GetOutput()->GetPointData()->SetActiveVectors("FSBinormals");
MakeGlyphs(frame->GetOutput(), radius, glyph3DBinormals.GetPointer());
vtkNew<vtkPolyData> binormalsPolyData;
binormalsPolyData->DeepCopy(glyph3DBinormals->GetOutput());
将各属性渲染出来如下图所示: