294 lines
11 KiB
Python
Executable File
294 lines
11 KiB
Python
Executable File
# import scipy
|
|
|
|
'''
|
|
http://en.wikipedia.org/wiki/Polygon_mesh
|
|
|
|
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 meshes: A simple list of vertices, and a set of polygons that vertex to the vertices it uses.
|
|
Winged-edge meshes, in which each edge vertices to two vertices, two faces, and the four (clockwise and counterclockwise) edges that touch it. Winged-edge meshes allow constant time traversal of the surface, but with higher storage requirements.
|
|
Half-edge meshes: Similar to winged-edge meshes except that only half the edge traversal information is used.
|
|
Quad-edge meshes, which store edges, half-edges, and vertices without any reference to polygons. The polygons are implicit in the representation, and may be found by traversing the structure. Memory requirements are similar to half-edge meshes.
|
|
Corner-tables, which store vertices in a predefined table, such that traversing the table implicitly defines polygons. This is in essence the "triangle fan" used in hardware graphics rendering. The representation is more compact, and more efficient to retrieve polygons, but operations to change polygons are slow. Furthermore, corner-tables do not represent meshes completely. Multiple corner-tables (triangle fans) are needed to represent most meshes.
|
|
Vertex-vertex meshes: A "VV" mesh represents only vertices, which vertex to other vertices. Both the edge and face information is implicit in the representation. However, the simplicity of the representation allows for many efficient operations to be performed on meshes.
|
|
|
|
|
|
Face-vertex meshes represent an object as a set of faces and a set of vertices. This is the most widely used mesh representation, being the input typically accepted by modern graphics hardware.
|
|
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>
|
|
|
|
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
|
|
|
|
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
|
|
|
|
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
|
|
|
|
'''
|
|
|
|
class Vertex(object):
|
|
'''
|
|
A vertex is a position along with other information such as color, normal vector and texture coordinates.
|
|
'''
|
|
def __init__(self, x, y, z):
|
|
self.x = x
|
|
self.y = y
|
|
self.z = z
|
|
self.edges = []
|
|
|
|
def __repr__(self):
|
|
return "<%.2f, %.2f, %.2f>, faces: %s" % (self.x, self.y, self.z, [edge.id for edge in self.edges])
|
|
|
|
class Edge(object):
|
|
'''
|
|
'''
|
|
def __init__(self):
|
|
self.id = 0
|
|
self.vertices = []
|
|
self.faces = []
|
|
self.edges = []
|
|
|
|
def createEdgeVertex(self):
|
|
'''
|
|
Set each edge vertices to be the average of the two neighboring
|
|
face vertices and its two original end vertices.
|
|
'''
|
|
|
|
# two neighboring face vertices:
|
|
neighborVertices = [face.centroid for face in self.faces]
|
|
|
|
vertices = list(self.vertices)
|
|
vertices.extend(neighborVertices)
|
|
return self.__averageVertices(vertices)
|
|
|
|
def __averageVertices(self, vertices):
|
|
xs = [vertex.x for vertex in vertices]
|
|
ys = [vertex.y for vertex in vertices]
|
|
zs = [vertex.z for vertex in vertices]
|
|
x = sum(xs)/len(xs)
|
|
y = sum(ys)/len(ys)
|
|
z = sum(zs)/len(zs)
|
|
return Vertex(x, y, z)
|
|
|
|
class Face(object):
|
|
'''
|
|
A face is a closed set of edges, in which a triangle face has three edges, and a quad face has four edges.
|
|
'''
|
|
def __init__(self):
|
|
self.edges = []
|
|
|
|
def __getCentroid(self):
|
|
# gather all vertex coords
|
|
faceVertices = self.__getFaceVertices()
|
|
xs = [vertex.x for vertex in faceVertices]
|
|
ys = [vertex.y for vertex in faceVertices]
|
|
zs = [vertex.z for vertex in faceVertices]
|
|
|
|
# average each vertex component
|
|
x = sum(xs) / len(xs)
|
|
y = sum(ys) / len(ys)
|
|
z = sum(zs) / len(zs)
|
|
|
|
return Vertex(x, y, z)
|
|
centroid = property(fget=__getCentroid)
|
|
|
|
def __getFaceVertices(self):
|
|
return list(set([vertex for edge in self.edges for vertex in edge.vertices]))
|
|
|
|
class Polygon(object):
|
|
'''
|
|
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
|
|
'''
|
|
|
|
def __init__(self, vertices, edges, faces):
|
|
self.vertices = vertices
|
|
self.edges = edges
|
|
self.faces = faces
|
|
|
|
def catmullClarkRefine(self):
|
|
'''
|
|
1. For each face, add a face vertex
|
|
Set each face vertex to be the centroid of all original vertices for the respective face.
|
|
2. For each edge, add an edge vertex.
|
|
Set each edge vertex to be the average of the two neighbouring face vertices and its two original endvertices.
|
|
3. For each face vertex, add an edge for every edge of the face, connecting the face vertex to each edge vertex for the face.
|
|
4. For each original vertex P, take the average F of all n face vertices for faces touching P, and take the average R of all n edge midvertices for edges touching P, where each edge midvertex is the average of its two endvertex vertices. Move each original vertex to the vertex
|
|
'''
|
|
|
|
# 1
|
|
faceVertex = self.faces[0].centroid
|
|
|
|
# 2
|
|
edgeVertices = [edge.createEdgeVertex() for edge in self.faces[0].edges]
|
|
|
|
# 3
|
|
|
|
# 4
|
|
# (F + 2R + (n-3) P) / n
|
|
#
|
|
# F = average of all face vertices touching P
|
|
# R = average of all edge vertices touching P
|
|
# P original point
|
|
# n = face vertices or edge vertices (should be the same number)
|
|
|
|
v = []
|
|
v.append(Vertex(0.0, 1.0, 0.0))
|
|
v.append(Vertex(1.0, 1.0, 0.0))
|
|
v.append(Vertex(1.0, 0.0, 0.0))
|
|
v.append(Vertex(0.0, 0.0, 0.0))
|
|
v.append(Vertex(0.0, 1.0, 1.0))
|
|
v.append(Vertex(1.0, 1.0, 1.0))
|
|
v.append(Vertex(1.0, 0.0, 1.0))
|
|
v.append(Vertex(0.0, 0.0, 1.0))
|
|
|
|
e = []
|
|
e.append(Edge())
|
|
e.append(Edge())
|
|
e.append(Edge())
|
|
e.append(Edge())
|
|
e.append(Edge())
|
|
e.append(Edge())
|
|
e.append(Edge())
|
|
e.append(Edge())
|
|
e.append(Edge())
|
|
e.append(Edge())
|
|
e.append(Edge())
|
|
e.append(Edge())
|
|
|
|
f = []
|
|
f.append(Face())
|
|
f.append(Face())
|
|
f.append(Face())
|
|
f.append(Face())
|
|
f.append(Face())
|
|
f.append(Face())
|
|
|
|
# vertex list
|
|
v[0].edges = [e[0], e[3], e[4]]
|
|
v[1].edges = [e[0], e[5], e[1]]
|
|
v[2].edges = [e[1], e[6], e[2]]
|
|
v[3].edges = [e[2], e[7], e[3]]
|
|
v[4].edges = [e[4], e[11], e[8]]
|
|
v[5].edges = [e[5], e[9], e[8]]
|
|
v[6].edges = [e[2], e[9], e[10]]
|
|
v[7].edges = [e[7], e[10], e[11]]
|
|
|
|
# face list
|
|
f[0].edges = [e[0], e[1], e[2], e[3]]
|
|
f[1].edges = [e[1], e[5], e[9], e[6]]
|
|
f[2].edges = [e[2], e[6], e[10], e[7]]
|
|
f[3].edges = [e[4], e[3], e[7], e[11]]
|
|
f[4].edges = [e[8], e[5], e[0], e[4]]
|
|
f[5].edges = [e[10], e[9], e[8], e[11]]
|
|
|
|
#winged edges ordered by face, then by vertex reference
|
|
e[0].vertices, e[0].faces, e[0].edges = [v[0], v[1]], [f[0], f[4]], [e[3], e[1], e[4], e[5]]
|
|
e[1].vertices, e[1].faces, e[1].edges = [v[1], v[2]], [f[0], f[1]], [e[0], e[2], e[5], e[6]]
|
|
e[2].vertices, e[2].faces, e[2].edges = [v[3], v[2]], [f[0], f[2]], [e[3], e[7], e[1], e[6]]
|
|
e[3].vertices, e[3].faces, e[3].edges = [v[0], v[3]], [f[3], f[0]], [e[4], e[7], e[0], e[2]]
|
|
e[4].vertices, e[4].faces, e[4].edges = [v[4], v[0]], [f[3], f[4]], [e[11], e[3], e[0], e[8]]
|
|
e[5].vertices, e[5].faces, e[5].edges = [v[5], v[1]], [f[4], f[1]], [e[8], e[0], e[9], e[1]]
|
|
e[6].vertices, e[6].faces, e[6].edges = [v[2], v[6]], [f[1], f[2]], [e[1], e[9], e[2], e[10]]
|
|
e[7].vertices, e[7].faces, e[7].edges = [v[7], v[3]], [f[3], f[2]], [e[11], e[3], e[10], e[2]]
|
|
e[8].vertices, e[8].faces, e[8].edges = [v[4], v[5]], [f[4], f[5]], [e[4], e[5], e[11], e[9]]
|
|
e[9].vertices, e[9].faces, e[9].edges = [v[5], v[6]], [f[1], f[5]], [e[5], e[6], e[8], e[10]]
|
|
e[10].vertices, e[10].faces, e[10].edges = [v[7], v[6]], [f[2], f[5]], [e[7], e[6], e[11], e[9]]
|
|
e[11].vertices, e[11].faces, e[11].edges = [v[4], v[7]], [f[3], f[5]], [e[4], e[7], e[8], e[10]]
|
|
|
|
# just to prove to myself that the objects are the same, this is what years of pass by value have done to me...
|
|
|
|
# print id(v[0].x)
|
|
# print id(e[0].vertices[0].x)
|
|
# print id(f[0].edges[0].vertices[0].x)
|
|
|
|
# v[0].x = 9
|
|
|
|
# print id(v[0].x)
|
|
# print id(e[0].vertices[0].x)
|
|
# print id(f[0].edges[0].vertices[0].x)
|
|
|
|
# print v[0].x
|
|
# print e[0].vertices[0].x
|
|
# print f[0].edges[0].vertices[0].x
|
|
|
|
polygon = Polygon(v, e, f)
|
|
polygon.catmullClarkRefine()
|
|
|
|
|
|
|
|
# from numpy import *
|
|
# import pylab
|
|
# import mpl_toolkits.mplot3d.axes3d as p3
|
|
|
|
# fig = pylab.figure()
|
|
# ax = p3.Axes3D(fig)
|
|
# ax.plot_wireframe(xs, ys, zs)
|
|
# ax.set_xlabel('X')
|
|
# ax.set_ylabel('Y')
|
|
# ax.set_zlabel('Z')
|
|
# pylab.show()
|
|
|
|
# v4 = Vertex(4, 0, 0, 1)
|
|
# v5 = Vertex(5, 1, 0, 1)
|
|
# v6 = Vertex(6, 0, 1, 1)
|
|
# v7 = Vertex(7, 1, 1, 1)
|