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·自然语言处理
SeaTunnel3 小时前
从 Python Script 地狱到标准化数据集成框架
大数据·开发语言·python·程序员·代码·seatunnel
深度研习笔记3 小时前
OpenCV工业视觉实战09|项目EXE打包+工控机无环境部署+后台常驻运行,彻底脱离Python环境,完成项目最终交付
python·opencv·webpack
CCPC不拿奖不改名3 小时前
大模型推理架构与开源生态知识整理
数据库·windows·python·架构·langchain·开源·github
Marst Code4 小时前
(python)2026Plotly 库评估:交互式可视化到底值不值得引入?
开发语言·python
databook4 小时前
当散点图不够用时:用 t-SNE 可视化多维数据
python·数据分析·数据可视化
我的xiaodoujiao6 小时前
快速学习Python基础知识详细图文教程9--函数进阶
开发语言·python·学习·测试工具
weixin_408099677 小时前
2026 图片去水印 API 接口完全指南:一键去除图片水印(附 Python/Java/PHP/C# 示例)
java·python·php·图片处理·api调用·图片去水印·石榴智能
去码头整点薯条ing7 小时前
某当网登录滑块【协议+OCR】
爬虫·python·ocr
赶紧写完去睡觉8 小时前
Anaconda 创建虚拟环境与使用
python·pycharm·conda