Allow GLMeshItem to draw edges from MeshData with face-indexed vertexes.

This commit is contained in:
Luke Campagnola 2014-03-10 23:04:10 -04:00
parent c8f03e828e
commit 00418e4921
4 changed files with 51 additions and 125 deletions

View File

@ -67,6 +67,7 @@ pyqtgraph-0.9.9 [unreleased]
- Fixed PySide crash caused by emitting signal from GraphicsObject.itemChange
- Fixed possible infinite loop from FiniteCache
- Allow images with NaN in ImageView
- MeshData can generate edges from face-indexed vertexes
pyqtgraph-0.9.8 2013-11-24

View File

@ -53,19 +53,24 @@ m1.translate(5, 5, 0)
m1.setGLOptions('additive')
w.addItem(m1)
## Example 2:
## Array of vertex positions, three per face
verts = np.empty((36, 3, 3), dtype=np.float32)
theta = np.linspace(0, 2*np.pi, 37)[:-1]
verts[:,0] = np.vstack([2*np.cos(theta), 2*np.sin(theta), [0]*36]).T
verts[:,1] = np.vstack([4*np.cos(theta+0.2), 4*np.sin(theta+0.2), [-1]*36]).T
verts[:,2] = np.vstack([4*np.cos(theta-0.2), 4*np.sin(theta-0.2), [1]*36]).T
## Colors are specified per-vertex
verts = verts[faces] ## Same mesh geometry as example 2, but now we are passing in 12 vertexes
colors = np.random.random(size=(verts.shape[0], 3, 4))
#colors[...,3] = 1.0
m2 = gl.GLMeshItem(vertexes=verts, vertexColors=colors, smooth=False, shader='balloon')
m2 = gl.GLMeshItem(vertexes=verts, vertexColors=colors, smooth=False, shader='balloon',
drawEdges=True, edgeColor=(1, 1, 0, 1))
m2.translate(-5, 5, 0)
w.addItem(m2)
## Example 3:
## sphere
@ -79,7 +84,7 @@ colors[:,1] = np.linspace(0, 1, colors.shape[0])
md.setFaceColors(colors)
m3 = gl.GLMeshItem(meshdata=md, smooth=False)#, shader='balloon')
m3.translate(-5, -5, 0)
m3.translate(5, -5, 0)
w.addItem(m3)
@ -115,45 +120,6 @@ w.addItem(m6)
def psi(i, j, k, offset=(25, 25, 50)):
x = i-offset[0]
y = j-offset[1]
z = k-offset[2]
th = np.arctan2(z, (x**2+y**2)**0.5)
phi = np.arctan2(y, x)
r = (x**2 + y**2 + z **2)**0.5
a0 = 1
#ps = (1./81.) * (2./np.pi)**0.5 * (1./a0)**(3/2) * (6 - r/a0) * (r/a0) * np.exp(-r/(3*a0)) * np.cos(th)
ps = (1./81.) * 1./(6.*np.pi)**0.5 * (1./a0)**(3/2) * (r/a0)**2 * np.exp(-r/(3*a0)) * (3 * np.cos(th)**2 - 1)
return ps
#return ((1./81.) * (1./np.pi)**0.5 * (1./a0)**(3/2) * (r/a0)**2 * (r/a0) * np.exp(-r/(3*a0)) * np.sin(th) * np.cos(th) * np.exp(2 * 1j * phi))**2
print("Generating scalar field..")
data = np.abs(np.fromfunction(psi, (50,50,100)))
#data = np.fromfunction(lambda i,j,k: np.sin(0.2*((i-25)**2+(j-15)**2+k**2)**0.5), (50,50,50));
# print("Generating isosurface..")
# verts = pg.isosurface(data, data.max()/4.)
# print dir(gl.MeshData)
# md = gl.GLMeshItem(vertexes=verts)
#
# colors = np.ones((md.vertexes(indexed='faces').shape[0], 4), dtype=float)
# colors[:,3] = 0.3
# colors[:,2] = np.linspace(0, 1, colors.shape[0])
# m1 = gl.GLMeshItem(meshdata=md, color=colors, smooth=False)
#
# w.addItem(m1)
# m1.translate(-25, -25, -20)
#
# m2 = gl.GLMeshItem(vertexes=verts, color=colors, smooth=True)
#
# w.addItem(m2)
# m2.translate(-25, -25, -50)
## Start Qt event loop unless running in interactive mode.

View File

