Features:
- GLScatterPlotItem can work with arbitrarily-shaped vertex arrays - added colorToAlpha function Bugfixes: - GraphicsScene emits sigMouseClicked for all clicks - CanvasItem emits transformation change signal when mirrored - GLViewWidget.pixelSize correctly handles position specified as array - SRTTransform3D assumes Zscale=1 when converting from 2D transform
This commit is contained in:
parent
b25e34f564
commit
4ceae9f1a1
@ -73,7 +73,7 @@ class GraphicsScene(QtGui.QGraphicsScene):
|
||||
|
||||
sigMouseHover = QtCore.Signal(object) ## emits a list of objects hovered over
|
||||
sigMouseMoved = QtCore.Signal(object) ## emits position of mouse on every move
|
||||
sigMouseClicked = QtCore.Signal(object) ## emitted when MouseClickEvent is not accepted by any items under the click.
|
||||
sigMouseClicked = QtCore.Signal(object) ## emitted when mouse is clicked. Check for event.isAccepted() to see whether the event has already been acted on.
|
||||
|
||||
_addressCache = weakref.WeakValueDictionary()
|
||||
|
||||
@ -343,10 +343,11 @@ class GraphicsScene(QtGui.QGraphicsScene):
|
||||
if int(item.flags() & item.ItemIsFocusable) > 0:
|
||||
item.setFocus(QtCore.Qt.MouseFocusReason)
|
||||
break
|
||||
if not ev.isAccepted() and ev.button() is QtCore.Qt.RightButton:
|
||||
#if not ev.isAccepted() and ev.button() is QtCore.Qt.RightButton:
|
||||
#print "GraphicsScene emitting sigSceneContextMenu"
|
||||
self.sigMouseClicked.emit(ev)
|
||||
ev.accept()
|
||||
#self.sigMouseClicked.emit(ev)
|
||||
#ev.accept()
|
||||
self.sigMouseClicked.emit(ev)
|
||||
return ev.isAccepted()
|
||||
|
||||
#def claimEvent(self, item, button, eventType):
|
||||
|
@ -35,6 +35,7 @@ class SRTTransform3D(pg.Transform3D):
|
||||
'angle': init._state['angle'],
|
||||
'axis': Vector(0, 0, 1),
|
||||
}
|
||||
self._state['scale'][2] = 1.0
|
||||
self.update()
|
||||
elif isinstance(init, QtGui.QMatrix4x4):
|
||||
self.setFromMatrix(init)
|
||||
|
@ -205,6 +205,7 @@ class CanvasItem(QtCore.QObject):
|
||||
self.userTransform = self.userTransform * inv
|
||||
self.updateTransform()
|
||||
self.selectBoxFromUser()
|
||||
self.sigTransformChangeFinished.emit(self)
|
||||
#if flip:
|
||||
#if tr['scale'][0] < 0 xor tr['scale'][1] < 0:
|
||||
#return
|
||||
|
46
functions.py
46
functions.py
@ -991,7 +991,53 @@ def imageToArray(img, copy=False, transpose=True):
|
||||
else:
|
||||
return arr
|
||||
|
||||
def colorToAlpha(data, color):
|
||||
"""
|
||||
Given an RGBA image in *data*, convert *color* to be transparent.
|
||||
*data* must be an array (w, h, 3 or 4) of ubyte values and *color* must be
|
||||
an array (3) of ubyte values.
|
||||
This is particularly useful for use with images that have a black or white background.
|
||||
|
||||
Algorithm is taken from Gimp's color-to-alpha function in plug-ins/common/colortoalpha.c
|
||||
Credit:
|
||||
/*
|
||||
* Color To Alpha plug-in v1.0 by Seth Burgess, sjburges@gimp.org 1999/05/14
|
||||
* with algorithm by clahey
|
||||
*/
|
||||
|
||||
"""
|
||||
data = data.astype(float)
|
||||
if data.shape[-1] == 3: ## add alpha channel if needed
|
||||
d2 = np.empty(data.shape[:2]+(4,), dtype=data.dtype)
|
||||
d2[...,:3] = data
|
||||
d2[...,3] = 255
|
||||
data = d2
|
||||
|
||||
color = color.astype(float)
|
||||
alpha = np.zeros(data.shape[:2]+(3,), dtype=float)
|
||||
output = data.copy()
|
||||
|
||||
for i in [0,1,2]:
|
||||
d = data[...,i]
|
||||
c = color[i]
|
||||
mask = d > c
|
||||
alpha[...,i][mask] = (d[mask] - c) / (255. - c)
|
||||
imask = d < c
|
||||
alpha[...,i][imask] = (c - d[imask]) / c
|
||||
|
||||
output[...,3] = alpha.max(axis=2) * 255.
|
||||
|
||||
mask = output[...,3] >= 1.0 ## avoid zero division while processing alpha channel
|
||||
correction = 255. / output[...,3][mask] ## increase value to compensate for decreased alpha
|
||||
for i in [0,1,2]:
|
||||
output[...,i][mask] = ((output[...,i][mask]-color[i]) * correction) + color[i]
|
||||
output[...,3][mask] *= data[...,3][mask] / 255. ## combine computed and previous alpha values
|
||||
|
||||
#raise Exception()
|
||||
return np.clip(output, 0, 255).astype(np.ubyte)
|
||||
|
||||
|
||||
|
||||
#def isosurface(data, level):
|
||||
#"""
|
||||
#Generate isosurface from volumetric data using marching tetrahedra algorithm.
|
||||
|
@ -1269,7 +1269,15 @@ class ViewBox(GraphicsWidget):
|
||||
|
||||
for item in g.childItems():
|
||||
item.setPen(fn.mkPen(color='y', width=3))
|
||||
item.setZValue(1000000)
|
||||
g.setZValue(1000000)
|
||||
|
||||
if children:
|
||||
g.path = QtGui.QGraphicsPathItem(g.childrenShape())
|
||||
else:
|
||||
g.path = QtGui.QGraphicsPathItem(g.shape())
|
||||
g.path.setParentItem(g)
|
||||
g.path.setPen(fn.mkPen('g'))
|
||||
g.path.setZValue(100)
|
||||
|
||||
QtCore.QTimer.singleShot(timeout*1000, self.clearLocate)
|
||||
|
||||
|
@ -202,9 +202,9 @@ class GLViewWidget(QtOpenGL.QGLWidget):
|
||||
Pos may be a Vector or an (N,3) array of locations
|
||||
"""
|
||||
cam = self.cameraPosition()
|
||||
if isinstance(pos, np.ndarray) and pos.ndim == 2:
|
||||
cam = np.array(cam).reshape(1,3)
|
||||
dist = ((pos-cam)**2).sum(axis=1)**0.5
|
||||
if isinstance(pos, np.ndarray):
|
||||
cam = np.array(cam).reshape((1,)*(pos.ndim-1)+(3,))
|
||||
dist = ((pos-cam)**2).sum(axis=-1)**0.5
|
||||
else:
|
||||
dist = (pos-cam).length()
|
||||
xDist = dist * 2. * np.tan(0.5 * self.opts['fov'] * np.pi / 180.)
|
||||
|
@ -118,7 +118,10 @@ class GLScatterPlotItem(GLGraphicsItem):
|
||||
#glUniform1i(self.shader.uniform('texture'), 0) ## inform the shader which texture to use
|
||||
glEnableClientState(GL_VERTEX_ARRAY)
|
||||
try:
|
||||
glVertexPointerf(self.pos)
|
||||
pos = self.pos
|
||||
#if pos.ndim > 2:
|
||||
#pos = pos.reshape((reduce(lambda a,b: a*b, pos.shape[:-1]), pos.shape[-1]))
|
||||
glVertexPointerf(pos)
|
||||
|
||||
if isinstance(self.color, np.ndarray):
|
||||
glEnableClientState(GL_COLOR_ARRAY)
|
||||
@ -131,19 +134,19 @@ class GLScatterPlotItem(GLGraphicsItem):
|
||||
|
||||
if not self.pxMode or isinstance(self.size, np.ndarray):
|
||||
glEnableClientState(GL_NORMAL_ARRAY)
|
||||
norm = np.empty(self.pos.shape)
|
||||
norm = np.empty(pos.shape)
|
||||
if self.pxMode:
|
||||
norm[:,0] = self.size
|
||||
norm[...,0] = self.size
|
||||
else:
|
||||
gpos = self.mapToView(self.pos.transpose()).transpose()
|
||||
gpos = self.mapToView(pos.transpose()).transpose()
|
||||
pxSize = self.view().pixelSize(gpos)
|
||||
norm[:,0] = self.size / pxSize
|
||||
norm[...,0] = self.size / pxSize
|
||||
|
||||
glNormalPointerf(norm)
|
||||
else:
|
||||
glNormal3f(self.size, 0, 0) ## vertex shader uses norm.x to determine point size
|
||||
#glPointSize(self.size)
|
||||
glDrawArrays(GL_POINTS, 0, len(self.pos))
|
||||
glDrawArrays(GL_POINTS, 0, pos.size / pos.shape[-1])
|
||||
finally:
|
||||
glDisableClientState(GL_NORMAL_ARRAY)
|
||||
glDisableClientState(GL_VERTEX_ARRAY)
|
||||
|
Loading…
Reference in New Issue
Block a user