updated the surf.geometry module to better map to blender primatives

This commit is contained in:
Stephen M. McQuay 2012-05-07 23:21:31 -06:00
parent 7d06a7037b
commit 6c516e26fc
1 changed files with 121 additions and 147 deletions

View File

@ -18,38 +18,53 @@ We have chosen to use a winged-edge style mesh for our purpopses.
''' '''
def cross(a, b): def cross(a, b):
i = a.y * b.z - a.z * b.y i = a.y * b.z - a.z * b.y
j = a.z * b.x - a.x * b.z j = a.z * b.x - a.x * b.z
k = a.x * b.y - a.y * b.x k = a.x * b.y - a.y * b.x
return Vertex(i, j, k) return Vertex(i, j, k)
def _centroid(verts):
xs = [vertex.x for vertex in verts]
ys = [vertex.y for vertex in verts]
zs = [vertex.z for vertex in verts]
# average each vertex component
x = sum(xs) / len(xs)
y = sum(ys) / len(ys)
z = sum(zs) / len(zs)
return Vertex(x, y, z)
class Vertex(object): class Vertex(object):
''' '''
A vertex is a position along with other information such as color, normal A vertex is a position along with other information such as color, normal
vector and texture coordinates. vector and texture coordinates.
For the sake of our algorithms, we will only worry about the (x, y, z)
float positions. Eventually we will also keep track of weights.
''' '''
def __init__(self, x=0.0, y=0.0, z=0.0): def __init__(self, x=0.0, y=0.0, z=0.0):
'''
'''
self.x = x self.x = x
self.y = y self.y = y
self.z = z self.z = z
def __eq__(self, other): def __eq__(self, other):
if(self.x == other.x and self.y == other.y and self.z == other.z): if(self.x == other.x and self.y == other.y and self.z == other.z):
return True return True
else: else:
return False return False
def __add__(self, other): def __add__(self, other):
# for now just assume type(other) = Vertex... bad, I know # for now just assume type(other) = Vertex... bad, I know
return Vertex(self.x + other.x, self.y + other.y, self.z + other.z) return Vertex(self.x + other.x, self.y + other.y, self.z + other.z)
def __radd__(self, other): def __radd__(self, other):
return other + self return other + self
def __mul__(self, other): def __mul__(self, other):
if isinstance(other, Vertex): if isinstance(other, Vertex):
return cross(self, other) return cross(self, other)
@ -58,183 +73,142 @@ class Vertex(object):
else: else:
raise TypeError("{0} has an unexpected type: {1}".format( raise TypeError("{0} has an unexpected type: {1}".format(
other, type(other))) other, type(other)))
def __rmul__(self, other): def __rmul__(self, other):
return self.__mul__(other) return self.__mul__(other)
def __div__(self, other): def __div__(self, other):
# same assumption as __mult__ # same assumption as __mult__
return Vertex(self.x / other, self.y / other, self.z / other) return Vertex(self.x / other, self.y / other, self.z / other)
__truediv__ = __div__ __truediv__ = __div__
def __neg__(self): def __neg__(self):
return Vertex(-self.x, -self.y, -self.z) return Vertex(-self.x, -self.y, -self.z)
def __unicode__(self): def __unicode__(self):
d = { return pprint.pformat([self.x, self.y, self.z])
'id': self.id,
'parent_id': self.parent_id,
'coords': [self.x, self.y, self.z]
}
return pprint.pformat(d)
__str__ = __unicode__ __str__ = __unicode__
__repr__ = __unicode__ __repr__ = __unicode__
class Edge(object): class Edge(object):
''' def __init__(self, v1, v2):
''' self.v1 = v1
self.v2 = v2
next_id = 0
def __init__(self, polygon, parent_id=None, vs=None, es=None, fs=None): @property
''' def centroid(self):
''' return _centroid([self.v1, self.v2])
self.polygon = polygon
self.parent_id = parent_id
self.vertex_ids = vs or []
self.edge_ids = es or []
self.face_ids = fs or []
self.id = Edge.next_id
Edge.next_id += 1
def neighbor_face_id(self, neighbor_face_id):
'''Get neighboring face id
'''
if neighbor_face_id == self.face_ids[0]:
return self.face_ids[1]
else:
return self.face_ids[0]
def __unicode__(self): def __unicode__(self):
d = { return pprint.pformat((self.v1, self.v2))
'id': self.id,
'vertex_ids': self.vertex_ids,
'edge_ids': self.edge_ids,
'face_ids': self.face_ids,
}
return pprint.pformat(d)
__str__ = __unicode__ __str__ = __unicode__
__repr__ = __unicode__ __repr__ = __unicode__
@property
def vertices(self):
return [self.polygon.vertex(v_id) for v_id in self.vertex_ids]
@property
def faces(self):
return [self.polygon.face(f_id) for f_id in self.face_ids]
def winged_edges_at_vertex(self, index):
edge_ids = []
for edge in self.edges:
if self.vertex_ids[index] in edge.vertex_ids:
edge_ids.append(edge.id)
return edge_ids
class Face(object): class Face(object):
''' '''
A face is a closed set of edges, A face is a closed set of edges, in which a triangle face has three edges,
in which a triangle face has three edges, and a quad face has four edges. Blender stores a face as a collection of
and a quad face has four edges. the verts that compose it, so we shall store them thusly as well.
Blender historicaly only supported faces with an edge count of three or
four. We will cross the N-gon bridge in the future.
''' '''
next_id = 0 def __init__(self, verts=None):
def __init__(self, polygon, parent_id=None, es=None): self.verts = verts or []
'''
'''
self.polygon = polygon
self.parent_id = parent_id
self.edge_ids = es or []
self.id = Face.next_id
Face.next_id += 1
def __unicode__(self): def __unicode__(self):
d = {'id': self.id, 'edge_ids': self.edge_ids} return pprint.pformat(self.verts)
return pprint.pformat(d)
__str__ = __unicode__ __str__ = __unicode__
__repr__ = __unicode__ __repr__ = __unicode__
def edge(self, edge_id):
return self.polygon.edge(edge_id)
@property
def edges(self):
return [self.polygon.edge(e_id) for e_id in self.edge_ids]
@property
def vertices(self):
vertices = []
for edge_id in self.edge_ids:
edge = self.polygon.edge(edge_id)
vertices.extend(edge.vertices)
return list(set(vertices))
@property @property
def centroid(self): def centroid(self):
''' return _centroid(self.verts)
'''
# gather all face vertex coords
face_vertices = self.vertices
xs = [vertex.x for vertex in face_vertices]
ys = [vertex.y for vertex in face_vertices]
zs = [vertex.z for vertex in face_vertices]
# average each vertex component
x = sum(xs) / len(xs)
y = sum(ys) / len(ys)
z = sum(zs) / len(zs)
return [x, y, z]
class PolygonMesh(object):
class Polygon(object):
''' '''
''' A polygon object is a collection of the following lists:
def __init__(self, vs=None, es=None, fs=None): - a list containing the 3-space vertex information
self.vertices = vs or [] - a list containing the edge indices ([0, 1] means first and second
self.edges = es or [] elements of the vertices list)
self.faces = fs or [] - a list of the faces (indices of the vertices in a given face)
def face(self, face_id): - connectivity information (eventually will be calculated given the verts,
for face in self.faces: edges, and faces)
if face.id == face_id: '''
return face
return None def __init__(self, *args, **kwargs):
self.vertices = kwargs['vertices']
def edge(self, edge_id): self.edges = kwargs['edges']
for edge in self.edges: self.faces = kwargs['faces']
if edge.id == edge_id:
return edge # the strategy for the following members involves lazy-instantiating
return None # them if they weren't passing them in:
self._faces_for_edge = kwargs.get('faces for edge', None)
def vertex(self, vertex_id): self._edges_for_face = kwargs.get('edges for face', None)
for vertex in self.vertices: self._edges_for_vert = kwargs.get('edges for vert', None)
if vertex.id == vertex_id: self._faces_for_vert = kwargs.get('faces for vert', None)
return vertex
return None @property
def faces_for_edge(self):
"""returns a list of face indices for a given edge index.
Intended to be used in the following way:
>>> # vs, es, fs, ffe, eff, efv, ffv from blender or similar
>>> mesh = Polygon(vs, es, fs, ffe, eff, efv, ffv)
>>> mesh.faces_for_edge[0]
[0, 1]
>>> [self.face[i] for i in mesh.faces_for_edge[1]]
[<Face 0>, <Face 1>]
where 0 and 1 are indices into the face list
"""
if self._faces_for_edge is None:
# TODO: eventually support generating this ourselves ...
raise AttributeError("Not yet implemented if you don't explicitly pass this in")
return self._faces_for_edge
@property
def edges_for_face(self):
"""returns a list of edge indices for a given face index."""
if self._edges_for_face is None:
# TODO: eventually support generating this ourselves ...
raise AttributeError("Not yet implemented if you don't explicitly pass this in")
return self._edges_for_face
@property
def edges_for_vert(self):
"""returns a list of edge indices for a given vertex index."""
if self._edges_for_vert is None:
# TODO: eventually support generating this ourselves ...
raise AttributeError("Not yet implemented if you don't explicitly pass this in")
return self._edges_for_vert
@property
def faces_for_vert(self):
"""returns a list of face indices for a given vert index."""
if self._faces_for_vert is None:
# TODO: eventually support generating this ourselves ...
raise AttributeError("Not yet implemented if you don't explicitly pass this in")
return self._faces_for_vert
def edge_ids_with_parent(self, parent_edge_id):
child_edge_ids = []
for edge in self.edges:
if edge.parent_id == parent_edge_id:
child_edge_ids.append(edge.id)
return child_edge_ids
def __unicode__(self): def __unicode__(self):
# TODO: perhaps also add connectivity here?
d = { d = {
'vertices': self.vertices, 'vertices': self.vertices,
'edges': self.edges, 'edges': self.edges,
'faces': self.faces, 'faces': self.faces,
} }
return pprint.pformat(d) return pprint.pformat(d)
__str__ = __unicode__ __str__ = __unicode__
__repr__ = __unicode__ __repr__ = __unicode__