Merge pull request #1892 from pijyoi/glpainteritem
This commit is contained in:
commit
d3755520d0
@ -1,6 +1,6 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
"""
|
"""
|
||||||
Demonstrate use of GLLinePlotItem to draw cross-sections of a surface.
|
This example demonstrates the use of GLBarGraphItem.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
## Add path to library (just for examples; you do not need this)
|
## Add path to library (just for examples; you do not need this)
|
||||||
|
94
examples/GLPainterItem.py
Normal file
94
examples/GLPainterItem.py
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
"""
|
||||||
|
Demonstrate using QPainter on a subclass of GLGraphicsItem.
|
||||||
|
"""
|
||||||
|
## Add path to library (just for examples; you do not need this)
|
||||||
|
import initExample
|
||||||
|
|
||||||
|
import pyqtgraph as pg
|
||||||
|
import pyqtgraph.opengl
|
||||||
|
from pyqtgraph.Qt import QtCore, QtGui
|
||||||
|
import OpenGL.GL as GL
|
||||||
|
|
||||||
|
SIZE = 32
|
||||||
|
|
||||||
|
class GLPainterItem(pg.opengl.GLGraphicsItem.GLGraphicsItem):
|
||||||
|
def __init__(self, **kwds):
|
||||||
|
super().__init__()
|
||||||
|
glopts = kwds.pop('glOptions', 'additive')
|
||||||
|
self.setGLOptions(glopts)
|
||||||
|
|
||||||
|
def compute_projection(self):
|
||||||
|
modelview = GL.glGetDoublev(GL.GL_MODELVIEW_MATRIX)
|
||||||
|
projection = GL.glGetDoublev(GL.GL_PROJECTION_MATRIX)
|
||||||
|
mvp = projection.T @ modelview.T
|
||||||
|
mvp = QtGui.QMatrix4x4(mvp.ravel().tolist())
|
||||||
|
|
||||||
|
# note that QRectF.bottom() != QRect.bottom()
|
||||||
|
rect = QtCore.QRectF(self.view().rect())
|
||||||
|
ndc_to_viewport = QtGui.QMatrix4x4()
|
||||||
|
ndc_to_viewport.viewport(rect.left(), rect.bottom(), rect.width(), -rect.height())
|
||||||
|
|
||||||
|
return ndc_to_viewport * mvp
|
||||||
|
|
||||||
|
def paint(self):
|
||||||
|
self.setupGLState()
|
||||||
|
|
||||||
|
painter = QtGui.QPainter(self.view())
|
||||||
|
self.draw(painter)
|
||||||
|
painter.end()
|
||||||
|
|
||||||
|
def draw(self, painter):
|
||||||
|
painter.setPen(QtCore.Qt.GlobalColor.white)
|
||||||
|
painter.setRenderHints(QtGui.QPainter.RenderHint.Antialiasing | QtGui.QPainter.RenderHint.TextAntialiasing)
|
||||||
|
|
||||||
|
rect = self.view().rect()
|
||||||
|
af = QtCore.Qt.AlignmentFlag
|
||||||
|
|
||||||
|
painter.drawText(rect, af.AlignTop | af.AlignRight, 'TR')
|
||||||
|
painter.drawText(rect, af.AlignBottom | af.AlignLeft, 'BL')
|
||||||
|
painter.drawText(rect, af.AlignBottom | af.AlignRight, 'BR')
|
||||||
|
|
||||||
|
opts = self.view().cameraParams()
|
||||||
|
lines = []
|
||||||
|
center = opts['center']
|
||||||
|
lines.append(f"center : ({center.x():.1f}, {center.y():.1f}, {center.z():.1f})")
|
||||||
|
for key in ['distance', 'fov', 'elevation', 'azimuth']:
|
||||||
|
lines.append(f"{key} : {opts[key]:.1f}")
|
||||||
|
xyz = self.view().cameraPosition()
|
||||||
|
lines.append(f"xyz : ({xyz.x():.1f}, {xyz.y():.1f}, {xyz.z():.1f})")
|
||||||
|
info = "\n".join(lines)
|
||||||
|
painter.drawText(rect, af.AlignTop | af.AlignLeft, info)
|
||||||
|
|
||||||
|
project = self.compute_projection()
|
||||||
|
|
||||||
|
hsize = SIZE // 2
|
||||||
|
for xi in range(-hsize, hsize+1):
|
||||||
|
for yi in range(-hsize, hsize+1):
|
||||||
|
if xi == -hsize and yi == -hsize:
|
||||||
|
# skip one corner for visual orientation
|
||||||
|
continue
|
||||||
|
vec3 = QtGui.QVector3D(xi, yi, 0)
|
||||||
|
pos = project.map(vec3).toPointF()
|
||||||
|
painter.drawEllipse(pos, 1, 1)
|
||||||
|
|
||||||
|
|
||||||
|
pg.mkQApp("GLPainterItem Example")
|
||||||
|
glv = pg.opengl.GLViewWidget()
|
||||||
|
glv.show()
|
||||||
|
glv.setWindowTitle('pyqtgraph example: GLPainterItem')
|
||||||
|
glv.setCameraPosition(distance=50, elevation=90, azimuth=0)
|
||||||
|
|
||||||
|
griditem = pg.opengl.GLGridItem()
|
||||||
|
griditem.setSize(SIZE, SIZE)
|
||||||
|
griditem.setSpacing(1, 1)
|
||||||
|
glv.addItem(griditem)
|
||||||
|
|
||||||
|
axisitem = pg.opengl.GLAxisItem()
|
||||||
|
axisitem.setSize(SIZE/2, SIZE/2, 1)
|
||||||
|
glv.addItem(axisitem)
|
||||||
|
|
||||||
|
paintitem = GLPainterItem()
|
||||||
|
glv.addItem(paintitem)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
pg.exec()
|
@ -70,51 +70,15 @@ conditionalExamples = {
|
|||||||
False,
|
False,
|
||||||
reason="Test is being problematic on CI machines"
|
reason="Test is being problematic on CI machines"
|
||||||
),
|
),
|
||||||
'GLVolumeItem.py': exceptionCondition(
|
}
|
||||||
not darwin_opengl_broken,
|
|
||||||
reason=darwin_opengl_reason
|
openglExamples = ['GLViewWidget.py']
|
||||||
),
|
openglExamples.extend(utils.examples_['3D Graphics'].values())
|
||||||
'GLIsosurface.py': exceptionCondition(
|
for key in openglExamples:
|
||||||
not darwin_opengl_broken,
|
conditionalExamples[key] = exceptionCondition(
|
||||||
reason=darwin_opengl_reason
|
|
||||||
),
|
|
||||||
'GLSurfacePlot.py': exceptionCondition(
|
|
||||||
not darwin_opengl_broken,
|
|
||||||
reason=darwin_opengl_reason
|
|
||||||
),
|
|
||||||
'GLScatterPlotItem.py': exceptionCondition(
|
|
||||||
not darwin_opengl_broken,
|
|
||||||
reason=darwin_opengl_reason
|
|
||||||
),
|
|
||||||
'GLshaders.py': exceptionCondition(
|
|
||||||
not darwin_opengl_broken,
|
|
||||||
reason=darwin_opengl_reason
|
|
||||||
),
|
|
||||||
'GLTextItem.py': exceptionCondition(
|
|
||||||
not darwin_opengl_broken,
|
|
||||||
reason=darwin_opengl_reason
|
|
||||||
),
|
|
||||||
'GLLinePlotItem.py': exceptionCondition(
|
|
||||||
not darwin_opengl_broken,
|
|
||||||
reason=darwin_opengl_reason
|
|
||||||
),
|
|
||||||
'GLMeshItem.py': exceptionCondition(
|
|
||||||
not darwin_opengl_broken,
|
|
||||||
reason=darwin_opengl_reason
|
|
||||||
),
|
|
||||||
'GLImageItem.py': exceptionCondition(
|
|
||||||
not darwin_opengl_broken,
|
|
||||||
reason=darwin_opengl_reason
|
|
||||||
),
|
|
||||||
'GLBarGraphItem.py': exceptionCondition(
|
|
||||||
not darwin_opengl_broken,
|
|
||||||
reason=darwin_opengl_reason
|
|
||||||
),
|
|
||||||
'GLViewWidget.py': exceptionCondition(
|
|
||||||
not darwin_opengl_broken,
|
not darwin_opengl_broken,
|
||||||
reason=darwin_opengl_reason
|
reason=darwin_opengl_reason
|
||||||
)
|
)
|
||||||
}
|
|
||||||
|
|
||||||
@pytest.mark.skipif(
|
@pytest.mark.skipif(
|
||||||
Qt.QT_LIB == "PySide2"
|
Qt.QT_LIB == "PySide2"
|
||||||
|
@ -74,6 +74,8 @@ examples_ = OrderedDict([
|
|||||||
('Mesh', 'GLMeshItem.py'),
|
('Mesh', 'GLMeshItem.py'),
|
||||||
('Image', 'GLImageItem.py'),
|
('Image', 'GLImageItem.py'),
|
||||||
('Text', 'GLTextItem.py'),
|
('Text', 'GLTextItem.py'),
|
||||||
|
('BarGraph', 'GLBarGraphItem.py'),
|
||||||
|
('Painter', 'GLPainterItem.py'),
|
||||||
])),
|
])),
|
||||||
('Widgets', OrderedDict([
|
('Widgets', OrderedDict([
|
||||||
('PlotWidget', 'PlotWidget.py'),
|
('PlotWidget', 'PlotWidget.py'),
|
||||||
@ -105,7 +107,6 @@ others = dict([
|
|||||||
('ScaleBar', 'ScaleBar.py'),
|
('ScaleBar', 'ScaleBar.py'),
|
||||||
('ViewBox', 'ViewBox.py'),
|
('ViewBox', 'ViewBox.py'),
|
||||||
('GradientEditor', 'GradientEditor.py'),
|
('GradientEditor', 'GradientEditor.py'),
|
||||||
('GLBarGraphItem', 'GLBarGraphItem.py'),
|
|
||||||
('GLViewWidget', 'GLViewWidget.py'),
|
('GLViewWidget', 'GLViewWidget.py'),
|
||||||
('DiffTreeWidget', 'DiffTreeWidget.py'),
|
('DiffTreeWidget', 'DiffTreeWidget.py'),
|
||||||
('MultiPlotWidget', 'MultiPlotWidget.py'),
|
('MultiPlotWidget', 'MultiPlotWidget.py'),
|
||||||
|
@ -326,6 +326,21 @@ class GLViewWidget(QtWidgets.QOpenGLWidget):
|
|||||||
)
|
)
|
||||||
return pos
|
return pos
|
||||||
|
|
||||||
|
def setCameraParams(self, **kwds):
|
||||||
|
valid_keys = {'center', 'rotation', 'distance', 'fov', 'elevation', 'azimuth'}
|
||||||
|
if not valid_keys.issuperset(kwds):
|
||||||
|
raise ValueError(f'valid keywords are {valid_keys}')
|
||||||
|
|
||||||
|
self.setCameraPosition(pos=kwds.get('center'), distance=kwds.get('distance'),
|
||||||
|
elevation=kwds.get('elevation'), azimuth=kwds.get('azimuth'),
|
||||||
|
rotation=kwds.get('rotation'))
|
||||||
|
if 'fov' in kwds:
|
||||||
|
self.opts['fov'] = kwds['fov']
|
||||||
|
|
||||||
|
def cameraParams(self):
|
||||||
|
valid_keys = {'center', 'rotation', 'distance', 'fov', 'elevation', 'azimuth'}
|
||||||
|
return { k : self.opts[k] for k in valid_keys }
|
||||||
|
|
||||||
def orbit(self, azim, elev):
|
def orbit(self, azim, elev):
|
||||||
"""Orbits the camera around the center position. *azim* and *elev* are given in degrees."""
|
"""Orbits the camera around the center position. *azim* and *elev* are given in degrees."""
|
||||||
if self.opts['rotationMethod'] == 'quaternion':
|
if self.opts['rotationMethod'] == 'quaternion':
|
||||||
|
Loading…
Reference in New Issue
Block a user