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()
相关推荐
砚底藏山河35 分钟前
python量化入门:多周期数据对齐统一时间轴
java·数据库·python·金融·maven
毕业设计7031 小时前
(免费领源码)django空气净化器销售系统09218- java、PHP、python、C#、小程序、大数据、单片机、网络工程等)
python·scrapy·mysql·pycharm·django·flask·pandas
小小张说故事2 小时前
Python 闭包到底捕获了啥?一个计数器例子讲透,别再背定义了
python
深蓝AI2 小时前
AI Agent 点了发布却超时:一条回执丢失,为什么能造成两篇文章?
人工智能·python
怪奇云呼军2 小时前
教育试听预约后没到课,闪电智能 Voice Agent 如何做分层回访?
人工智能·python·算法·云计算·音视频
weixin199701080162 小时前
《淘宝TOP API:落地方案、接口边界与业务踩坑 —— 聚石塔内外价差 10 倍的真相》(附 Python 源码)
开发语言·python
梦想的颜色2 小时前
【编程实战】AI 时代 APP 开发全栈硬核指南:技术选型 + AI 架构 + 模型落地全维度决策
python·flutter·react native·react.js·ai·桌面应用·milvus
Madison-No73 小时前
多语言聊天大模型--测试报告
linux·git·python·selenium·jmeter·自动化·postman
鲲鹏ai3 小时前
盈启鲲鹏数字人招商政策
大数据·人工智能·python
荣码3 小时前
从0到1搭一个生产级RAG系统:串联前面21篇所有知识
java·python