merge with inp

This commit is contained in:
Guillaume Poulin 2013-07-05 00:09:30 +08:00
commit a290a39779
2 changed files with 122 additions and 92 deletions

View File

@ -1078,14 +1078,29 @@ def arrayToQPath(x, y, connect='all'):
should be connected, or an array of int32 values (0 or 1) indicating should be connected, or an array of int32 values (0 or 1) indicating
connections. connections.
""" """
## Create all vertices in path. The method used below creates a binary format so that all ## Create all vertices in path. The method used below creates a binary format so that all
## vertices can be read in at once. This binary format may change in future versions of Qt, ## vertices can be read in at once. This binary format may change in future versions of Qt,
## so the original (slower) method is left here for emergencies: ## so the original (slower) method is left here for emergencies:
#path.moveTo(x[0], y[0]) #path.moveTo(x[0], y[0])
#for i in range(1, y.shape[0]): #if connect == 'all':
# path.lineTo(x[i], y[i]) #for i in range(1, y.shape[0]):
#path.lineTo(x[i], y[i])
#elif connect == 'pairs':
#for i in range(1, y.shape[0]):
#if i%2 == 0:
#path.lineTo(x[i], y[i])
#else:
#path.moveTo(x[i], y[i])
#elif isinstance(connect, np.ndarray):
#for i in range(1, y.shape[0]):
#if connect[i] == 1:
#path.lineTo(x[i], y[i])
#else:
#path.moveTo(x[i], y[i])
#else:
#raise Exception('connect argument must be "all", "pairs", or array')
## Speed this up using >> operator ## Speed this up using >> operator
## Format is: ## Format is:
## numVerts(i4) 0(i4) ## numVerts(i4) 0(i4)
@ -1095,76 +1110,60 @@ def arrayToQPath(x, y, connect='all'):
## 0(i4) ## 0(i4)
## ##
## All values are big endian--pack using struct.pack('>d') or struct.pack('>i') ## All values are big endian--pack using struct.pack('>d') or struct.pack('>i')
path = QtGui.QPainterPath() path = QtGui.QPainterPath()
#prof = debug.Profiler('PlotCurveItem.generatePath', disabled=True) #prof = debug.Profiler('PlotCurveItem.generatePath', disabled=True)
if sys.version_info[0] == 2: ## So this is disabled for python 3... why?? n = x.shape[0]
n = x.shape[0] # create empty array, pad with extra space on either end
# create empty array, pad with extra space on either end arr = np.empty(n+2, dtype=[('x', '>f8'), ('y', '>f8'), ('c', '>i4')])
arr = np.empty(n+2, dtype=[('x', '>f8'), ('y', '>f8'), ('c', '>i4')]) # write first two integers
# write first two integers #prof.mark('allocate empty')
#prof.mark('allocate empty') byteview = arr.view(dtype=np.ubyte)
arr.data[12:20] = struct.pack('>ii', n, 0) byteview[:12] = 0
#prof.mark('pack header') byteview.data[12:20] = struct.pack('>ii', n, 0)
# Fill array with vertex values #prof.mark('pack header')
arr[1:-1]['x'] = x # Fill array with vertex values
arr[1:-1]['y'] = y arr[1:-1]['x'] = x
arr[1:-1]['y'] = y
# decide which points are connected by lines
if connect == 'pairs': # decide which points are connected by lines
connect = np.empty((n/2,2), dtype=np.int32) if connect == 'pairs':
connect[:,0] = 1 connect = np.empty((n/2,2), dtype=np.int32)
connect[:,1] = 0 connect[:,0] = 1
connect = connect.flatten() connect[:,1] = 0
connect = connect.flatten()
if connect == 'all':
arr[1:-1]['c'] = 1 if connect == 'all':
elif isinstance(connect, np.ndarray): arr[1:-1]['c'] = 1
arr[1:-1]['c'] = connect elif isinstance(connect, np.ndarray):
else: arr[1:-1]['c'] = connect
raise Exception('connect argument must be "all", "pairs", or array')
#prof.mark('fill array')
# write last 0
lastInd = 20*(n+1)
arr.data[lastInd:lastInd+4] = struct.pack('>i', 0)
#prof.mark('footer')
# create datastream object and stream into path
## Avoiding this method because QByteArray(str) leaks memory in PySide
#buf = QtCore.QByteArray(arr.data[12:lastInd+4]) # I think one unnecessary copy happens here
path.strn = arr.data[12:lastInd+4] # make sure data doesn't run away
buf = QtCore.QByteArray.fromRawData(path.strn)
#prof.mark('create buffer')
ds = QtCore.QDataStream(buf)
ds >> path
#prof.mark('load')
#prof.finish()
else: else:
## This does exactly the same as above, but less efficiently (and more simply). raise Exception('connect argument must be "all", "pairs", or array')
path.moveTo(x[0], y[0])
if connect == 'all': #prof.mark('fill array')
for i in range(1, y.shape[0]): # write last 0
path.lineTo(x[i], y[i]) lastInd = 20*(n+1)
elif connect == 'pairs': byteview.data[lastInd:lastInd+4] = struct.pack('>i', 0)
for i in range(1, y.shape[0]): #prof.mark('footer')
if i%2 == 0: # create datastream object and stream into path
path.lineTo(x[i], y[i])
else: ## Avoiding this method because QByteArray(str) leaks memory in PySide
path.moveTo(x[i], y[i]) #buf = QtCore.QByteArray(arr.data[12:lastInd+4]) # I think one unnecessary copy happens here
elif isinstance(connect, np.ndarray):
for i in range(1, y.shape[0]): path.strn = byteview.data[12:lastInd+4] # make sure data doesn't run away
if connect[i] == 1: try:
path.lineTo(x[i], y[i]) buf = QtCore.QByteArray.fromRawData(path.strn)
else: except TypeError:
path.moveTo(x[i], y[i]) buf = QtCore.QByteArray(bytes(path.strn))
else: #prof.mark('create buffer')
raise Exception('connect argument must be "all", "pairs", or array') ds = QtCore.QDataStream(buf)
ds >> path
#prof.mark('load')
#prof.finish()
return path return path
#def isosurface(data, level): #def isosurface(data, level):

