commit
58aac09387
@ -13,9 +13,9 @@ import numpy as np
|
||||
|
||||
app = pg.mkQApp("GLBarGraphItem Example")
|
||||
w = gl.GLViewWidget()
|
||||
w.opts['distance'] = 40
|
||||
w.show()
|
||||
w.setWindowTitle('pyqtgraph example: GLBarGraphItem')
|
||||
w.setCameraPosition(distance=40)
|
||||
|
||||
gx = gl.GLGridItem()
|
||||
gx.rotate(90, 0, 1, 0)
|
||||
|
@ -15,9 +15,9 @@ import numpy as np
|
||||
|
||||
app = pg.mkQApp("GLImageItem Example")
|
||||
w = gl.GLViewWidget()
|
||||
w.opts['distance'] = 200
|
||||
w.show()
|
||||
w.setWindowTitle('pyqtgraph example: GLImageItem')
|
||||
w.setCameraPosition(distance=200)
|
||||
|
||||
## create volume data set to slice three images from
|
||||
shape = (100,100,70)
|
||||
|
@ -13,9 +13,9 @@ import numpy as np
|
||||
|
||||
app = pg.mkQApp("GLLinePlotItem Example")
|
||||
w = gl.GLViewWidget()
|
||||
w.opts['distance'] = 40
|
||||
w.show()
|
||||
w.setWindowTitle('pyqtgraph example: GLLinePlotItem')
|
||||
w.setCameraPosition(distance=40)
|
||||
|
||||
gx = gl.GLGridItem()
|
||||
gx.rotate(90, 0, 1, 0)
|
||||
|
@ -15,9 +15,9 @@ import numpy as np
|
||||
|
||||
app = pg.mkQApp("GLScatterPlotItem Example")
|
||||
w = gl.GLViewWidget()
|
||||
w.opts['distance'] = 20
|
||||
w.show()
|
||||
w.setWindowTitle('pyqtgraph example: GLScatterPlotItem')
|
||||
w.setCameraPosition(distance=20)
|
||||
|
||||
g = gl.GLGridItem()
|
||||
w.addItem(g)
|
||||
|
@ -11,9 +11,9 @@ import pyqtgraph.opengl as gl
|
||||
|
||||
pg.mkQApp("GLViewWidget Example")
|
||||
w = gl.GLViewWidget()
|
||||
w.opts['distance'] = 20
|
||||
w.show()
|
||||
w.setWindowTitle('pyqtgraph example: GLViewWidget')
|
||||
w.setCameraPosition(distance=20)
|
||||
|
||||
ax = gl.GLAxisItem()
|
||||
ax.setSize(5,5,5)
|
||||
|
@ -14,9 +14,9 @@ from pyqtgraph import functions as fn
|
||||
|
||||
app = pg.mkQApp("GLVolumeItem Example")
|
||||
w = gl.GLViewWidget()
|
||||
w.opts['distance'] = 200
|
||||
w.show()
|
||||
w.setWindowTitle('pyqtgraph example: GLVolumeItem')
|
||||
w.setCameraPosition(distance=200)
|
||||
|
||||
g = gl.GLGridItem()
|
||||
g.scale(10, 10, 1)
|
||||
|
@ -4,6 +4,7 @@ import OpenGL.GL.framebufferobjects as glfbo
|
||||
import numpy as np
|
||||
from .. import Vector
|
||||
from .. import functions as fn
|
||||
from .. import getConfigOption
|
||||
import warnings
|
||||
from math import cos, sin, tan, radians
|
||||
##Vector = QtGui.QVector3D
|
||||
@ -21,10 +22,8 @@ class GLViewWidget(QtWidgets.QOpenGLWidget):
|
||||
================ ==============================================================
|
||||
**Arguments:**
|
||||
parent (QObject, optional): Parent QObject. Defaults to None.
|
||||
devicePixelRatio (float, optional): High-DPI displays Qt5 should automatically
|
||||
detect the correct resolution. For Qt4, specify the
|
||||
``devicePixelRatio`` argument when initializing the widget
|
||||
(usually this value is 1-2). Defaults to None.
|
||||
devicePixelRatio No longer in use. High-DPI displays should automatically
|
||||
detect the correct resolution.
|
||||
rotationMethod (str): Mechanimsm to drive the rotation method, options are
|
||||
'euler' and 'quaternion'. Defaults to 'euler'.
|
||||
================ ==============================================================
|
||||
@ -34,8 +33,8 @@ class GLViewWidget(QtWidgets.QOpenGLWidget):
|
||||
|
||||
self.setFocusPolicy(QtCore.Qt.FocusPolicy.ClickFocus)
|
||||
|
||||
if rotationMethod not in {"euler", "quaternion"}:
|
||||
raise RuntimeError("Rotation method should be either 'euler' or 'quaternion'")
|
||||
if rotationMethod not in ["euler", "quaternion"]:
|
||||
raise ValueError("Rotation method should be either 'euler' or 'quaternion'")
|
||||
|
||||
self.opts = {
|
||||
'center': Vector(0,0,0), ## will always appear at the center of the widget
|
||||
@ -46,7 +45,7 @@ class GLViewWidget(QtWidgets.QOpenGLWidget):
|
||||
'azimuth': 45, ## camera's azimuthal angle in degrees
|
||||
## (rotation around z-axis 0 points along x-axis)
|
||||
'viewport': None, ## glViewport params; None == whole widget
|
||||
'devicePixelRatio': devicePixelRatio,
|
||||
## note that 'viewport' is in device pixels
|
||||
'rotationMethod': rotationMethod
|
||||
}
|
||||
self.reset()
|
||||
@ -56,8 +55,6 @@ class GLViewWidget(QtWidgets.QOpenGLWidget):
|
||||
self.keysPressed = {}
|
||||
self.keyTimer = QtCore.QTimer()
|
||||
self.keyTimer.timeout.connect(self.evalKeyState)
|
||||
self.makeCurrent()
|
||||
|
||||
|
||||
def _updateScreen(self, screen):
|
||||
self._updatePixelRatio()
|
||||
@ -74,14 +71,13 @@ class GLViewWidget(QtWidgets.QOpenGLWidget):
|
||||
window.screenChanged.connect(self._updateScreen)
|
||||
self._updateScreen(window.screen())
|
||||
|
||||
def width(self):
|
||||
dpr = self.devicePixelRatio()
|
||||
return int(super().width() * dpr)
|
||||
|
||||
def height(self):
|
||||
dpr = self.devicePixelRatio()
|
||||
return int(super().height() * dpr)
|
||||
def deviceWidth(self):
|
||||
dpr = self.devicePixelRatioF()
|
||||
return int(self.width() * dpr)
|
||||
|
||||
def deviceHeight(self):
|
||||
dpr = self.devicePixelRatioF()
|
||||
return int(self.height() * dpr)
|
||||
|
||||
def reset(self):
|
||||
"""
|
||||
@ -94,20 +90,15 @@ class GLViewWidget(QtWidgets.QOpenGLWidget):
|
||||
self.opts['azimuth'] = 45 ## camera's azimuthal angle in degrees
|
||||
## (rotation around z-axis 0 points along x-axis)
|
||||
self.opts['viewport'] = None ## glViewport params; None == whole widget
|
||||
self.setBackgroundColor('k')
|
||||
self.setBackgroundColor(getConfigOption('background'))
|
||||
|
||||
def addItem(self, item):
|
||||
self.items.append(item)
|
||||
|
||||
if self.isValid():
|
||||
self.makeCurrent()
|
||||
try:
|
||||
item.initialize()
|
||||
except:
|
||||
self.checkOpenGLVersion('Error while adding item %s to GLViewWidget.' % str(item))
|
||||
item.initialize()
|
||||
|
||||
item._setView(self)
|
||||
#print "set view", item, self, item.view()
|
||||
self.update()
|
||||
|
||||
def removeItem(self, item):
|
||||
@ -131,6 +122,14 @@ class GLViewWidget(QtWidgets.QOpenGLWidget):
|
||||
"""
|
||||
Initialize items that were not initialized during addItem().
|
||||
"""
|
||||
ctx = self.context()
|
||||
fmt = ctx.format()
|
||||
if ctx.isOpenGLES() or fmt.version() < (2, 0):
|
||||
verString = glGetString(GL_VERSION)
|
||||
raise RuntimeError(
|
||||
"pyqtgraph.opengl: Requires >= OpenGL 2.0 (not ES); Found %s" % verString
|
||||
)
|
||||
|
||||
for item in self.items:
|
||||
if not item.isInitialized():
|
||||
item.initialize()
|
||||
@ -146,33 +145,18 @@ class GLViewWidget(QtWidgets.QOpenGLWidget):
|
||||
def getViewport(self):
|
||||
vp = self.opts['viewport']
|
||||
if vp is None:
|
||||
return (0, 0, self.width(), self.height())
|
||||
return (0, 0, self.deviceWidth(), self.deviceHeight())
|
||||
else:
|
||||
dpr = self.devicePixelRatio()
|
||||
return tuple([int(x * dpr) for x in vp])
|
||||
return vp
|
||||
|
||||
def devicePixelRatio(self):
|
||||
dpr = self.opts['devicePixelRatio']
|
||||
if dpr is not None:
|
||||
return dpr
|
||||
|
||||
return self.devicePixelRatioF()
|
||||
|
||||
def resizeGL(self, w, h):
|
||||
pass
|
||||
#glViewport(*self.getViewport())
|
||||
#self.update()
|
||||
|
||||
def setProjection(self, region=None):
|
||||
m = self.projectionMatrix(region)
|
||||
glMatrixMode(GL_PROJECTION)
|
||||
glLoadIdentity()
|
||||
a = np.array(m.copyDataTo()).reshape((4,4))
|
||||
glMultMatrixf(a.transpose())
|
||||
glLoadMatrixf(m.data())
|
||||
|
||||
def projectionMatrix(self, region=None):
|
||||
if region is None:
|
||||
region = (0, 0, self.width(), self.height())
|
||||
region = (0, 0, self.deviceWidth(), self.deviceHeight())
|
||||
|
||||
x0, y0, w, h = self.getViewport()
|
||||
dist = self.opts['distance']
|
||||
@ -194,11 +178,9 @@ class GLViewWidget(QtWidgets.QOpenGLWidget):
|
||||
return tr
|
||||
|
||||
def setModelview(self):
|
||||
glMatrixMode(GL_MODELVIEW)
|
||||
glLoadIdentity()
|
||||
m = self.viewMatrix()
|
||||
a = np.array(m.copyDataTo()).reshape((4,4))
|
||||
glMultMatrixf(a.transpose())
|
||||
glMatrixMode(GL_MODELVIEW)
|
||||
glLoadMatrixf(m.data())
|
||||
|
||||
def viewMatrix(self):
|
||||
tr = QtGui.QMatrix4x4()
|
||||
@ -218,7 +200,7 @@ class GLViewWidget(QtWidgets.QOpenGLWidget):
|
||||
Return a list of the items displayed in the region (x, y, w, h)
|
||||
relative to the widget.
|
||||
"""
|
||||
region = (region[0], self.height()-(region[1]+region[3]), region[2], region[3])
|
||||
region = (region[0], self.deviceHeight()-(region[1]+region[3]), region[2], region[3])
|
||||
|
||||
#buf = np.zeros(100000, dtype=np.uint)
|
||||
buf = glSelectBuffer(100000)
|
||||
@ -273,14 +255,7 @@ class GLViewWidget(QtWidgets.QOpenGLWidget):
|
||||
except:
|
||||
from .. import debug
|
||||
debug.printExc()
|
||||
msg = "Error while drawing item %s." % str(item)
|
||||
ver = glGetString(GL_VERSION)
|
||||
if ver is not None:
|
||||
ver = ver.split()[0]
|
||||
if int(ver.split(b'.')[0]) < 2:
|
||||
print(msg + " The original exception is printed above; however, pyqtgraph requires OpenGL version 2.0 or greater for many of its 3D features and your OpenGL version is %s. Installing updated display drivers may resolve this issue." % ver)
|
||||
else:
|
||||
print(msg)
|
||||
print("Error while drawing item %s." % str(item))
|
||||
|
||||
finally:
|
||||
glPopAttrib()
|
||||
@ -297,21 +272,40 @@ class GLViewWidget(QtWidgets.QOpenGLWidget):
|
||||
glPopMatrix()
|
||||
|
||||
def setCameraPosition(self, pos=None, distance=None, elevation=None, azimuth=None, rotation=None):
|
||||
if rotation is not None:
|
||||
# Alternatively, we could define that rotation overrides elevation and azimuth
|
||||
if elevation is not None:
|
||||
raise ValueError("cannot set both rotation and elevation")
|
||||
if azimuth is not None:
|
||||
raise ValueError("cannot set both rotation and azimuth")
|
||||
|
||||
if pos is not None:
|
||||
self.opts['center'] = pos
|
||||
if distance is not None:
|
||||
self.opts['distance'] = distance
|
||||
if rotation is not None:
|
||||
# set with quaternion
|
||||
self.opts['rotation'] = rotation
|
||||
|
||||
if self.opts['rotationMethod'] == "quaternion":
|
||||
# note that "quaternion" mode modifies only opts['rotation']
|
||||
if elevation is not None or azimuth is not None:
|
||||
eu = self.opts['rotation'].toEulerAngles()
|
||||
if azimuth is not None:
|
||||
eu.setZ(-azimuth-90)
|
||||
if elevation is not None:
|
||||
eu.setX(elevation-90)
|
||||
self.opts['rotation'] = QtGui.QQuaternion.fromEulerAngles(eu)
|
||||
if rotation is not None:
|
||||
self.opts['rotation'] = rotation
|
||||
else:
|
||||
# set with elevation-azimuth, restored for compatibility
|
||||
eu = self.opts['rotation'].toEulerAngles()
|
||||
if azimuth is not None:
|
||||
eu.setZ(-azimuth-90)
|
||||
# note that "euler" mode modifies only opts['elevation'] and opts['azimuth']
|
||||
if elevation is not None:
|
||||
eu.setX(elevation-90)
|
||||
self.opts['rotation'] = QtGui.QQuaternion.fromEulerAngles(eu)
|
||||
self.opts['elevation'] = elevation
|
||||
if azimuth is not None:
|
||||
self.opts['azimuth'] = azimuth
|
||||
if rotation is not None:
|
||||
eu = rotation.toEulerAngles()
|
||||
self.opts['elevation'] = eu.x() + 90
|
||||
self.opts['azimuth'] = -eu.z() - 90
|
||||
|
||||
self.update()
|
||||
|
||||
def cameraPosition(self):
|
||||
@ -492,7 +486,7 @@ class GLViewWidget(QtWidgets.QOpenGLWidget):
|
||||
return
|
||||
try:
|
||||
del self.keysPressed[ev.key()]
|
||||
except:
|
||||
except KeyError:
|
||||
self.keysPressed = {}
|
||||
self.evalKeyState()
|
||||
|
||||
@ -516,54 +510,11 @@ class GLViewWidget(QtWidgets.QOpenGLWidget):
|
||||
else:
|
||||
self.keyTimer.stop()
|
||||
|
||||
def checkOpenGLVersion(self, msg):
|
||||
"""
|
||||
Give exception additional context about version support.
|
||||
|
||||
Only to be called from within exception handler.
|
||||
As this check is only performed on error,
|
||||
unsupported versions might still work!
|
||||
"""
|
||||
|
||||
# Check for unsupported version
|
||||
verString = glGetString(GL_VERSION)
|
||||
ver = verString.split()[0]
|
||||
# If not OpenGL ES...
|
||||
if str(ver.split(b'.')[0]).isdigit():
|
||||
verNumber = int(ver.split(b'.')[0])
|
||||
# ...and version is supported:
|
||||
if verNumber >= 2:
|
||||
# OpenGL version is fine, raise the original exception
|
||||
raise
|
||||
|
||||
# Print original exception
|
||||
from .. import debug
|
||||
debug.printExc()
|
||||
|
||||
# Notify about unsupported version
|
||||
raise Exception(
|
||||
msg + "\n" + \
|
||||
"pyqtgraph.opengl: Requires >= OpenGL 2.0 (not ES); Found %s" % verString
|
||||
)
|
||||
|
||||
def readQImage(self):
|
||||
"""
|
||||
Read the current buffer pixels out as a QImage.
|
||||
"""
|
||||
w = self.width()
|
||||
h = self.height()
|
||||
self.repaint()
|
||||
pixels = np.empty((h, w, 4), dtype=np.ubyte)
|
||||
pixels[:] = 128
|
||||
pixels[...,0] = 50
|
||||
pixels[...,3] = 255
|
||||
|
||||
glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, pixels)
|
||||
|
||||
pixels = pixels[::-1].copy() # flip vertical
|
||||
|
||||
qimg = fn.ndarray_to_qimage(pixels, QtGui.QImage.Format.Format_RGBA8888)
|
||||
return qimg
|
||||
return self.grabFramebuffer()
|
||||
|
||||
def renderToArray(self, size, format=GL_BGRA, type=GL_UNSIGNED_BYTE, textureSize=1024, padding=256):
|
||||
w,h = map(int, size)
|
||||
@ -573,7 +524,7 @@ class GLViewWidget(QtWidgets.QOpenGLWidget):
|
||||
fb = None
|
||||
depth_buf = None
|
||||
try:
|
||||
output = np.empty((w, h, 4), dtype=np.ubyte)
|
||||
output = np.empty((h, w, 4), dtype=np.ubyte)
|
||||
fb = glfbo.glGenFramebuffers(1)
|
||||
glfbo.glBindFramebuffer(glfbo.GL_FRAMEBUFFER, fb )
|
||||
|
||||
@ -586,9 +537,9 @@ class GLViewWidget(QtWidgets.QOpenGLWidget):
|
||||
## Test texture dimensions first
|
||||
glTexImage2D(GL_PROXY_TEXTURE_2D, 0, GL_RGBA, texwidth, texwidth, 0, GL_RGBA, GL_UNSIGNED_BYTE, None)
|
||||
if glGetTexLevelParameteriv(GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_WIDTH) == 0:
|
||||
raise Exception("OpenGL failed to create 2D texture (%dx%d); too large for this hardware." % shape[:2])
|
||||
## create teture
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texwidth, texwidth, 0, GL_RGBA, GL_UNSIGNED_BYTE, data.transpose((1,0,2)))
|
||||
raise RuntimeError("OpenGL failed to create 2D texture (%dx%d); too large for this hardware." % data.shape[:2])
|
||||
## create texture
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texwidth, texwidth, 0, GL_RGBA, GL_UNSIGNED_BYTE, data)
|
||||
|
||||
# Create depth buffer
|
||||
depth_buf = glGenRenderbuffers(1)
|
||||
@ -614,8 +565,8 @@ class GLViewWidget(QtWidgets.QOpenGLWidget):
|
||||
|
||||
## read texture back to array
|
||||
data = glGetTexImage(GL_TEXTURE_2D, 0, format, type)
|
||||
data = np.fromstring(data, dtype=np.ubyte).reshape(texwidth,texwidth,4).transpose(1,0,2)[:, ::-1]
|
||||
output[x+padding:x2-padding, y+padding:y2-padding] = data[padding:w2-padding, -(h2-padding):-padding]
|
||||
data = np.frombuffer(data, dtype=np.ubyte).reshape(texwidth,texwidth,4)[::-1, ...]
|
||||
output[y+padding:y2-padding, x+padding:x2-padding] = data[-(h2-padding):-padding, padding:w2-padding]
|
||||
|
||||
finally:
|
||||
self.opts['viewport'] = None
|
||||
|
@ -99,5 +99,5 @@ class GLImageItem(GLGraphicsItem):
|
||||
glTexCoord2f(0,1)
|
||||
glVertex3f(0, self.data.shape[1], 0)
|
||||
glEnd()
|
||||
glDisable(GL_TEXTURE_3D)
|
||||
glDisable(GL_TEXTURE_2D)
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
from OpenGL.GL import *
|
||||
import numpy as np
|
||||
from pyqtgraph.Qt import QtCore, QtGui
|
||||
from pyqtgraph.opengl.GLGraphicsItem import GLGraphicsItem
|
||||
import pyqtgraph.functions as fn
|
||||
from ...Qt import QtCore, QtGui
|
||||
from .. GLGraphicsItem import GLGraphicsItem
|
||||
from ... import functions as fn
|
||||
|
||||
__all__ = ['GLTextItem']
|
||||
|
||||
@ -39,7 +39,7 @@ class GLTextItem(GLGraphicsItem):
|
||||
args = ['pos', 'color', 'text', 'font']
|
||||
for k in kwds.keys():
|
||||
if k not in args:
|
||||
raise ArgumentError('Invalid keyword argument: %s (allowed arguments are %s)' % (k, str(args)))
|
||||
raise ValueError('Invalid keyword argument: %s (allowed arguments are %s)' % (k, str(args)))
|
||||
for arg in args:
|
||||
if arg in kwds:
|
||||
value = kwds[arg]
|
||||
@ -65,12 +65,11 @@ class GLTextItem(GLGraphicsItem):
|
||||
|
||||
modelview = glGetDoublev(GL_MODELVIEW_MATRIX)
|
||||
projection = glGetDoublev(GL_PROJECTION_MATRIX)
|
||||
viewport = glGetIntegerv(GL_VIEWPORT)
|
||||
|
||||
viewport = [0, 0, self.view().width(), self.view().height()]
|
||||
text_pos = self.__project(self.pos, modelview, projection, viewport)
|
||||
|
||||
text_pos.setY(viewport[3] - text_pos.y())
|
||||
text_pos /= self.view().devicePixelRatio()
|
||||
|
||||
painter = QtGui.QPainter(self.view())
|
||||
painter.setPen(self.color)
|
||||
|
@ -162,4 +162,4 @@ if HAVE_OPENGL:
|
||||
glTexCoord2f(0, 0)
|
||||
glVertex3f(-1, 1, 0)
|
||||
glEnd()
|
||||
glDisable(GL_TEXTURE_3D)
|
||||
glDisable(GL_TEXTURE_2D)
|
||||
|
Loading…
x
Reference in New Issue
Block a user