简体   繁体   English

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

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

I would like to form a shape between two updating points in 3D space using pyqtgraph and OpenGL.我想使用 pyqtgraph 和 OpenGL 在 3D 空间中的两个更新点之间形成一个形状。 For now, I have only found it possible to connect GLLinePlotItem and GLMeshItem with vertexes and flat faces between two points.目前,我只发现可以将GLLinePlotItemGLMeshItem与两点之间的顶点和平面连接起来。 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 integratedMeshData sphere and cylinder, without jumping into complicated mathematics, rotation matrices and trigonometry.但是,我希望在点之间连接一个椭圆形或圆柱体形式,但我似乎无法找到一种方法来使用集成的MeshData球体和圆柱体,而不跳入复杂的数学、旋转矩阵和三角函数。

Is there a simpler way, similar to GLLinePlotItem or GLMeshItem?有没有更简单的方法,类似于 GLLinePlotItem 或 GLMeshItem?

Illustration of what I have right now, and what I would like to have instead:我现在拥有的东西以及我想要拥有的东西的插图:

在此处输入图像描述

Sample code:示例代码:

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_())

I don't think you can avoid having to do a little math here, but the trig isn't too bad:我不认为你可以避免在这里做一些数学运算,但是三角函数还不错:

        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)

And if you prefer linear algebra rather than trigonometry, that's not too bad either, although a bit more verbose:如果你更喜欢线性代数而不是三角函数,那也不错,虽然有点冗长:

        # 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)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM