一:主要的知识点
1、说明
本文只是教程内容的一小段,因博客字数限制,故进行拆分。主教程链接:vtk教程------逐行解析官网所有Python示例-CSDN博客
2、知识点纪要
本段代码主要涉及的有①对源数据的平移、缩放和缩放,②vtkTransform的concanate方法
二:代码及注释
python
from vtkmodules.vtkFiltersSources import vtkArrowSource
from vtkmodules.vtkCommonColor import vtkNamedColors
from vtkmodules.vtkCommonCore import vtkMath, vtkMinimalStandardRandomSequence
from vtkmodules.vtkCommonMath import vtkMatrix4x4
from vtkmodules.vtkCommonTransforms import vtkTransform
from vtkmodules.vtkFiltersGeneral import vtkTransformPolyDataFilter
from vtkmodules.vtkFiltersSources import (
vtkArrowSource,
vtkSphereSource
)
from vtkmodules.vtkRenderingCore import (
vtkActor,
vtkPolyDataMapper,
vtkRenderWindow,
vtkRenderWindowInteractor,
vtkRenderer
)
def main():
colors = vtkNamedColors()
colors.SetColor("BkgColor", [26, 51, 77, 255])
USE_MATRIX = True
"""
arrowSource无法通过自身携带的函数设置箭头的起点、终点和方向
很多vtk源都创建了一个标准化的模型,然后由变换负责将其移动、旋转和缩放到正确的位置
这样做的目的是:
解耦:将几何体的生成和它的空间变换分离开来,使得代码更清晰、更模块化
效率:你可以在一次渲染中,对一个原始模型应用不同的变换,来创建多个实例
"""
arrowSource = vtkArrowSource() # 标准箭头,从(0,0,0)指向(1, 0, 0)
"""
下面这段代码的目的就是创建一个变换矩阵,用于将一个标准化的箭头
(从 (0,0,0) 指向 (1,0,0) 的箭头)移动、旋转和缩放,使其从一个随机起点指向另一个随机终点
"""
startPoint = [0] * 3
endPoint = [0] * 3
rng = vtkMinimalStandardRandomSequence()
rng.SetSeed(82443)
for i in range(3):
rng.Next()
startPoint[i] = rng.GetRangeValue(-10, 10)
rng.Next()
endPoint[i] = rng.GetRangeValue(-10, 10)
normalizedX = [0] * 3
normalizedY = [0] * 3
normalizedZ = [0] * 3
vtkMath.Subtract(endPoint, startPoint, normalizedX)
length = vtkMath.Norm(normalizedX)
vtkMath.Normalize(normalizedX)
arbitrary = [0] * 3
for i in range(0, 3):
rng.Next()
arbitrary[i] = rng.GetRangeValue(-10, 10)
vtkMath.Cross(normalizedX, arbitrary, normalizedZ)
vtkMath.Normalize(normalizedZ)
vtkMath.Cross(normalizedZ, normalizedX, normalizedZ)
matrix = vtkMatrix4x4()
matrix.Identity()
for i in range(0, 3):
matrix.SetElement(i, 0, normalizedX[i])
matrix.SetElement(i, 1, normalizedY[i])
matrix.SetElement(i, 2, normalizedZ[i])
"""
必须严格按照缩放 → 旋转 → 平移的顺序来应用这些变换
个变换矩阵可以将一个点从其局部坐标系转换到世界坐标系。
T 代表平移矩阵(Translation)
R 代表旋转矩阵(Rotation)
S 代表缩放矩阵(Scale)
P_local 代表点在局部坐标系中的位置
P_world 代表点在世界坐标系中的位置
最终的变换公式是:
Pworld =T∗R∗S∗Plocal
这个公式意味着,对一个点应用变换时,应该先缩放,再旋转,最后平移。这是因为:
如果你先平移再旋转:物体会绕着新的平移位置旋转,而不是绕着它自身的中心旋转,这通常不是你想要的效果。
如果你先旋转再缩放:缩放会沿着已经旋转过的轴进行,可能导致不均匀的变形。
因此,从数学上讲,缩放 → 旋转 → 平移 的顺序是正确的。
"""
"""
vtkTransform的Concatenate 方法
有一个重要的特性,它执行的是矩阵后乘。这意味着,新连接的变换矩阵会放在当前变换矩阵的右边
最终的复合变换矩阵是 T∗R∗S,这与数学上的正确顺序完全一致。
因此,在 VTK 中使用 Concatenate 方法时,你需要按照平移、旋转、缩放的顺序调用函数,
才能得到正确的缩放、旋转、平移效果。
"""
transform = vtkTransform()
transform.Translate(startPoint)
transform.Concatenate(matrix)
transform.Scale(length, length, length)
"""
两种思路
1、直接对数据进行操作,产生新的数据,
2、在actor中,使用SetUserMatrix,不会产生新的数据,效率更高,但是不会改变底层数据
"""
transformPD = vtkTransformPolyDataFilter()
transformPD.SetTransform(transform)
transformPD.SetInputConnection(arrowSource.GetOutputPort())
mapper = vtkPolyDataMapper()
actor = vtkActor()
if USE_MATRIX:
mapper.SetInputConnection(arrowSource.GetOutputPort())
actor.SetUserMatrix(transform.GetMatrix())
else:
mapper.SetInputConnection(transformPD.GetOutputPort())
actor.SetMapper(mapper)
actor.GetProperty().SetColor(colors.GetColor3d("Cyan"))
sphereStartSource = vtkSphereSource()
sphereStartSource.SetCenter(startPoint)
sphereStartSource.SetRadius(0.8)
sphereStartMapper = vtkPolyDataMapper()
sphereStartMapper.SetInputConnection(sphereStartSource.GetOutputPort())
sphereStart = vtkActor()
sphereStart.SetMapper(sphereStartMapper)
sphereStart.GetProperty().SetColor(colors.GetColor3d('Yellow'))
sphereEndSource = vtkSphereSource()
sphereEndSource.SetCenter(endPoint)
sphereEndSource.SetRadius(0.8)
sphereEndMapper = vtkPolyDataMapper()
sphereEndMapper.SetInputConnection(sphereEndSource.GetOutputPort())
sphereEnd = vtkActor()
sphereEnd.SetMapper(sphereEndMapper)
sphereEnd.GetProperty().SetColor(colors.GetColor3d('Magenta'))
# Create a renderer, render window, and interactor
renderer = vtkRenderer()
renderWindow = vtkRenderWindow()
renderWindow.SetWindowName('OrientedArrow')
renderWindow.AddRenderer(renderer)
renderWindowInteractor = vtkRenderWindowInteractor()
renderWindowInteractor.SetRenderWindow(renderWindow)
# Add the actor to the scene
renderer.AddActor(actor)
renderer.AddActor(sphereStart)
renderer.AddActor(sphereEnd)
renderer.SetBackground(colors.GetColor3d('BkgColor'))
# Render and interact
renderWindow.Render()
renderWindowInteractor.Start()
if __name__ == '__main__':
main()