I'd like to show a rotating cube in 3D reflecting roll/pitch/yaw updates from my IMU.
I've developed the code to display the box using GLMeshItem, now I'd like to add an update function that rotates it based on a rotation matrix derived from the IMU data.
I'm new to Qt, so please feel free to suggest an alternate methods. I may be barking up the wrong tree. I searched the docs and web a bit and tried a few things which didn't work.
Any suggestions will be appreciated.
When I run the code below "box3d.py" (derived from GLVolumeItem.py) I get the following exception in my update function. My update function blows:
Error while drawing item <pyqtgraph.opengl.items.GLMeshItem.GLMeshItem object at 0x7f4bdf664478>.
[14:34:24]
|==============================>>
| Traceback (most recent call last):
| File "box3d.py", line 105, in <module>
| if __name__ == '__main__':
| File "/usr/lib/python2.7/bdb.py", line 49, in trace_dispatch
| return self.dispatch_line(frame)
| File "/usr/lib/python2.7/bdb.py", line 67, in dispatch_line
| self.user_line(frame)
| File "/usr/lib/python2.7/pdb.py", line 158, in user_line
| self.interaction(frame, None)
| File "/usr/lib/python2.7/pdb.py", line 210, in interaction
| self.cmdloop()
| File "/usr/lib/python2.7/cmd.py", line 130, in cmdloop
| line = raw_input(self.prompt)
| File "/usr/lib/python2.7/dist-packages/pyqtgraph/opengl/GLViewWidget.py", line 179, in paintGL
| self.drawItemTree(useItemNames=useItemNames)
| File "/usr/lib/python2.7/dist-packages/pyqtgraph/opengl/GLViewWidget.py", line 219, in drawItemTree
| self.drawItemTree(i, useItemNames=useItemNames)
| File "/usr/lib/python2.7/dist-packages/pyqtgraph/opengl/GLViewWidget.py", line 200, in drawItemTree
| debug.printExc()
| --- exception caught here ---
| File "/usr/lib/python2.7/dist-packages/pyqtgraph/opengl/GLViewWidget.py", line 197, in drawItemTree
| i.paint()
| File "/usr/lib/python2.7/dist-packages/pyqtgraph/opengl/items/GLMeshItem.py", line 167, in paint
| self.parseMeshData()
| File "/usr/lib/python2.7/dist-packages/pyqtgraph/opengl/items/GLMeshItem.py", line 148, in parseMeshData
| self.normals = md.faceNormals(indexed='faces')
| File "/usr/lib/python2.7/dist-packages/pyqtgraph/opengl/MeshData.py", line 188, in faceNormals
| self._faceNormals = np.cross(v[:,1]-v[:,0], v[:,2]-v[:,0])
| File "/usr/lib/python2.7/dist-packages/numpy/core/numeric.py", line 1682, in cross
| raise ValueError(msg)
| ValueError: incompatible dimensions for cross product
| (dimension must be 2 or 3)
|==============================<<
Test code is here, in its entirety:
from pyqtgraph.Qt import QtCore, QtGui
import pyqtgraph as pg
import pyqtgraph.opengl as gl
import numpy as np
import math
import pdb
app = QtGui.QApplication([])
w = gl.GLViewWidget()
w.show()
w.setWindowTitle('3D Box')
w.setCameraPosition(distance=10, elevation=30, azimuth=90)
g = gl.GLGridItem()
g.scale(1,1,1)
w.addItem(g)
# Box vertices, faces, and face colors
verts_box = np.array([
[ 0, 0, 0],
[ 1, 0, 0],
[ 1, 1, 0],
[ 0, 1, 0],
[ 0, 0, 1],
[ 1, 0, 1],
[ 1, 1, 1],
[ 0, 1, 1]],
dtype=float)
faces_box = np.array([
[0, 1, 2],
[0, 2, 3],
[0, 1, 4],
[1, 5, 4],
[1, 2, 5],
[2, 5, 6],
[2, 3, 6],
[3, 6, 7],
[0, 3, 7],
[0, 4, 7],
[4, 5, 7],
[5, 6, 7],
])
colors_box = np.array([
[1, 1, 0, 0.5],
[1, 1, 0, 0.5],
[1, 0, 1, 0.5],
[1, 0, 1, 0.5],
[0, 1, 1, 0.5],
[0, 1, 1, 0.5],
[1, 0, 0, 0.5],
[1, 0, 0, 0.5],
[0, 1, 0, 0.5],
[0, 1, 0, 0.5],
[0, 0, 1, 0.5],
[0, 0, 1, 0.5],
])
## Mesh item will automatically compute face normals.
#m1 = gl.GLMeshItem(vertexes=verts, faces=faces, faceColors=colors, smooth=False)
m1 = gl.GLMeshItem(vertexes=verts_box, faces=faces_box, faceColors=colors_box, smooth=False)
m1.translate(0, 0, 0)
#m1.setGLOptions('additive')
w.addItem(m1)
def rotation_matrix(axis, theta):
"""
Return the rotation matrix associated with counterclockwise rotation about
the given axis by theta radians.
"""
axis = np.asarray(axis)
axis = axis/math.sqrt(np.dot(axis, axis))
a = math.cos(theta/2.0)
b, c, d = -axis*math.sin(theta/2.0)
aa, bb, cc, dd = a*a, b*b, c*c, d*d
bc, ad, ac, ab, bd, cd = b*c, a*d, a*c, a*b, b*d, c*d
return np.array([[aa+bb-cc-dd, 2*(bc+ad), 2*(bd-ac)],
[2*(bc-ad), aa+cc-bb-dd, 2*(cd+ab)],
[2*(bd+ac), 2*(cd-ab), aa+dd-bb-cc]])
R2 = rotation_matrix([0,0,1],np.pi/180.)
def update() :
global verts_box, m1, R2
verts_box = np.dot(verts_box,R2)
m1.setMeshData(vertexes=verts_box)
t = QtCore.QTimer()
t.timeout.connect(update)
t.start(500)
pdb.set_trace()
## Start Qt event loop unless running in interactive mode.
if __name__ == '__main__':
import sys
if (sys.flags.interactive != 1) or not hasattr(QtCore, 'PYQT_VERSION'):
QtGui.QApplication.instance().exec_()