2012-03-22 09:09:14 -07:00
|
|
|
from __future__ import division
|
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
|
|
|
'''
|
|
|
|
|
2012-03-20 06:16:15 -07:00
|
|
|
def cross(a, b):
|
|
|
|
i = a.y * b.z - a.z * b.y
|
|
|
|
j = a.z * b.x - a.x * b.z
|
|
|
|
k = a.x * b.y - a.y * b.x
|
|
|
|
return Vertex(i, j, k)
|
|
|
|
|
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):
|
2012-03-20 06:16:15 -07:00
|
|
|
return other + self
|
|
|
|
# return self.__add__(other)
|
2012-03-19 21:56:12 -07:00
|
|
|
|
|
|
|
def __mul__(self, other):
|
2012-03-20 06:16:15 -07:00
|
|
|
if isinstance(other, Vertex):
|
|
|
|
return cross(self, other)
|
|
|
|
elif isinstance(other, (float, int)):
|
|
|
|
return Vertex(self.x * other, self.y * other, self.z * other)
|
|
|
|
else:
|
|
|
|
raise TypeError("{0} has an unexpected type: {1}".format(
|
|
|
|
other, type(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__
|
|
|
|
return Vertex(self.x / other, self.y / other, self.z / other)
|
2012-03-22 09:09:14 -07:00
|
|
|
__truediv__ = __div__
|
2012-03-19 21:56:12 -07:00
|
|
|
|
2012-03-20 06:16:15 -07:00
|
|
|
def __neg__(self):
|
|
|
|
return Vertex(-self.x, -self.y, -self.z)
|
|
|
|
|
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__
|