VTK 空间几何变换(Transform),平移、旋转和缩放

摘要:
空间变换的基础知识变换矩阵我们都知道,在屏幕上显示的是二维的图形,三维图形都是投影到二维平面的,但它们定义在三维空间的。VTK有关空间变换的类和方法VTK相关的类有:vtkTransform,vtkTransformFilter,vtkMatrix4x4等相关的方法有:RotateX、RotateY、RotateZRotateWXYZScaleTranslateSetMatrix、GetMatrixPostMultiply()、PreMultiply()SetPosition、GetPositionSetOrientation、GetOrientationSetScaleSetOrigin、GetOrigin下面通过几个场景来看看上面的一些类和方法是如何使用以及一些常见的问题。对于变换矩阵,VTK是用以下顺序来应用这些变化的:1.移动actor到它的origin,缩放和旋转都是基于这个点完成的。

先看下面的模型,这是一个Cow的三维模型,

VTK 空间几何变换(Transform),平移、旋转和缩放第1张

在使用中,你是否会有下面的操作?

1.将Cow移动到某个位置——平移

2.转动到Cow背面——旋转

3.改变它大小——缩放

等等

可能你会说,这还不简单,通过操作相机就好了。然而并不是这样,操作相机,只使得相机的空间位置发生了变化,对三维物体并没有改变,要想改变模型,就需要对模形本身做空间变换。

空间变换的基础知识

变换矩阵(Transformation Matrices)

我们都知道,在屏幕上显示的是二维的图形,三维图形都是投影到二维平面的,但它们定义在三维空间的。空间变换的基本元素都是三维坐标点,在计算机图形学中,三维坐标点用齐次坐标表示。利用齐次坐标,可以将空间变换用4x4的矩阵来表示。这些变换最终都是由矩阵的运算完成。

VTK有关空间变换的类和方法

VTK相关的类有:

vtkTransform,vtkTransformFilter, vtkMatrix4x4等

相关的方法有:

• RotateX(angle)、RotateY(angle)、RotateZ(angle)

• RotateWXYZ(angle,x,y,z)

• Scale(x,y,z)

• Translate(x,y,z)

• SetMatrix(m)、GetMatrix(m)

• PostMultiply()、PreMultiply()

• SetPosition(x,y,z)、GetPosition(x,y,z)

• SetOrientation(x,y,z)、GetOrientation(x,y,z)

• SetScale(sx,sy,sz)

• SetOrigin(x,y,z)、GetOrigin

下面通过几个场景来看看上面的一些类和方法是如何使用以及一些常见的问题。

VTK 空间几何变换(Transform),平移、旋转和缩放第2张

[图1 圆锥体位于(0,0,0),坐标轴向量长度为1个单位]

场景一:矩阵的顺序问题

我们要对图1中位于世界坐标系原点的圆锥体做如下操作:

1. 圆锥体在X轴正方向上移动1个单位

2.绕Z轴旋转45^{circ}

1 vtkSmartPointer<vtkTransform> trans = 
2     vtkSmartPointer<vtkTransform>::New();
3 trans->PostMultiply();
4 trans->Translate(1, 0, 0);
5 trans->RotateZ(45);
6 coneActor->SetUserTransform(trans);

VTK 空间几何变换(Transform),平移、旋转和缩放第4张

试着改变一下1, 2两步的顺序:

VTK 空间几何变换(Transform),平移、旋转和缩放第5张

对比来看,是两个不同的结果。而这个结果正是因为矩阵乘法并不满足交换定律。

因此,在使用时,进行变换的顺序非常重要,将对结果产生直接的影响。

对于变换矩阵,VTK是用以下顺序来应用这些变化的:

VTK 空间几何变换(Transform),平移、旋转和缩放第6张

1. 移动actor到它的origin,缩放和旋转都是基于这个点完成的。

2. 缩放几何体。

3.actor依次绕Y, X和Z轴旋转。

4.从旋转中心移回到原来的位置后再移动actor到最终的位置。

在VTK中,矩阵乘法默认是左乘,即PreMultiply,上面的公式也遵循这个原则。为了便于理解,示例代码特地使用了右乘PostMultiply.

场景二:GetMatrix和GetUserMatrix的区别

Code1:

1 coneActor->RotateZ(45);
2 coneActor->SetPosition(1, 0, 0);

VTK 空间几何变换(Transform),平移、旋转和缩放第7张

Code2:

1 trans->RotateZ(45);
2 trans->Translate(1, 0, 0);
3 coneActor->SetUserTransform(trans);

VTK 空间几何变换(Transform),平移、旋转和缩放第8张

从两个结果可以看出,GetMatix和GetUserMatrix都是获取变换矩阵。所不同的是:

GetMatrix始终都可以获取到值,也就是说它得到的是圆锥体在世界坐标系的变换矩阵。

GetUserMatrix在Code2中获取到了值,而在Code1中得到是NULL,这说明它获取的是用户设置的变换矩阵。

注:GetUserMatrix、SetUserMatrix和GetUserTransform、SetUserTransform具有相同的作用。

