VTK笔记-图形相关-线段平滑-vtkSplineFilter类

  在实际的开发中,提供有限的连续线段组成一条曲线,需要将该条曲线进行插值处理,生成更高采样率的曲线;这种情况下就需要进行插值;VTK中的线段插值是通过B样条插值实现,使用vtkSplineFilter完成这一功能;

vtkSplineFilter

  vtkSplineFilter是一个从多段线的输入集生成输出多段线的Filter。
  通过用户可以指定的vtkSpline类(默认情况下使用vtkCardinalSpline),可以对多段线进行统一细分和生成。可以通过多种方式控制线的细分数目。用户可以指定细分的数量,也可以提供每个细分的长度(vtkSplineFilter类将计算出整个多段线上需要计算出多少个细分段)。也可以设置最大细分数。
  此Filter的输出是每个输入多段线(或线)的多段线。将创建新的点和纹理坐标。对点数据进行插值,并传递单元数据。任何少于两点的多段线或具有重合点的多段线都将被忽略。
在这里插入图片描述

接口

细分段个数

vtkSetClampMacro(NumberOfSubdivisions, int, 1, VTK_INT_MAX);
vtkGetMacro(NumberOfSubdivisions, int);
vtkSetClampMacro(MaximumNumberOfSubdivisions, int, 1, VTK_INT_MAX);
vtkGetMacro(MaximumNumberOfSubdivisions, int);
void SetSubdivideToSpecified() { this->SetSubdivide(VTK_SUBDIVIDE_SPECIFIED); }
void SetSubdivideToLength() { this->SetSubdivide(VTK_SUBDIVIDE_LENGTH); }
vtkSetClampMacro(Subdivide, int, VTK_SUBDIVIDE_SPECIFIED, VTK_SUBDIVIDE_LENGTH);
vtkGetMacro(Subdivide, int);
vtkSetClampMacro(Length, double, 0.0000001, VTK_DOUBLE_MAX);
vtkGetMacro(Length, double);
const char* GetSubdivideAsString();

  SetNumberOfSubdivisions:设置为多段线创建的细分数目。只有将Subdivisions设置为SetSubdivisionsToSpecify()时,此方法才有效。
  SetSubdivideToSpecified:指定如何确定细分数目。
  SetLength基于绝对长度控制为多段线创建的细分数目。样条曲线的长度除以此长度以确定细分的数目。只有将Subdivisions设置为SetSubdivideToLength()时,此方法才有效。
  SetMaximumNumberOfSubdivisions:设置为每条多段线创建的最大细分数。

插值类型对象

vtkSpline是样条插值的样条抽象类,SetSpline设置了vtkSplineFilter使用的vtkSpline的派生类对象,可以使用vtkCardinalSpline/vtkKochanekSpline/vtkSCurveSpline;

virtual void SetSpline(vtkSpline*);
vtkGetObjectMacro(Spline, vtkSpline);

纹理坐标

  纹理坐标可以通过三种方式生成:归一化(0,1)生成;基于长度(除以纹理长度);通过使用输入的标量值。

意义
VTK_TCOORDS_FROM_NORMALIZED_LENGTH归一化方式
VTK_TCOORDS_FROM_LENGTH基于长度方式
VTK_TCOORDS_FROM_SCALARS基于输入的标量值方式
vtkSetClampMacro(GenerateTCoords, int, VTK_TCOORDS_OFF, VTK_TCOORDS_FROM_SCALARS);
vtkGetMacro(GenerateTCoords, int);
void SetGenerateTCoordsToOff() { this->SetGenerateTCoords(VTK_TCOORDS_OFF); }
void SetGenerateTCoordsToNormalizedLength(){this->SetGenerateTCoords(VTK_TCOORDS_FROM_NORMALIZED_LENGTH);}
void SetGenerateTCoordsToUseLength() { this->SetGenerateTCoords(VTK_TCOORDS_FROM_LENGTH); }
void SetGenerateTCoordsToUseScalars() { this->SetGenerateTCoords(VTK_TCOORDS_FROM_SCALARS); }
const char* GetGenerateTCoordsAsString();  
vtkSetClampMacro(TextureLength, double, 0.000001, VTK_INT_MAX);
vtkGetMacro(TextureLength, double);

vtkSpline

