如何使用 pyqtgraph 和 OpenGL 在两个更新的 3D 点之间连接椭圆形或圆柱形形状?

How to connect an oval or cylinder formed shape between two updating 3D points using pyqtgraph and OpenGL?

我想在 3D space 中使用 pyqtgraph 和 OpenGL 在两个更新点之间形成一个形状。目前,我只发现可以连接 GLLinePlotItem and GLMeshItem with vertexes and flat faces between two points. However, I would like to have an oval or cylinder form connected between the points, but I cannot seem to find a way to use the integrated MeshData 球体和圆柱体,而无需跳入复杂的数学、旋转矩阵和三角函数。

是否有更简单的方法,类似于 GLLinePlotItem 或 GLMeshItem?

说明我现在拥有什么,以及我想拥有什么:

示例代码:

from pyqtgraph.Qt import QtCore, QtGui
import pyqtgraph as pg
import pyqtgraph.opengl as gl
import numpy as np
import sys
from PyQt5.QtCore import QTimer
from PyQt5.QtWidgets import QMainWindow, QApplication
from random import randint

class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()

        w = gl.GLViewWidget()
        w.show()
        w.setCameraPosition(distance=15, azimuth=-90)

        self.timer = QTimer()
        self.timer.start(1000)
        self.timer.timeout.connect(self.start)

        g = gl.GLGridItem()
        g.scale(2, 2, 1)
        w.addItem(g)


        self.md = gl.MeshData.sphere(rows=10, cols=20)
        self.m1 = gl.GLMeshItem(meshdata=self.md,
                                smooth=True,
                                color=(1, 0, 0, 0.2),
                                shader="balloon",
                                glOptions="additive")
        w.addItem(self.m1)

        self.lineMesh = gl.GLLinePlotItem(width=1, antialias=False)
        w.addItem(self.lineMesh)


    def start(self):
        # coordinates

        point1 = np.array([randint(0,25), randint(0,25), 0])
        point2 = np.array([randint(0,25), randint(0,25), 20])

        line = np.array([point1, point2])
        self.lineMesh.setData(pos=line)

        length = (((point2[0] - point1[0]) ** 2 + (point2[1] - point1[1]) ** 2 + (
                point2[2] - point1[2]) ** 2) ** 0.5)*0.5

        center = (point1 + point2) / 2
        #radius = np.linalg.norm(point2 - point1) / 2


        self.md = gl.MeshData.sphere(rows=10, cols=20, radius=[1])
        self.m1.setMeshData(meshdata=self.md)

        self.m1.resetTransform()
        self.m1.scale(1, 1, length)
        self.m1.translate(*center)



if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = MainWindow()
    ex.show()
    sys.exit(app.exec_())

我认为您无法避免在这里做一些数学运算,但三角函数还不错:

        v = point2 - point1
        theta = np.arctan2(v[1], v[0])
        phi = np.arctan2(np.linalg.norm(v[:2]), v[2])

        tr = pg.Transform3D()
        tr.translate(*point1)
        tr.rotate(theta * 180 / np.pi, 0, 0, 1)
        tr.rotate(phi * 180 / np.pi, 0, 1, 0)
        tr.scale(1, 1, np.linalg.norm(v) / 2)
        tr.translate(0, 0, 1)

        self.m1.setTransform(tr)

如果你更喜欢线性代数而不是三角学,那也不错,虽然有点冗长:

        # pick 4 points on the untransformed sphere
        a = np.array([
            [0., 0., -1.],
            [0., 0., 1.],
            [1., 0., -1.],
            [0., 1., -1.],
        ])

        # and 4 corresponding points on the transformed sphere
        v1 = np.cross(point1-point2, [0., 0., 1.])
        v2 = np.cross(point1-point2, v1)
        b = np.array([
            point1,
            point2,
            point1 + v1 / np.linalg.norm(v1),
            point1 + v2 / np.linalg.norm(v2),
        ])

        # solve the transform mapping from a to b
        tr = pg.solve3DTransform(a, b)

        # make this transform work in opengl's homogeneous coordinate system
        tr[3,3] = 1

        self.m1.setTransform(tr)