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()
相关推荐
Petrichor_H_41 分钟前
DAY 43 复习日
开发语言·python
m0_738120721 小时前
渗透测试——Kioptrix5靶机渗透测试详细教程
网络·python·安全·web安全·ssh
z***94841 小时前
Java进阶07 嵌套类
java·开发语言·python
橘子编程1 小时前
仓颉语言:华为新一代编程利器
java·c语言·开发语言·数据库·python·青少年编程
Darenm1111 小时前
Vue Router 路由管理
python·vue
___波子 Pro Max.1 小时前
Python argparse 参数解析用法详解
python
风华浪浪1 小时前
python 基础之 jsonpatch 用于对 JSON 文档的局部更新操作
linux·python·json
FeiHuo565151 小时前
微信个人号API二次开发:如何提高开发效率和质量
java·开发语言·python·php
wsj__WSJ1 小时前
Python 项目管理工具 uv 详解
python·conda·virtualenv