在这里插入图片描述
  vtkSpline插值一组数据点(插值意味着样条曲线通过这些点)。
  vtkSpline是一个抽象类:它的子类vtkCardinalSpline、vtkKochanekSpline和vtkSCurveSpline实现vtkSpline提供的接口功能。请注意,此样条曲线将1D参数化坐标t映射为单个值x。因此,如果要使用样条曲线插值点(即x[3]),则必须为每个x-y-z坐标创建三条样条曲线。vtkParametricSpline类可以将离散点拟合成一条样条曲线。通常,样条曲线是通过添加一系列参数坐标/数据(t,x)值,然后使用求值函数(例如,vtkCardinalSpline::Evaluate())来使用的。因为这些样条曲线是一维的,所以这里的一个点是独立/因变量对。样条曲线也可以设置为关闭或打开。闭合样条曲线以连续函数和导数值从最后一点延续到第一点(无需复制第一个点即可闭合样条曲线,只需设置ClosedOn即可)。
  样条曲线的这种实现不使用规范化的参数化坐标。如果样条曲线打开,则参数空间为(tMin<=t<=tMax),其中tMin和tMax是执行AddPoint()时看到的最小和最大参数值。如果样条曲线是闭合的,那么参数空间是(tMin<=t<=(tMax+1)),其中tMin和tMax是执行AddPoint()时看到的最小和最大参数值。但是,请注意,可以通过显式设置ParametricRange(tMin,tMax)来更改此行为。如果设置,则参数空间保持不变(tMin<=t<=tMax),除非参数值超出此范围的数据的添加被限制在此范围内。
样条:通过一组指定点集生成平滑曲线的柔型带;
样条曲线:计算机图形学中,样条曲线指多项式曲线段连接而成的曲线;

样条(Spline) 可以理解为 多段 Cubic Curve 的拼接,不过样条在 Cubic Curve 拼接的时候,提出了特殊要求:两段 Cubic Curve 在拼接的位置,需要能够“平滑衔接”,以保证整个样条的曲线平滑。这种“平滑衔接”,是通过导数和曲线的连续性来实现的。

需要实现的两个接口

virtual void Compute() = 0;  
virtual double Evaluate(double t) = 0;

参数空间

void SetParametricRange(double tMin, double tMax);
void SetParametricRange(double tRange[2]) { this->SetParametricRange(tRange[0], tRange[1]); }
void GetParametricRange(double tRange[2]) const;

  SetParametricRange设置参数空间范围;如果未设置,则通过跟踪t的(min,max)参数值隐式确定范围。如果设置了,AddPoint()方法会将t值钳制在指定的范围内。

样条曲线拟合的点

void AddPoint(double t, double x);  
void RemovePoint(double t);  
void RemoveAllPoints();  
int GetNumberOfPoints();

  AddPoint添加一对要与样条曲线拟合的点。
  RemovePoint移除一个坐标对应的点;
  RemoveAllPoints移除所有点;

夹逼模式

vtkSetMacro(ClampValue, vtkTypeBool);
vtkGetMacro(ClampValue, vtkTypeBool);
vtkBooleanMacro(ClampValue, vtkTypeBool);

  SetClampValue设置插值夹逼类型,如果启用,插值结果将被钳制为输入数据的最小值/最大值。

样条区间是否打开

vtkSetMacro(Closed, vtkTypeBool);
vtkGetMacro(Closed, vtkTypeBool);
vtkBooleanMacro(Closed, vtkTypeBool);

  SetClosed()设置是否开启闭合样条曲线,闭合样条曲线形成一个连续的循环:第一个点和最后一个点是相同的,导数是连续的。

   vtkSetClampMacro(LeftConstraint, int, 0, 3);
   vtkGetMacro(LeftConstraint, int);
   vtkSetClampMacro(RightConstraint, int, 0, 3);
   vtkGetMacro(RightConstraint, int);  
   vtkSetMacro(LeftValue, double);
   vtkGetMacro(LeftValue, double);
   vtkSetMacro(RightValue, double);
   vtkGetMacro(RightValue, double);

  SetLeftConstraint和SetRightConstraint设置左(右)端点的约束类型。
  有四个约束:

含义
0最左(右)点的一阶导数由前(后)两点定义的直线确定
1最左(右)点的一阶导数设为左(右)值
2最左(右)点的二阶导数设为左(右)值
3最左(右)点的二阶导数是左(右)值乘以第一个内点的二阶导数

  SetLeftValue和SetRightValue用来设置左右两边导数的值。

vtkCardinalSpline

  在Cardinal样条中,一个控制点的一阶导数值可以由两个相邻控制点的坐标进行计算。
  一个Cardinal样条完全由四个连续控制点给出,中间两个控制点是曲线端点,另外两个点用于计算端点斜率。
  如图14.12所示,设P(u)是两控制点Pk和Pk+1间的参数三次函数式,则从Pk-1到Pk+1间的四个控制点用于建立cardinal样条段的边界条件:
    P(0) = pk;
    P(1) = pk+1;
    P(0) =1/2*(1-t)(pk+1-pk-1);
    P(1) =1/2