View File

@ -80,23 +80,26 @@ class GLViewWidget(QtOpenGL.QGLWidget):
#self.update() #self.update()
def setProjection(self, region=None): def setProjection(self, region=None):
m = self.projectionMatrix(region)
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
a = np.array(m.copyDataTo()).reshape((4,4))
glMultMatrixf(a.transpose())
def projectionMatrix(self, region=None):
# Xw = (Xnd + 1) * width/2 + X # Xw = (Xnd + 1) * width/2 + X
if region is None: if region is None:
region = (0, 0, self.width(), self.height()) region = (0, 0, self.width(), self.height())
## Create the projection matrix
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
#w = self.width()
#h = self.height()
x0, y0, w, h = self.getViewport() x0, y0, w, h = self.getViewport()
dist = self.opts['distance'] dist = self.opts['distance']
fov = self.opts['fov'] fov = self.opts['fov']
nearClip = dist * 0.001 nearClip = dist * 0.001
farClip = dist * 1000. farClip = dist * 1000.
r = nearClip * np.tan(fov * 0.5 * np.pi / 180.) r = nearClip * np.tan(fov * 0.5 * np.pi / 180.)
t = r * h / w t = r * h / w
# convert screen coordinates (region) to normalized device coordinates # convert screen coordinates (region) to normalized device coordinates
# Xnd = (Xw - X0) * 2/width - 1 # Xnd = (Xw - X0) * 2/width - 1
## Note that X0 and width in these equations must be the values used in viewport ## Note that X0 and width in these equations must be the values used in viewport
@ -104,21 +107,46 @@ class GLViewWidget(QtOpenGL.QGLWidget):
right = r * ((region[0]+region[2]-x0) * (2.0/w) - 1) right = r * ((region[0]+region[2]-x0) * (2.0/w) - 1)
bottom = t * ((region[1]-y0) * (2.0/h) - 1) bottom = t * ((region[1]-y0) * (2.0/h) - 1)
top = t * ((region[1]+region[3]-y0) * (2.0/h) - 1) top = t * ((region[1]+region[3]-y0) * (2.0/h) - 1)
glFrustum( left, right, bottom, top, nearClip, farClip) tr = QtGui.QMatrix4x4()
#glFrustum(-r, r, -t, t, nearClip, farClip) tr.frustum(left, right, bottom, top, nearClip, farClip)
return tr
def setModelview(self): def setModelview(self):
glMatrixMode(GL_MODELVIEW) glMatrixMode(GL_MODELVIEW)
glLoadIdentity() glLoadIdentity()
glTranslatef( 0.0, 0.0, -self.opts['distance']) m = self.viewMatrix()
glRotatef(self.opts['elevation']-90, 1, 0, 0) a = np.array(m.copyDataTo()).reshape((4,4))
glRotatef(self.opts['azimuth']+90, 0, 0, -1) glMultMatrixf(a.transpose())
def viewMatrix(self):
tr = QtGui.QMatrix4x4()
tr.translate( 0.0, 0.0, -self.opts['distance'])
tr.rotate(self.opts['elevation']-90, 1, 0, 0)
tr.rotate(self.opts['azimuth']+90, 0, 0, -1)
center = self.opts['center'] center = self.opts['center']
glTranslatef(-center.x(), -center.y(), -center.z()) tr.translate(-center.x(), -center.y(), -center.z())
return tr
def itemsAt(self, region=None):
#buf = np.zeros(100000, dtype=np.uint)
buf = glSelectBuffer(100000)
try:
glRenderMode(GL_SELECT)
glInitNames()
glPushName(0)
self._itemNames = {}
self.paintGL(region=region, useItemNames=True)
finally:
hits = glRenderMode(GL_RENDER)
items = [(h.near, h.names[0]) for h in hits]
items.sort(key=lambda i: i[0])
return [self._itemNames[i[1]] for i in items]
def paintGL(self, region=None, viewport=None): def paintGL(self, region=None, viewport=None, useItemNames=False):
""" """
viewport specifies the arguments to glViewport. If None, then we use self.opts['viewport'] viewport specifies the arguments to glViewport. If None, then we use self.opts['viewport']
region specifies the sub-region of self.opts['viewport'] that should be rendered. region specifies the sub-region of self.opts['viewport'] that should be rendered.
@ -131,9 +159,9 @@ class GLViewWidget(QtOpenGL.QGLWidget):
self.setProjection(region=region) self.setProjection(region=region)
self.setModelview() self.setModelview()
glClear( GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT ) glClear( GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT )
self.drawItemTree() self.drawItemTree(useItemNames=useItemNames)
def drawItemTree(self, item=None): def drawItemTree(self, item=None, useItemNames=False):
if item is None: if item is None:
items = [x for x in self.items if x.parentItem() is None] items = [x for x in self.items if x.parentItem() is None]
else: else:
@ -146,6 +174,9 @@ class GLViewWidget(QtOpenGL.QGLWidget):
if i is item: if i is item:
try: try:
glPushAttrib(GL_ALL_ATTRIB_BITS) glPushAttrib(GL_ALL_ATTRIB_BITS)
if useItemNames:
glLoadName(id(i))
self._itemNames[id(i)] = i
i.paint() i.paint()
except: except:
import pyqtgraph.debug import pyqtgraph.debug
@ -168,7 +199,7 @@ class GLViewWidget(QtOpenGL.QGLWidget):
tr = i.transform() tr = i.transform()
a = np.array(tr.copyDataTo()).reshape((4,4)) a = np.array(tr.copyDataTo()).reshape((4,4))
glMultMatrixf(a.transpose()) glMultMatrixf(a.transpose())
self.drawItemTree(i) self.drawItemTree(i, useItemNames=useItemNames)
finally: finally:
glMatrixMode(GL_MODELVIEW) glMatrixMode(GL_MODELVIEW)
glPopMatrix() glPopMatrix()