@ -84,64 +84,11 @@ class MeshData(object):
if faceColors is not None:
self.setFaceColors(faceColors)
#self.setFaces(vertexes=vertexes, faces=faces, vertexColors=vertexColors, faceColors=faceColors)
#def setFaces(self, vertexes=None, faces=None, vertexColors=None, faceColors=None):
#"""
#Set the faces in this data set.
#Data may be provided either as an Nx3x3 array of floats (9 float coordinate values per face)::
#faces = [ [(x, y, z), (x, y, z), (x, y, z)], ... ]
#or as an Nx3 array of ints (vertex integers) AND an Mx3 array of floats (3 float coordinate values per vertex)::
#faces = [ (p1, p2, p3), ... ]
#vertexes = [ (x, y, z), ... ]
#"""
#if not isinstance(vertexes, np.ndarray):
#vertexes = np.array(vertexes)
#if vertexes.dtype != np.float:
#vertexes = vertexes.astype(float)
#if faces is None:
#self._setIndexedFaces(vertexes, vertexColors, faceColors)
#else:
#self._setUnindexedFaces(faces, vertexes, vertexColors, faceColors)
##print self.vertexes().shape
##print self.faces().shape
#def setMeshColor(self, color):
#"""Set the color of the entire mesh. This removes any per-face or per-vertex colors."""
#color = fn.Color(color)
#self._meshColor = color.glColor()
#self._vertexColors = None
#self._faceColors = None
#def __iter__(self):
#"""Iterate over all faces, yielding a list of three tuples [(position, normal, color), ...] for each face."""
#vnorms = self.vertexNormals()
#vcolors = self.vertexColors()
#for i in range(self._faces.shape[0]):
#face = []
#for j in [0,1,2]:
#vind = self._faces[i,j]
#pos = self._vertexes[vind]
#norm = vnorms[vind]
#if vcolors is None:
#color = self._meshColor
#else:
#color = vcolors[vind]
#face.append((pos, norm, color))
#yield face
#def __len__(self):
#return len(self._faces)
def faces(self):
"""Return an array (Nf, 3) of vertex indexes, three per triangular face in the mesh."""
"""Return an array (Nf, 3) of vertex indexes, three per triangular face in the mesh.
If faces have not been computed for this mesh, the function returns None.
"""
return self._faces
def edges(self):
@ -162,8 +109,6 @@ class MeshData(object):
self._vertexColorsIndexedByFaces = None
self._faceColorsIndexedByFaces = None
def vertexes(self, indexed=None):
"""Return an array (N,3) of the positions of vertexes in the mesh.
By default, each unique vertex appears only once in the array.
@ -208,7 +153,6 @@ class MeshData(object):
self._faceNormals = None
self._faceNormalsIndexedByFaces = None
def hasFaceIndexedData(self):
"""Return True if this object already has vertex positions indexed by face"""
return self._vertexesIndexedByFaces is not None
@ -230,7 +174,6 @@ class MeshData(object):
return True
return False
def faceNormals(self, indexed=None):
"""
Return an array (Nf, 3) of normal vectors for each face.
@ -366,7 +309,6 @@ class MeshData(object):
## This is done by collapsing into a list of 'unique' vertexes (difference < 1e-14)
## I think generally this should be discouraged..
faces = self._vertexesIndexedByFaces
verts = {} ## used to remember the index of each vertex position
self._faces = np.empty(faces.shape[:2], dtype=np.uint)
@ -427,8 +369,8 @@ class MeshData(object):
#pass
def _computeEdges(self):
if not self.hasFaceIndexedData:
## generate self._edges from self._faces
#print self._faces
nf = len(self._faces)
edges = np.empty(nf*3, dtype=[('i', np.uint, 2)])
edges['i'][0:nf] = self._faces[:,:2]
@ -443,6 +385,19 @@ class MeshData(object):
# remove duplicate entries
self._edges = np.unique(edges)['i']
#print self._edges
elif self._vertexesIndexedByFaces is not None:
verts = self._vertexesIndexedByFaces
edges = np.empty((verts.shape[0], 3, 2), dtype=np.uint)
nf = verts.shape[0]
edges[:,0,0] = np.arange(nf) * 3
edges[:,0,1] = edges[:,0,0] + 1
edges[:,1,0] = edges[:,0,1]
edges[:,1,1] = edges[:,1,0] + 1
edges[:,2,0] = edges[:,1,1]
edges[:,2,1] = edges[:,0,0]
self._edges = edges
else:
raise Exception("MeshData cannot generate edges--no faces in this data.")
def save(self):

View File

@ -153,8 +153,12 @@ class GLMeshItem(GLGraphicsItem):
self.colors = md.faceColors(indexed='faces')
if self.opts['drawEdges']:
if not md.hasFaceIndexedData():
self.edges = md.edges()
self.edgeVerts = md.vertexes()
else:
self.edges = md.edges()
self.edgeVerts = md.vertexes(indexed='faces')
return
def paint(self):