(1-t)*(pk+2-pk);
  控制点Pk​和Pk+1处的一阶导数(斜率)分别和弦Pk-1Pk+1和PkPk+2​成正比。参数t称为张量(tension)参数,因为t控制cardinal样条与输入控制点之间的松紧程度。图14.14说明了张量t取很大和很小值时cardinal曲线的形状。当t=0时,这样的曲线称为Catmull-Rom样条或Overhauser样条。
在这里插入图片描述

接口

在这里插入代码片

vtkKochanekSpline

  vtkKochanekSpline提供三个参数来控制花键的形状:
    张力:更改切线向量的长度;
    偏差:主要改变切向量的方向;
    连续性:改变切线之间变化的清晰度;
  给出了四个连续控制点,记为Pk-1、Pk、Pk+1和Pk+2,在Pk和Pk+1间的Konchanek-Bartels曲线段中的边界条件定义为:
    P(0) = pk;
    P(1) = pk+1;
    P(0)in =1/2*(1-t*)[(1+b)(1-c)*(pk-pk-1)+(1-b)+(1-b)*(1+c)*(pk+1-pk)];
    P(1)out 1/2*(1-t*)[(1+b)(1+c)*(pk+1-pk)+(1-b)+(1-b)*(1-c)*(pk+2-pk+1)];
其中t是张量(tension)参数,b是偏离(bias)参数,c是连续性(continuity)参数。在Konchanek-Bartels公式中,导数在曲线段边界处不一定是连续。
张量参数t具有cardinal样条公式中同样的解释,即该参数控制曲线段的松紧程度。偏离参数b用来调整曲线段在端点处弯曲的数值,因此曲线段可以偏向一个端点或另一个端点(参见图14.19)。参数c控制切向量在曲线段边界处的连续性。若c取非零值,则曲线在曲线段边界处的斜率上具有不连续性。
在这里插入图片描述

#include <vtkActor.h>
#include <vtkGlyph3DMapper.h>
#include <vtkKochanekSpline.h>
#include <vtkNamedColors.h>
#include <vtkNew.h>
#include <vtkParametricFunctionSource.h>
#include <vtkParametricSpline.h>
#include <vtkPointSource.h>
#include <vtkPoints.h>
#include <vtkPolyData.h>
#include <vtkPolyDataMapper.h>
#include <vtkProperty.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkRenderer.h>
#include <vtkSphereSource.h>

#include "vtkAutoInit.h" 
VTK_MODULE_INIT(vtkRenderingOpenGL2);
VTK_MODULE_INIT(vtkInteractionStyle);
using namespace std;

int main()
{
	vtkNew<vtkNamedColors> colors;

	int numberOfPoints = 10;
	vtkNew<vtkPointSource> pointSource;
	pointSource->SetNumberOfPoints(numberOfPoints);
	pointSource->Update();

	vtkPoints* points = pointSource->GetOutput()->GetPoints();

	vtkNew<vtkKochanekSpline> xSpline;
	vtkNew<vtkKochanekSpline> ySpline;
	vtkNew<vtkKochanekSpline> zSpline;

	vtkNew<vtkParametricSpline> spline;
	spline->SetXSpline(xSpline);
	spline->SetYSpline(ySpline);
	spline->SetZSpline(zSpline);
	spline->SetPoints(points);

	vtkNew<vtkParametricFunctionSource> functionSource;
	functionSource->SetParametricFunction(spline);
	functionSource->SetUResolution(50 * numberOfPoints);
	functionSource->SetVResolution(50 * numberOfPoints);
	functionSource->SetWResolution(50 * numberOfPoints);
	functionSource->Update();

	// Setup actor and mapper
	vtkNew<vtkPolyDataMapper> mapper;
	mapper->SetInputConnection(functionSource->GetOutputPort());

	vtkNew<vtkActor> actor;
	actor->SetMapper(mapper);
	actor->GetProperty()->SetColor(colors->GetColor3d("DarkSlateGrey").GetData());
	actor->GetProperty()->SetLineWidth(3.0);

	// Glyph the points
	vtkNew<vtkSphereSource> sphere;
	sphere->SetPhiResolution(21);
	sphere->SetThetaResolution(21);
	sphere->SetRadius(.02);

	// Create a polydata to store everything in
	vtkNew<vtkPolyData> polyData;
	polyData->SetPoints(points);

	vtkNew<vtkGlyph3DMapper> pointMapper;
	pointMapper->SetInputData(polyData);
	pointMapper->SetSourceConnection(sphere->GetOutputPort());

	vtkNew<vtkActor> pointActor;
	pointActor->SetMapper(pointMapper);
	pointActor->GetProperty()->SetColor(colors->GetColor3d("Peacock").GetData());

	// Setup render window, renderer, and interactor
	vtkNew<vtkRenderer> renderer;
	vtkNew<vtkRenderWindow> renderWindow;
	renderWindow->AddRenderer(renderer);
	renderWindow->SetWindowName("KochanekSpline");

	vtkNew<vtkRenderWindowInteractor> renderWindowInteractor;
	renderWindowInteractor->SetRenderWindow(renderWindow);

	renderer->AddActor(actor);
	renderer->AddActor(pointActor);

	renderer->SetBackground(colors->GetColor3d("Silver").GetData());

	renderWindow->Render();
	renderWindowInteractor->Start();

	return 0;
}

