OrientedArrow 在两个随机生成的点之间绘制一根带箭头的线,以可视化一个向量

一:主要的知识点

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()
相关推荐
沈浩(种子思维作者)2 小时前
真的能精准医疗吗?癌症能提前发现吗?
人工智能·python·网络安全·健康医疗·量子计算
njsgcs2 小时前
ue python二次开发启动教程+ 导入fbx到指定文件夹
开发语言·python·unreal engine·ue
io_T_T2 小时前
迭代器 iteration、iter 与 多线程 concurrent 交叉实践(详细)
python
华研前沿标杆游学3 小时前
2026年走进洛阳格力工厂参观游学
python
Carl_奕然3 小时前
【数据挖掘】数据挖掘必会技能之:A/B测试
人工智能·python·数据挖掘·数据分析
AI小怪兽3 小时前
基于YOLOv13的汽车零件分割系统(Python源码+数据集+Pyside6界面)
开发语言·python·yolo·无人机
wszy18093 小时前
新文章标签:让用户一眼发现最新内容
java·python·harmonyos
Eric.Lee20214 小时前
python实现 mp4转gif文件
开发语言·python·手势识别·手势交互·手势建模·xr混合现实
EntyIU4 小时前
python开发中虚拟环境配置
开发语言·python
wszy18094 小时前
顶部标题栏的设计与实现:让用户知道自己在哪
java·python·react native·harmonyos