2012-03-06 06:22:02 +00:00
|
|
|
from pyqtgraph.Qt import QtGui, QtCore
|
2012-10-27 01:47:45 +00:00
|
|
|
from pyqtgraph import Transform3D
|
2012-03-06 06:22:02 +00:00
|
|
|
|
|
|
|
class GLGraphicsItem(QtCore.QObject):
|
|
|
|
def __init__(self, parentItem=None):
|
|
|
|
QtCore.QObject.__init__(self)
|
|
|
|
self.__parent = None
|
|
|
|
self.__view = None
|
|
|
|
self.__children = set()
|
2012-10-27 01:47:45 +00:00
|
|
|
self.__transform = Transform3D()
|
2012-03-09 17:38:15 +00:00
|
|
|
self.__visible = True
|
2012-03-06 06:22:02 +00:00
|
|
|
self.setParentItem(parentItem)
|
|
|
|
self.setDepthValue(0)
|
|
|
|
|
|
|
|
def setParentItem(self, item):
|
|
|
|
if self.__parent is not None:
|
|
|
|
self.__parent.__children.remove(self)
|
|
|
|
if item is not None:
|
|
|
|
item.__children.add(self)
|
|
|
|
self.__parent = item
|
|
|
|
|
2012-03-09 17:38:15 +00:00
|
|
|
if self.__parent is not None and self.view() is not self.__parent.view():
|
|
|
|
if self.view() is not None:
|
|
|
|
self.view().removeItem(self)
|
|
|
|
self.__parent.view().addItem(self)
|
|
|
|
|
2012-03-06 06:22:02 +00:00
|
|
|
def parentItem(self):
|
|
|
|
return self.__parent
|
|
|
|
|
|
|
|
def childItems(self):
|
|
|
|
return list(self.__children)
|
|
|
|
|
|
|
|
def _setView(self, v):
|
|
|
|
self.__view = v
|
|
|
|
|
|
|
|
def view(self):
|
|
|
|
return self.__view
|
|
|
|
|
|
|
|
def setDepthValue(self, value):
|
|
|
|
"""
|
|
|
|
Sets the depth value of this item. Default is 0.
|
|
|
|
This controls the order in which items are drawn--those with a greater depth value will be drawn later.
|
|
|
|
Items with negative depth values are drawn before their parent.
|
|
|
|
(This is analogous to QGraphicsItem.zValue)
|
|
|
|
The depthValue does NOT affect the position of the item or the values it imparts to the GL depth buffer.
|
|
|
|
'"""
|
|
|
|
self.__depthValue = value
|
|
|
|
|
|
|
|
def depthValue(self):
|
|
|
|
"""Return the depth value of this item. See setDepthValue for mode information."""
|
|
|
|
return self.__depthValue
|
|
|
|
|
2012-03-09 17:38:15 +00:00
|
|
|
def setTransform(self, tr):
|
2012-10-27 01:47:45 +00:00
|
|
|
self.__transform = Transform3D(tr)
|
2012-03-09 17:38:15 +00:00
|
|
|
self.update()
|
|
|
|
|
2012-04-28 19:12:46 +00:00
|
|
|
def resetTransform(self):
|
|
|
|
self.__transform.setToIdentity()
|
|
|
|
self.update()
|
|
|
|
|
2012-03-09 17:38:15 +00:00
|
|
|
def applyTransform(self, tr, local):
|
|
|
|
"""
|
|
|
|
Multiply this object's transform by *tr*.
|
|
|
|
If local is True, then *tr* is multiplied on the right of the current transform:
|
|
|
|
newTransform = transform * tr
|
|
|
|
If local is False, then *tr* is instead multiplied on the left:
|
|
|
|
newTransform = tr * transform
|
|
|
|
"""
|
|
|
|
if local:
|
|
|
|
self.setTransform(self.transform() * tr)
|
|
|
|
else:
|
|
|
|
self.setTransform(tr * self.transform())
|
|
|
|
|
|
|
|
def transform(self):
|
|
|
|
return self.__transform
|
|
|
|
|
2012-10-27 01:47:45 +00:00
|
|
|
def viewTransform(self):
|
|
|
|
tr = self.__transform
|
|
|
|
p = self
|
|
|
|
while True:
|
|
|
|
p = p.parentItem()
|
|
|
|
if p is None:
|
|
|
|
break
|
|
|
|
tr = p.transform() * tr
|
|
|
|
return Transform3D(tr)
|
|
|
|
|
2012-03-09 17:38:15 +00:00
|
|
|
def translate(self, dx, dy, dz, local=False):
|
|
|
|
"""
|
|
|
|
Translate the object by (*dx*, *dy*, *dz*) in its parent's coordinate system.
|
|
|
|
If *local* is True, then translation takes place in local coordinates.
|
|
|
|
"""
|
2012-10-27 01:47:45 +00:00
|
|
|
tr = Transform3D()
|
2012-03-09 17:38:15 +00:00
|
|
|
tr.translate(dx, dy, dz)
|
|
|
|
self.applyTransform(tr, local=local)
|
|
|
|
|
|
|
|
def rotate(self, angle, x, y, z, local=False):
|
|
|
|
"""
|
|
|
|
Rotate the object around the axis specified by (x,y,z).
|
|
|
|
*angle* is in degrees.
|
|
|
|
|
|
|
|
"""
|
2012-10-27 01:47:45 +00:00
|
|
|
tr = Transform3D()
|
2012-03-09 17:38:15 +00:00
|
|
|
tr.rotate(angle, x, y, z)
|
|
|
|
self.applyTransform(tr, local=local)
|
|
|
|
|
|
|
|
def scale(self, x, y, z, local=True):
|
|
|
|
"""
|
|
|
|
Scale the object by (*dx*, *dy*, *dz*) in its local coordinate system.
|
|
|
|
If *local* is False, then scale takes place in the parent's coordinates.
|
|
|
|
"""
|
2012-10-27 01:47:45 +00:00
|
|
|
tr = Transform3D()
|
2012-03-09 17:38:15 +00:00
|
|
|
tr.scale(x, y, z)
|
|
|
|
self.applyTransform(tr, local=local)
|
|
|
|
|
|
|
|
|
|
|
|
def hide(self):
|
|
|
|
self.setVisible(False)
|
|
|
|
|
|
|
|
def show(self):
|
|
|
|
self.setVisible(True)
|
|
|
|
|
|
|
|
def setVisible(self, vis):
|
|
|
|
self.__visible = vis
|
|
|
|
self.update()
|
|
|
|
|
|
|
|
def visible(self):
|
|
|
|
return self.__visible
|
|
|
|
|
|
|
|
|
2012-03-06 06:22:02 +00:00
|
|
|
def initializeGL(self):
|
|
|
|
"""
|
|
|
|
Called after an item is added to a GLViewWidget.
|
|
|
|
The widget's GL context is made current before this method is called.
|
|
|
|
(So this would be an appropriate time to generate lists, upload textures, etc.)
|
|
|
|
"""
|
|
|
|
pass
|
|
|
|
|
|
|
|
def paint(self):
|
|
|
|
"""
|
|
|
|
Called by the GLViewWidget to draw this item.
|
|
|
|
It is the responsibility of the item to set up its own modelview matrix,
|
|
|
|
but the caller will take care of pushing/popping.
|
|
|
|
"""
|
|
|
|
pass
|
2012-03-09 17:38:15 +00:00
|
|
|
|
|
|
|
def update(self):
|
|
|
|
v = self.view()
|
|
|
|
if v is None:
|
|
|
|
return
|
|
|
|
v.updateGL()
|
|
|
|
|
2012-10-27 01:47:45 +00:00
|
|
|
def mapToParent(self, point):
|
|
|
|
tr = self.transform()
|
|
|
|
if tr is None:
|
|
|
|
return point
|
|
|
|
return tr.map(point)
|
|
|
|
|
2012-03-09 17:38:15 +00:00
|
|
|
def mapFromParent(self, point):
|
|
|
|
tr = self.transform()
|
|
|
|
if tr is None:
|
|
|
|
return point
|
2012-10-27 01:47:45 +00:00
|
|
|
return tr.inverted()[0].map(point)
|
|
|
|
|
|
|
|
def mapToView(self, point):
|
|
|
|
tr = self.viewTransform()
|
|
|
|
if tr is None:
|
|
|
|
return point
|
|
|
|
return tr.map(point)
|
|
|
|
|
|
|
|
def mapFromView(self, point):
|
|
|
|
tr = self.viewTransform()
|
|
|
|
if tr is None:
|
|
|
|
return point
|
|
|
|
return tr.inverted()[0].map(point)
|
|
|
|
|
|
|
|
|
|
|
|
|