在这里插入图片描述

vtkSCurveSpline

vtkSCurveSpline 使用曲线基计算插值样条曲线。使用方法同vtkKochanekSpline;

示例

1.生成8条线段;

	float x[8][3] = {
		{0,0,0},{1,0,0},{1,1,0},{0,1,0},
		{0,0,1},{1,0,1},{1,1,1},{0,1,1}
	};
	vtkNew<vtkPolyData> geometry;
	vtkNew<vtkPoints> points;
	for (size_t i = 0; i < 8; i++)	{
		points->InsertPoint(i, x[i]);
	}
	vtkNew<vtkCellArray> polys;
	polys->InsertNextCell(8);
	for (size_t i = 0; i < 8; i++)	{		
		polys->InsertCellPoint(i);
	}

	geometry->SetPoints(points);
	geometry->SetLines(polys);

	vtkNew<vtkPolyDataMapper> geometryMapper;
	geometryMapper->SetInputData(geometry);
	vtkNew<vtkActor> geometryActor;
	geometryActor->SetMapper(geometryMapper);

	vtkNew<vtkRenderer> renderer;
	renderer->AddActor(geometryActor);
	renderer->ResetCamera();
	renderer->SetBackground(0, 0, 0);

	vtkNew<vtkRenderWindow> renWin;
	renWin->AddRenderer(renderer);
	renWin->SetSize(300, 300);

	vtkNew<vtkRenderWindowInteractor> iren;
	iren->SetRenderWindow(renWin);

	renWin->Render();
	iren->Start();

在这里插入图片描述
2.使用样条插值后

	float x[8][3] = {
		{0,0,0},{1,0,0},{1,1,0},{0,1,0},
		{0,0,1},{1,0,1},{1,1,1},{0,1,1}
	};
	vtkNew<vtkPolyData> geometry;
	vtkNew<vtkPoints> points;
	for (size_t i = 0; i < 8; i++)	{
		points->InsertPoint(i, x[i]);
	}
	vtkNew<vtkCellArray> polys;
	polys->InsertNextCell(8);
	for (size_t i = 0; i < 8; i++)	{		
		polys->InsertCellPoint(i);
	}

	geometry->SetPoints(points);
	geometry->SetLines(polys);

	vtkNew<vtkCardinalSpline> spline;
	spline->SetLeftConstraint(2);
	spline->SetLeftValue(0.0);
	spline->SetRightConstraint(2);
	spline->SetRightValue(0.0);
	vtkNew<vtkSplineFilter> filter;
	filter->SetInputData(geometry);
	filter->SetNumberOfSubdivisions(100);
	filter->SetSpline(spline);
	filter->Update();

	vtkNew<vtkPolyDataMapper> geometryMapper;
	geometryMapper->SetInputData(filter->GetOutput());
	vtkNew<vtkActor> geometryActor;
	geometryActor->SetMapper(geometryMapper);

	vtkNew<vtkRenderer> renderer;
	renderer->AddActor(geometryActor);
	renderer->ResetCamera();
	renderer->SetBackground(0, 0, 0);

	vtkNew<vtkRenderWindow> renWin;
	renWin->AddRenderer(renderer);
	renWin->SetSize(300, 300);

	vtkNew<vtkRenderWindowInteractor> iren;
	iren->SetRenderWindow(renWin);

	renWin->Render();
	iren->Start();

在这里插入图片描述

参考文献

1.vtkSpline
2.vtkCardinalSpline
3.vtkKochanekSpline
4.vtkSCurveSpline

  • 0
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

黑山老妖的笔记本

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值