Импорт:
from pyqtgraph.Qt import QtCore, QtGui
import pyqtgraph.opengl as gl
import numpy as np
Хорошо, во-первых, похоже, вы не можете запустить два QApplication
одновременно. Так что вместо
app = QtGui.QApplication([])
запись
app = QtGui.QApplication.instance()
if app is None:
app = QtGui.QApplication([])
Это создаст новый экземпляр вместо нового приложения только в том случае, если он уже существует.
Теперь для рисования сетки с pyqtgraph
. Вы должны определить вершины своей сетки. Для куба это восемь углов:
vertexes = np.array([[1, 0, 0], #0
[0, 0, 0], #1
[0, 1, 0], #2
[0, 0, 1], #3
[1, 1, 0], #4
[1, 1, 1], #5
[0, 1, 1], #6
[1, 0, 1]])#7
Это только положения углов в декартовых координатах.
Теперь мы должны определить лица. Это треугольники, поэтому нам нужно 12 из них для куба. Мы даем углы треугольников в позициях массивов вершин, которые должны охватывать треугольник:
faces = np.array([[1,0,7], [1,3,7],
[1,2,4], [1,0,4],
[1,2,6], [1,3,6],
[0,4,5], [0,7,5],
[2,4,5], [2,6,5],
[3,6,5], [3,7,5]])
Там вполне может быть алгоритм; сейчас я просто написал это от руки; возможно я обновлю позже.
Теперь мы должны определить цвета граней. Нам нужны значения RGBA для каждого лица; Я только сделал это красным:
colors = np.array([[1,0,0,1] for i in range(12)])
С этим мы можем создать GLMeshItem
. Я рисую края черным, чтобы вы могли видеть треугольники:
cube = gl.GLMeshItem(vertexes=vertexes, faces=faces, faceColors=colors,
drawEdges=True, edgeColor=(0, 0, 0, 1))
Теперь нам просто нужно добавить элемент и запустить основной цикл:
w.addItem(cube)
if __name__ == '__main__':
import sys
if (sys.flags.interactive != 1) or not hasattr(QtCore, 'PYQT_VERSION'):
QtGui.QApplication.instance().exec_()
Куб можно перемещать с помощью:
cube.translate(x,y,z)
Он будет автоматически обновляться. И, конечно, вы можете иметь несколько экземпляров куба в списке.
РЕДАКТИРОВАТЬ Я действительно нашел уродливый алгоритм. Он использует идею, что хотя бы одна координата всегда должна быть одинаковой, если треугольники находятся на поверхности куба. Новый код:
from pyqtgraph.Qt import QtCore, QtGui
import pyqtgraph.opengl as gl
import numpy as np
import itertools
app = QtGui.QApplication.instance()
if app is None:
app = QtGui.QApplication([])
w = gl.GLViewWidget()
w.opts['distance'] = 20
w.show()
w.setWindowTitle('A cube')
vertexes = np.array(list(itertools.product(range(2),repeat=3)))
faces = []
for i in range(2):
temp = np.where(vertexes==i)
for j in range(3):
temp2 = temp[0][np.where(temp[1]==j)]
for k in range(2):
faces.append([temp2[0],temp2[1+k],temp2[3]])
faces = np.array(faces)
colors = np.array([[1,0,0,1] for i in range(12)])
cube = gl.GLMeshItem(vertexes=vertexes, faces=faces, faceColors=colors,
drawEdges=True, edgeColor=(0, 0, 0, 1))
w.addItem(cube)
if __name__ == '__main__':
import sys
if (sys.flags.interactive != 1) or not hasattr(QtCore, 'PYQT_VERSION'):
QtGui.QApplication.instance().exec_()
РЕДАКТИРОВАТЬ 2 Ошибка в pyqtgraph
из-за внутреннего деления на ноль. Если вы перейдете к файлу MeshData.py
, вы найдете функцию vertexNormals
. Я изменил первое if
заявление на:
if self._vertexNormals is None:
faceNorms = self.faceNormals()
vertFaces = self.vertexFaces()
self._vertexNormals = np.empty(self._vertexes.shape, dtype=float)
for vindex in xrange(self._vertexes.shape[0]):
faces = vertFaces[vindex]
if len(faces) == 0:
self._vertexNormals[vindex] = (0,0,0)
continue
norms = faceNorms[faces] ## get all face normals
norm = norms.sum(axis=0) ## sum normals
if all(norm==0):
self._vertexNormals[vindex] = norm
continue
#norm /= (norm**2).sum()**0.5 ## and re-normalize
np.true_divide(norm, (norm**2).sum()**0.5, out=norm, casting='unsafe')
self._vertexNormals[vindex] = norm
Теперь он не выдает никаких ошибок. Это потому что:
- Я не пользуюсь, казалось бы, устаревшим
/=
- Я просто
continue
, если вектор является нулевым вектором