完整示例代码

1 #include <vtkLineSource.h>
2 #include <vtkPolyData.h>
3 #include <vtkSmartPointer.h>
4 #include <vtkPolyDataMapper.h>
5 #include <vtkActor.h>
6 #include <vtkRenderWindow.h>
7 #include <vtkRenderer.h>
8 #include <vtkRenderWindowInteractor.h>
9 #include <vtkProperty.h>
10 #include <vtkAxesActor.h>
11 #include <vtkConeSource.h>
12 #include <vtkTextActor.h>
13 #include <vtkTextProperty.h>
14 #include <vtkTransform.h>
15 #include <vtkSphereSource.h>
16  
17 int main(int, char *[])
18 {
19     vtkSmartPointer<vtkSphereSource> sphereSource =
20         vtkSmartPointer<vtkSphereSource>::New();
21     sphereSource->SetRadius(0.1);
22     sphereSource->Update();
23  
24     vtkSmartPointer<vtkPolyDataMapper> sphereMapper =
25         vtkSmartPointer<vtkPolyDataMapper>::New();
26     sphereMapper->SetInputConnection(sphereSource->GetOutputPort());
27  
28     vtkSmartPointer<vtkActor> sphereActor =
29         vtkSmartPointer<vtkActor>::New();
30     sphereActor->SetPosition(0, 0, 0);
31     sphereActor->SetMapper(sphereMapper);
32     sphereActor->GetProperty()->SetColor(1, 0, 0);
33  
34     vtkSmartPointer<vtkConeSource> coneSource =
35         vtkSmartPointer<vtkConeSource>::New();
36     coneSource->SetRadius(.2);
37     coneSource->SetHeight(.5);
38     coneSource->SetCenter(0, 0, 0);
39     vtkSmartPointer<vtkPolyDataMapper> coneMapper =
40         vtkSmartPointer<vtkPolyDataMapper>::New();
41     coneMapper->SetInputConnection(coneSource->GetOutputPort());
42     vtkSmartPointer<vtkActor> coneActor =
43         vtkSmartPointer<vtkActor>::New();
44     coneActor->SetMapper(coneMapper);
45  
46     vtkSmartPointer<vtkActor> oriConeActor =
47         vtkSmartPointer<vtkActor>::New();
48     oriConeActor->SetMapper(coneMapper);
49 #define AXIS_LEN 1.
50     vtkSmartPointer<vtkAxesActor> oriAxesActor =
51         vtkSmartPointer<vtkAxesActor>::New();
52     oriAxesActor->SetPosition(0, 0, 0);
53     oriAxesActor->SetTotalLength(AXIS_LEN, AXIS_LEN, AXIS_LEN);
54     oriAxesActor->SetShaftType(0);
55     oriAxesActor->SetAxisLabels(0);
56     oriAxesActor->SetCylinderRadius(0.02);
57  
58     vtkSmartPointer<vtkAxesActor> axesActor =
59         vtkSmartPointer<vtkAxesActor>::New();
60     axesActor->SetPosition(0, 0, 0);
61     axesActor->SetTotalLength(AXIS_LEN, AXIS_LEN, AXIS_LEN);
62     axesActor->SetShaftType(0);
63     axesActor->SetAxisLabels(0);
64     axesActor->SetCylinderRadius(0.02);
65  
66     vtkSmartPointer<vtkTextActor> textActor = 
67         vtkSmartPointer<vtkTextActor>::New();
68     textActor->SetPosition2(100, 40);
69     textActor->GetTextProperty()->SetFontSize(24);
70     textActor->GetTextProperty()->SetColor(1, 0, 0);
71  
72  
73     vtkSmartPointer<vtkTransform> trans = 
74         vtkSmartPointer<vtkTransform>::New();
75  
76 #if 0
77     trans->PostMultiply();
78  
79     coneActor->SetPosition(1, 0, 0);
80     //trans->Translate(1, 0, 0);
81     //trans->RotateZ(45);
82     trans->RotateZ(45);
83     trans->Translate(1, 0, 0);
84     coneActor->SetUserTransform(trans);
85     //textActor->SetInput("PostMultiply()
Translate(1, 0, 0)
RotateZ(45)");
86     textActor->SetInput("PostMultiply()
RotateZ(45)
Translate(1, 0, 0)");
87 #endif
88  
89 #if 1
90     //coneActor->RotateZ(45);
91     //coneActor->SetPosition(1, 0, 0);
92     //textActor->SetInput("coneActor->RotateZ(45)
coneActor->SetPosition(1, 0, 0)");
93  
94     trans->RotateZ(45);
95     trans->Translate(1, 0, 0);
96     coneActor->SetUserTransform(trans);
97     textActor->SetInput("trans->RotateZ(45)
trans->Translate(1, 0, 0)
coneActor->SetUserTransform(trans)");
98  
99     cout << "GetMatrix:" <<endl;
100     if (coneActor->GetMatrix()!=NULL)
101 {
102         coneActor->GetMatrix()->Print(cout);
103 }
104     else
105 {
106         cout << "NULL" <<endl;
107 }
108     cout << "GetUserMatrix:" <<endl;
109     if (coneActor->GetUserMatrix() !=NULL)
110 {
111         coneActor->GetUserMatrix()->Print(cout);
112 }
113     else
114 {
115         cout << "NULL" <<endl;
116 }
117     //cout << "GetUserTransform:" << endl;
118     //if (coneActor->GetUserTransform() !=NULL)
119     //{
120     //coneActor->GetUserTransform()->Print(cout);
121     //}
122     //else
123     //{
124     //cout << "NULL" << endl;
125     //}
126 #endif
127     vtkSmartPointer<vtkRenderer> renderer1 =
128         vtkSmartPointer<vtkRenderer>::New();
129     vtkSmartPointer<vtkRenderer> renderer2 =
130         vtkSmartPointer<vtkRenderer>::New();
131  
132     vtkSmartPointer<vtkRenderWindow> renderWindow =
133         vtkSmartPointer<vtkRenderWindow>::New();
134     renderWindow->SetSize(800, 400);
135     renderWindow->AddRenderer(renderer1);
136     renderWindow->AddRenderer(renderer2);
137     vtkSmartPointer<vtkRenderWindowInteractor> renderWindowInteractor =
138         vtkSmartPointer<vtkRenderWindowInteractor>::New();
139     renderWindowInteractor->SetRenderWindow(renderWindow);
140  
141     double leftViewport[] = { 0.0, 0.0, 0.5, 1.0};
142     double rightViewport[] = { 0.5, 0.0, 1.0, 1.0};
143  
144     renderer1->AddActor(oriAxesActor);
145     renderer1->AddActor(sphereActor);
146     renderer1->AddActor(oriConeActor);
147     renderer2->AddActor(axesActor);
148     renderer2->AddActor(sphereActor);
149     renderer2->AddActor(coneActor);
150     renderer2->AddActor2D(textActor);
151     renderer1->SetBackground(.3, .3, .5);
152     renderer2->SetBackground(.2, .4, .5);
153     renderer1->SetViewport(leftViewport);
154     renderer2->SetViewport(rightViewport);
155  
156     renderWindow->Render();
157     renderWindowInteractor->Start();
158  
159     returnEXIT_SUCCESS;
160 }

免责声明:文章转载自《VTK 空间几何变换(Transform),平移、旋转和缩放》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇c++ 发送消息,模拟拖拽文件Qt使用镜像源快速安装与更新下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

判断上三角矩阵

2019年春季学期第三周作业 基础作业本周没上课,但是请大家不要忘记学习。本周请大家完成上周挑战作业的第一部分:给定一个整数数组(包含正负数),找到一个具有最大和的子数组,返回其最大的子数组的和。例如:[1, -2, 3, 10, -4, 7, 2, -5]的最大子数组为[3, 10, -4, 7, 2]输入: 请建立以自己英文名字命名的txt文件,并输入...

OptimalSolution(5)--数组和矩阵问题(1)简单

  一、转圈打印矩阵   题目:给定一个整型矩阵matrix,按照转圈的方式打印它。   要求:额外空间复杂度为O(1) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 打印结果为:1 2 3 4 8 12 16 15 14 13 9 5 6 7 11 10   思路:矩阵分圈处理问题。用...

抖音很火的3D旋转相册 (源代码分享)

效果: 旋转,鼠标移上旋张开 百度云盘代码分享: 链接:https://pan.baidu.com/s/1d7Rozcs7x6Pgt6WxpGphiQ提取码:3dpt 实现流程 工具:电脑右键记事本  材料:照片 打开方式:点击浏览器打开 代码技术:Html+css 步骤1:准备照片 规格100×100 6张图片  400×400 6张大图片  (图...

使用lockbits方法处理图像(转)

   许多图像处理任务即时是最简单的文件类型转换,例如从32位深度到8位深度的格式转化,直接获得像素阵列要比使用GetPixel和SetPixel等方法的效率高得多。         你可能会发现DotNet采用托管机制,大多数情况下微软会推荐你使用托管代码,理由是便捷和安全。实际应用中,直接操作内存中的数据块是很少见的,尽管如此,图像处理恰恰是这类为数...

vs2010驱动开发环境配置

1、文件 -> 新建 -> 项目 -> Visual C++ -> 空项目 名称:Driver 2、生成 -> 配置管理器   活动解决方案配置: 新建 名称:Driver Debug 从此处复制设置:Debug 3、视图 -> 属性管理器  展开刚配置的Driver Debug | Win32  ->  右...

矩阵方程的计算求解(Matlab实现)

一、Lyapunov方程的计算求解1、连续Lyapunov方程连续Lyapunov方程可以表示为: AX + XA* = -C % 其中A*是A的转置1Lyapunov方程源于微分方程稳定性理论,其中要求-C为对称正定的nxn矩阵,从而可以证明解X亦为nxn对称矩阵。Lyapunov类的方程求解是很困难的,可以利用Matlab控制系统工具箱中提供的lyap...