2012-03-19 19:38:40 -07:00
|
|
|
import pprint
|
|
|
|
|
|
|
|
'''
|
|
|
|
http://en.wikipedia.org/wiki/Polygon_mesh
|
|
|
|
|
2012-03-19 21:56:12 -07:00
|
|
|
Polygon meshes may be represented in a variety of ways, using different methods
|
|
|
|
to store the vertex, edge and face data. These include:
|
|
|
|
- Face-vertex
|
|
|
|
- Winged-edge
|
|
|
|
- Half-edge
|
|
|
|
- Quad-edge
|
|
|
|
- Corner-tables
|
|
|
|
- Vertex-vertex
|
|
|
|
- Face-vertex
|
|
|
|
|
|
|
|
We have chosen to use a winged-edge style mesh for our purpopses.
|
|
|
|
|
2012-03-19 19:38:40 -07:00
|
|
|
v4 v5
|
|
|
|
*-----e8-----*
|
|
|
|
| |
|
|
|
|
| |
|
|
|
|
e|4 f4 e|5
|
|
|
|
| |
|
|
|
|
v4 v|0 v|1 v5
|
|
|
|
*-----e4-----*-----e0-----*-----e5-----*
|
|
|
|
| | | |
|
|
|
|
| | | |
|
|
|
|
e11| f3 e|3 f0 e|1 f1 e|9
|
|
|
|
| | | |
|
|
|
|
| | | |
|
|
|
|
*-----e7-----*-----e2-----*-----e6-----*
|
|
|
|
v7 v|3 v|2 v6
|
|
|
|
| |
|
|
|
|
e|7 f2 e|6
|
|
|
|
| |
|
|
|
|
v|7 v|6
|
|
|
|
*-----e10----*
|
|
|
|
| |
|
|
|
|
| |
|
|
|
|
e|11 f5 e|9
|
|
|
|
| |
|
|
|
|
| |
|
|
|
|
*-----e8-----*
|
|
|
|
v4 v5
|
|
|
|
v0 - <0,1,0>
|
|
|
|
v1 - <1,1,0>
|
|
|
|
v2 - <1,0,0>
|
|
|
|
v3 - <0,0,0>
|
|
|
|
v4 - <0,1,1>
|
|
|
|
v5 - <1,1,1>
|
|
|
|
v6 - <1,0,1>
|
|
|
|
v7 - <0,0,1>
|
2012-03-19 21:56:12 -07:00
|
|
|
|
2012-03-19 19:38:40 -07:00
|
|
|
face list
|
|
|
|
f0 - e0, e1, e2, e3
|
|
|
|
f1 - e1, e5, e9, e6
|
|
|
|
f2 - e2, e6, e10, e7
|
|
|
|
f3 - e4, e3, e7, e11
|
|
|
|
f4 - e8, e5, e0, e4
|
|
|
|
f5 - e10, e9, e8, e11
|
2012-03-19 21:56:12 -07:00
|
|
|
|
2012-03-19 19:38:40 -07:00
|
|
|
winged edges ordered by face, then by vertex reference
|
|
|
|
edge list
|
|
|
|
e0 - v0, v1; f0, f4; e3, e1, e4, e5
|
|
|
|
e1 - v1, v2; f0, f1; e0, e2, e5, e6
|
|
|
|
e2 - v3, v2; f0, f2; e3, e7, e1, e6
|
|
|
|
e3 - v0, v3; f3, f0; e4, e7, e0, e2
|
|
|
|
e4 - v4, v0; f3, f4; e11, e3, e0 e8
|
|
|
|
e5 - v5, v1; f4, f1; e8, e0, e9, e1
|
|
|
|
e6 - v2, v6; f1, f2; e1, e9, e2, e10
|
|
|
|
e7 - v7, v3; f3, f2; e11, e3, e10, e2
|
|
|
|
e8 - v4, v5, f4, f5; e4, e5, e11, e9
|
|
|
|
e9 - v5, v6; f1, f5; e5, e6, e8, e10
|
|
|
|
e10 - v7, v6; f2, f5; e7, e6, e11, e9
|
|
|
|
e11 - v4, v7; f3, f5; e4, e7, e8, 10
|
2012-03-19 21:56:12 -07:00
|
|
|
|
2012-03-19 19:38:40 -07:00
|
|
|
vertex list
|
|
|
|
v0 - e0, e3, e4
|
|
|
|
v1 - e0, e5, e1
|
|
|
|
v2 - e1, e6, e2
|
|
|
|
v3 - e2, e7, e3
|
|
|
|
v4 - e4, e11, e8
|
|
|
|
v5 - e5, e9, e8
|
|
|
|
v6 - e2, e9, e10
|
|
|
|
v7 - e7, e10, e11
|
2012-03-19 21:56:12 -07:00
|
|
|
|
2012-03-19 19:38:40 -07:00
|
|
|
'''
|
|
|
|
|
2012-03-19 21:56:12 -07:00
|
|
|
|
2012-03-19 19:38:40 -07:00
|
|
|
class Vertex(object):
|
|
|
|
'''
|
2012-03-19 21:56:12 -07:00
|
|
|
A vertex is a position along with other information such as color, normal
|
|
|
|
vector and texture coordinates.
|
2012-03-19 19:38:40 -07:00
|
|
|
'''
|
|
|
|
def __init__(self, x=0, y=0, z=0):
|
|
|
|
self.x = x
|
|
|
|
self.y = y
|
|
|
|
self.z = z
|
|
|
|
self.edges = []
|
2012-03-19 21:18:02 -07:00
|
|
|
|
|
|
|
def __eq__(self, other):
|
|
|
|
if(self.x == other.x and self.y == other.y and self.z == other.z):
|
|
|
|
return True
|
|
|
|
else:
|
|
|
|
return False
|
|
|
|
|
2012-03-19 19:38:40 -07:00
|
|
|
def __repr__(self):
|
2012-03-19 21:18:02 -07:00
|
|
|
return "[%.2f, %.2f, %.2f]" % (self.x, self.y, self.z)
|
2012-03-19 21:56:12 -07:00
|
|
|
|
2012-03-19 19:38:40 -07:00
|
|
|
def __add__(self, other):
|
|
|
|
# for now just assume type(other) = Vertex... bad, I know
|
2012-03-19 21:56:12 -07:00
|
|
|
return Vertex(self.x + other.x, self.y + other.y, self.z + other.z)
|
|
|
|
|
2012-03-19 19:38:40 -07:00
|
|
|
def __radd__(self, other):
|
|
|
|
return self.__add__(other)
|
2012-03-19 21:56:12 -07:00
|
|
|
|
|
|
|
def __mul__(self, other):
|
2012-03-19 19:38:40 -07:00
|
|
|
# for now just assume type(other) = int or float
|
|
|
|
return Vertex(self.x * other, self.y * other, self.z * other)
|
2012-03-19 21:56:12 -07:00
|
|
|
|
2012-03-19 19:38:40 -07:00
|
|
|
def __rmul__(self, other):
|
|
|
|
return self.__mul__(other)
|
2012-03-19 21:56:12 -07:00
|
|
|
|
2012-03-19 19:38:40 -07:00
|
|
|
def __div__(self, other):
|
|
|
|
# same assumption as __mult__
|
2012-03-19 21:18:02 -07:00
|
|
|
other = float(other)
|
2012-03-19 19:38:40 -07:00
|
|
|
return Vertex(self.x / other, self.y / other, self.z / other)
|
2012-03-19 21:56:12 -07:00
|
|
|
|
|
|
|
|
2012-03-19 19:38:40 -07:00
|
|
|
class Edge(object):
|
|
|
|
'''
|
|
|
|
'''
|
|
|
|
def __init__(self):
|
|
|
|
self.vertices = []
|
|
|
|
self.faces = []
|
|
|
|
self.edges = []
|
2012-03-19 21:56:12 -07:00
|
|
|
self.__edge_vertex = None
|
|
|
|
self.__sub_edges = []
|
|
|
|
|
2012-03-19 19:38:40 -07:00
|
|
|
def neighborFace(self, neighborFace):
|
|
|
|
if neighborFace == self.faces[0]:
|
|
|
|
return self.faces[1]
|
|
|
|
else:
|
|
|
|
return self.faces[0]
|
2012-03-19 21:56:12 -07:00
|
|
|
|
|
|
|
@property
|
|
|
|
def mid_point(self):
|
|
|
|
return sum(self.vertices, Vertex()) / len(self.vertices)
|
|
|
|
|
|
|
|
@property
|
|
|
|
def sub_edges(self):
|
|
|
|
if not self.__sub_edges:
|
|
|
|
self.__sub_edges = [Edge(), Edge()]
|
|
|
|
self.__sub_edges[0].vertices = [self.vertices[0], self.edge_vertex]
|
|
|
|
self.__sub_edges[1].vertices = [self.edge_vertex, self.vertices[1]]
|
|
|
|
return self.__sub_edges
|
|
|
|
|
|
|
|
@property
|
|
|
|
def edge_vertex(self):
|
2012-03-19 19:38:40 -07:00
|
|
|
'''
|
|
|
|
Set each edge vertices to be the average of the two neighboring
|
|
|
|
face vertices and its two original end vertices.
|
|
|
|
'''
|
2012-03-19 21:56:12 -07:00
|
|
|
if not self.__edge_vertex:
|
2012-03-19 19:38:40 -07:00
|
|
|
# two neighboring face vertices:
|
|
|
|
neighboringFaceVertices = [face.centroid for face in self.faces]
|
|
|
|
neighboringFaceVertices.extend(self.vertices)
|
|
|
|
xs = [vertex.x for vertex in neighboringFaceVertices]
|
|
|
|
ys = [vertex.y for vertex in neighboringFaceVertices]
|
|
|
|
zs = [vertex.z for vertex in neighboringFaceVertices]
|
2012-03-19 21:56:12 -07:00
|
|
|
x = sum(xs) / len(xs)
|
|
|
|
y = sum(ys) / len(ys)
|
|
|
|
z = sum(zs) / len(zs)
|
|
|
|
self.__edge_vertex = Vertex(x, y, z)
|
|
|
|
self.__edge_vertex.edges.extend(self.__sub_edges)
|
|
|
|
return self.__edge_vertex
|
|
|
|
|
2012-03-19 19:38:40 -07:00
|
|
|
def __averageVertices(self, vertices):
|
2012-03-19 21:56:12 -07:00
|
|
|
return
|
|
|
|
|
|
|
|
|
2012-03-19 19:38:40 -07:00
|
|
|
class Face(object):
|
|
|
|
'''
|
2012-03-19 21:56:12 -07:00
|
|
|
A face is a closed set of edges, in which a triangle face has three edges,
|
|
|
|
and a quad face has four edges.
|
2012-03-19 19:38:40 -07:00
|
|
|
'''
|
|
|
|
def __init__(self):
|
|
|
|
self.edges = []
|
|
|
|
self.__centroid = None
|
2012-03-19 21:56:12 -07:00
|
|
|
self.__interior_edges = []
|
|
|
|
self.__sub_faces = []
|
|
|
|
|
|
|
|
@property
|
|
|
|
def centroid(self):
|
2012-03-19 19:38:40 -07:00
|
|
|
if not self.__centroid:
|
|
|
|
# gather all face vertex coords
|
2012-03-19 21:56:12 -07:00
|
|
|
face_vertices = list(set([vertex
|
|
|
|
for edge in self.edges for vertex in edge.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]
|
|
|
|
|
2012-03-19 19:38:40 -07:00
|
|
|
# average each vertex component
|
|
|
|
x = sum(xs) / len(xs)
|
|
|
|
y = sum(ys) / len(ys)
|
|
|
|
z = sum(zs) / len(zs)
|
2012-03-19 21:56:12 -07:00
|
|
|
|
2012-03-19 19:38:40 -07:00
|
|
|
self.__centroid = Vertex(x, y, z)
|
|
|
|
return self.__centroid
|
2012-03-19 21:56:12 -07:00
|
|
|
|
|
|
|
@property
|
|
|
|
def sub_faces(self):
|
2012-03-19 19:38:40 -07:00
|
|
|
self.__setupSubDivisions()
|
2012-03-19 21:56:12 -07:00
|
|
|
return self.__sub_faces
|
|
|
|
|
|
|
|
@property
|
|
|
|
def interior_edges(self):
|
2012-03-19 19:38:40 -07:00
|
|
|
self.__setupSubDivisions()
|
2012-03-19 21:56:12 -07:00
|
|
|
return self.__interior_edges
|
|
|
|
|
2012-03-19 19:38:40 -07:00
|
|
|
def __setupSubDivisions(self):
|
|
|
|
'''
|
|
|
|
v0 ev0 v1
|
|
|
|
*------e0-----*
|
|
|
|
| | |
|
|
|
|
| | |
|
|
|
|
ev3 e|11----f5----e|1 ev1
|
|
|
|
| | |
|
|
|
|
| | |
|
|
|
|
*------e2-----*
|
|
|
|
v3 ev2 v2
|
|
|
|
'''
|
2012-03-19 21:56:12 -07:00
|
|
|
if not self.__sub_faces:
|
|
|
|
# create empty sub_faces that will be filled with edge references
|
|
|
|
# below
|
|
|
|
# these need to at least exist so the interior edges have
|
|
|
|
# something to reference
|
|
|
|
self.__sub_faces = [Face() for edge in self.edges]
|
|
|
|
|
|
|
|
if not self.__interior_edges:
|
2012-03-19 19:38:40 -07:00
|
|
|
# set up empty edge objects to be filled below
|
2012-03-19 21:56:12 -07:00
|
|
|
self.__interior_edges = [Edge() for edge in self.edges]
|
|
|
|
|
|
|
|
# each interior edge connects the exterior edge vertex (mid-point)
|
|
|
|
# to the faceVertex (centroid)
|
2012-03-19 19:38:40 -07:00
|
|
|
for index in range(len(self.edges)):
|
|
|
|
prevIndex = (index - 1) % len(self.edges)
|
|
|
|
nextIndex = (index + 1) % len(self.edges)
|
2012-03-19 21:56:12 -07:00
|
|
|
|
|
|
|
# end vertices are face centroid and currEdge edge_vertex
|
|
|
|
self.__interior_edges[index].vertices = [
|
|
|
|
self.edges[index].edge_vertex, self.centroid
|
|
|
|
]
|
|
|
|
|
|
|
|
# wing edges are the current edge's sub_edges (ordered same as
|
|
|
|
# vertex order) and the prev and next interior edges
|
|
|
|
self.__interior_edges[index].edges = [
|
|
|
|
self.edges[index].sub_edges[0],
|
|
|
|
self.edges[index].sub_edges[1],
|
|
|
|
self.__interior_edges[prevIndex],
|
|
|
|
self.__interior_edges[nextIndex]
|
|
|
|
]
|
|
|
|
|
|
|
|
# edge faces are the new sub_faces (current and next faces), the
|
|
|
|
# current will be define below
|
|
|
|
# and the next will be defined on the next iteration (or
|
|
|
|
# already defined on the last iteration)
|
|
|
|
self.__interior_edges[index].faces = [
|
|
|
|
self.__sub_faces[index],
|
|
|
|
self.__sub_faces[nextIndex]
|
|
|
|
]
|
|
|
|
|
2012-03-19 19:38:40 -07:00
|
|
|
# now reference the current edge back into the faces,
|
2012-03-19 21:56:12 -07:00
|
|
|
# and the edge.sub_edges, and the edge.edge_vertex
|
|
|
|
|
2012-03-19 19:38:40 -07:00
|
|
|
# current subFace (same index as current interior edge)
|
2012-03-19 21:56:12 -07:00
|
|
|
# set its edges to reference the same edges used to setup the
|
|
|
|
# interior edge
|
2012-03-19 19:38:40 -07:00
|
|
|
# order will be pretty important on these steps...
|
2012-03-19 21:56:12 -07:00
|
|
|
self.__sub_faces[index].edges = [
|
|
|
|
self.edges[index].sub_edges[0],
|
|
|
|
self.__interior_edges[index],
|
|
|
|
self.__interior_edges[prevIndex],
|
|
|
|
self.edges[prevIndex].sub_edges[1]
|
|
|
|
]
|
|
|
|
|
|
|
|
# just set one of the vertex edges, the other belongs to
|
|
|
|
# another face and will get added when that face is run
|
|
|
|
self.edges[index].edge_vertex.edges.append(
|
|
|
|
self.__interior_edges[index])
|
|
|
|
|
|
|
|
self.edges[index].sub_edges[0].faces.append(
|
|
|
|
self.__sub_faces[index])
|
|
|
|
self.edges[index].sub_edges[0].faces.append(
|
|
|
|
self.__sub_faces[index])
|
|
|
|
|
|
|
|
|
2012-03-19 19:38:40 -07:00
|
|
|
class Polygon(object):
|
|
|
|
'''
|
2012-03-19 21:56:12 -07:00
|
|
|
Face splitting should happend on the polygon level(?). It doesn't make
|
|
|
|
sense to split just one face since it needs to average vertices with all
|
|
|
|
adjoinging faces
|
2012-03-19 19:38:40 -07:00
|
|
|
'''
|
2012-03-19 21:56:12 -07:00
|
|
|
|
2012-03-19 19:38:40 -07:00
|
|
|
def __init__(self, v=None, e=None, f=None):
|
|
|
|
self.vertices = v or []
|
|
|
|
self.edges = e or []
|
|
|
|
self.faces = f or []
|
|
|
|
|
|
|
|
def __unicode__(self):
|
|
|
|
d = {
|
|
|
|
'vertices': self.vertices,
|
|
|
|
'edges': self.edges,
|
|
|
|
'faces': self.faces,
|
|
|
|
}
|
|
|
|
return pprint.pformat(d)
|
|
|
|
|
|
|
|
__str__ = __unicode__
|
|
|
|
__repr__ = __unicode__
|