Allow GLMeshItem to draw edges from MeshData with face-indexed vertexes.
This commit is contained in:
parent
c8f03e828e
commit
00418e4921
@ -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
|
||||
|
||||
|
@ -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)
|
||||
|
||||
|
||||
@ -114,45 +119,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)
|
||||
|
||||
|
||||
|
||||
|
@ -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):
|
||||
@ -161,8 +108,6 @@ class MeshData(object):
|
||||
self.resetNormals()
|
||||
self._vertexColorsIndexedByFaces = None
|
||||
self._faceColorsIndexedByFaces = None
|
||||
|
||||
|
||||
|
||||
def vertexes(self, indexed=None):
|
||||
"""Return an array (N,3) of the positions of vertexes in the mesh.
|
||||
@ -207,7 +152,6 @@ class MeshData(object):
|
||||
self._vertexNormalsIndexedByFaces = None
|
||||
self._faceNormals = None
|
||||
self._faceNormalsIndexedByFaces = None
|
||||
|
||||
|
||||
def hasFaceIndexedData(self):
|
||||
"""Return True if this object already has vertex positions indexed by face"""
|
||||
@ -229,7 +173,6 @@ class MeshData(object):
|
||||
if v is not None:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def faceNormals(self, indexed=None):
|
||||
"""
|
||||
@ -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,22 +369,35 @@ class MeshData(object):
|
||||
#pass
|
||||
|
||||
def _computeEdges(self):
|
||||
## 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]
|
||||
edges['i'][nf:2*nf] = self._faces[:,1:3]
|
||||
edges['i'][-nf:,0] = self._faces[:,2]
|
||||
edges['i'][-nf:,1] = self._faces[:,0]
|
||||
|
||||
# sort per-edge
|
||||
mask = edges['i'][:,0] > edges['i'][:,1]
|
||||
edges['i'][mask] = edges['i'][mask][:,::-1]
|
||||
|
||||
# remove duplicate entries
|
||||
self._edges = np.unique(edges)['i']
|
||||
#print self._edges
|
||||
if not self.hasFaceIndexedData:
|
||||
## generate self._edges from self._faces
|
||||
nf = len(self._faces)
|
||||
edges = np.empty(nf*3, dtype=[('i', np.uint, 2)])
|
||||
edges['i'][0:nf] = self._faces[:,:2]
|
||||
edges['i'][nf:2*nf] = self._faces[:,1:3]
|
||||
edges['i'][-nf:,0] = self._faces[:,2]
|
||||
edges['i'][-nf:,1] = self._faces[:,0]
|
||||
|
||||
# sort per-edge
|
||||
mask = edges['i'][:,0] > edges['i'][:,1]
|
||||
edges['i'][mask] = edges['i'][mask][:,::-1]
|
||||
|
||||
# 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):
|
||||
|
@ -153,8 +153,12 @@ class GLMeshItem(GLGraphicsItem):
|
||||
self.colors = md.faceColors(indexed='faces')
|
||||
|
||||
if self.opts['drawEdges']:
|
||||
self.edges = md.edges()
|
||||
self.edgeVerts = md.vertexes()
|
||||
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):
|
||||
|
Loading…
Reference in New Issue
Block a user