f6da6e2fd0
Updates to MeshData class (this is still not tested)
125 lines
4.4 KiB
Python
125 lines
4.4 KiB
Python
class MeshData(object):
|
|
"""
|
|
Class for storing 3D mesh data. May contain:
|
|
- list of vertex locations
|
|
- list of edges
|
|
- list of triangles
|
|
- colors per vertex, edge, or tri
|
|
- normals per vertex or tri
|
|
"""
|
|
|
|
def __init__(self):
|
|
self.vertexes = []
|
|
self.edges = None
|
|
self.faces = []
|
|
self.vertexFaces = None ## maps vertex ID to a list of face IDs
|
|
self.vertexNormals = None
|
|
self.faceNormals = None
|
|
self.vertexColors = None
|
|
self.edgeColors = None
|
|
self.faceColors = None
|
|
|
|
def setFaces(self, faces, vertexes=None):
|
|
"""
|
|
Set the faces in this data set.
|
|
Data may be provided either as an Nx3x3 list of floats (9 float coordinate values per face)
|
|
*faces* = [ [(x, y, z), (x, y, z), (x, y, z)], ... ]
|
|
or as an Nx3 list of ints (vertex integers) AND an Mx3 list of floats (3 float coordinate values per vertex)
|
|
*faces* = [ (p1, p2, p3), ... ]
|
|
*vertexes* = [ (x, y, z), ... ]
|
|
"""
|
|
|
|
if vertexes is None:
|
|
self._setUnindexedFaces(self, faces)
|
|
else:
|
|
self._setIndexedFaces(self, faces)
|
|
|
|
def _setUnindexedFaces(self, faces):
|
|
verts = {}
|
|
self.faces = []
|
|
self.vertexes = []
|
|
self.vertexFaces = []
|
|
self.faceNormals = None
|
|
self.vertexNormals = None
|
|
for face in faces:
|
|
inds = []
|
|
for pt in face:
|
|
pt2 = tuple([int(x*1e14) for x in pt]) ## quantize to be sure that nearly-identical points will be merged
|
|
index = verts.get(pt2, None)
|
|
if index is None:
|
|
self.vertexes.append(tuple(pt))
|
|
self.vertexFaces.append([])
|
|
index = len(self.vertexes)-1
|
|
verts[pt2] = index
|
|
self.vertexFaces[index].append(face)
|
|
inds.append(index)
|
|
self.faces.append(tuple(inds))
|
|
|
|
def _setIndexedFaces(self, faces, vertexes):
|
|
self.vertexes = vertexes
|
|
self.faces = faces
|
|
self.edges = None
|
|
self.vertexFaces = None
|
|
self.faceNormals = None
|
|
self.vertexNormals = None
|
|
|
|
def getVertexFaces(self):
|
|
"""
|
|
Return list mapping each vertex index to a list of face indexes that use the vertex.
|
|
"""
|
|
if self.vertexFaces is None:
|
|
self.vertexFaces = [[]] * len(self.vertexes)
|
|
for i, face in enumerate(self.faces):
|
|
for ind in face:
|
|
if len(self.vertexFaces[ind]) == 0:
|
|
self.vertexFaces[ind] = [] ## need a unique/empty list to fill
|
|
self.vertexFaces[ind].append(i)
|
|
return self.vertexFaces
|
|
|
|
|
|
def getFaceNormals(self):
|
|
"""
|
|
Computes and stores normal of each face.
|
|
"""
|
|
if self.faceNormals is None:
|
|
self.faceNormals = []
|
|
for i, face in enumerate(self.faces):
|
|
## compute face normal
|
|
pts = [QtGui.QVector3D(*self.vertexes[vind]) for vind in face]
|
|
norm = QtGui.QVector3D.crossProduct(pts[1]-pts[0], pts[2]-pts[0])
|
|
self.faceNormals.append(norm)
|
|
return self.faceNormals
|
|
|
|
def getVertexNormals(self):
|
|
"""
|
|
Assigns each vertex the average of its connected face normals.
|
|
If face normals have not been computed yet, then generateFaceNormals will be called.
|
|
"""
|
|
if self.vertexNormals is None:
|
|
faceNorms = self.getFaceNormals()
|
|
vertFaces = self.getVertexFaces()
|
|
self.vertexNormals = []
|
|
for vindex in xrange(len(self.vertexes)):
|
|
norms = [faceNorms[findex] for findex in vertFaces[vindex]]
|
|
if len(norms) == 0:
|
|
norm = QtGui.QVector3D()
|
|
else:
|
|
norm = reduce(QtGui.QVector3D.__add__, facenorms) / float(len(norms))
|
|
self.vertexNormals.append(norm)
|
|
return self.vertexNormals
|
|
|
|
|
|
def reverseNormals(self):
|
|
"""
|
|
Reverses the direction of all normal vectors.
|
|
"""
|
|
pass
|
|
|
|
def generateEdgesFromFaces(self):
|
|
"""
|
|
Generate a set of edges by listing all the edges of faces and removing any duplicates.
|
|
Useful for displaying wireframe meshes.
|
|
"""
|
|
pass
|
|
|