Merge pull request #5 from willblatt/master

It plots it out, it looks mostly correct
This commit is contained in:
Stephen McQuay 2012-03-19 08:22:39 -07:00
commit 4e3573a5b9
1 changed files with 280 additions and 138 deletions

View File

@ -88,15 +88,33 @@ class Vertex(object):
''' '''
A vertex is a position along with other information such as color, normal vector and texture coordinates. A vertex is a position along with other information such as color, normal vector and texture coordinates.
''' '''
def __init__(self, x, y, z): def __init__(self, x=0, y=0, z=0):
self.x = x self.x = x
self.y = y self.y = y
self.z = z self.z = z
self.edges = [] self.edges = []
def __repr__(self): def __repr__(self):
return "<%.2f, %.2f, %.2f>" % (self.x, self.y, self.z) return "<%.2f, %.2f, %.2f>" % (self.x, self.y, self.z)
def __add__(self, other):
# for now just assume type(other) = Vertex... bad, I know
return Vertex(self.x + other.x, self.y + other.y, self.z + other.z)
def __radd__(self, other):
return self.__add__(other)
def __mul__(self, other):
# for now just assume type(other) = int or float
return Vertex(self.x * other, self.y * other, self.z * other)
def __rmul__(self, other):
return self.__mul__(other)
def __div__(self, other):
# same assumption as __mult__
return Vertex(self.x / other, self.y / other, self.z / other)
class Edge(object): class Edge(object):
''' '''
''' '''
@ -104,34 +122,49 @@ class Edge(object):
self.vertices = [] self.vertices = []
self.faces = [] self.faces = []
self.edges = [] self.edges = []
self.__edgeVertex = None
self.__subEdges = []
def neighborFace(self, neighborFace): def neighborFace(self, neighborFace):
if neighborFace == self.faces[0]: if neighborFace == self.faces[0]:
return self.faces[1] return self.faces[1]
else: else:
return self.faces[0] return self.faces[0]
def __getMidPoint(self):
return sum(self.vertices, Vertex())/len(self.vertices)
midPoint = property(fget=__getMidPoint)
def edgeVertex(self): def __getSubEdges(self):
if not self.__subEdges:
self.__subEdges = [Edge(), Edge()]
self.__subEdges[0].vertices = [self.vertices[0], self.edgeVertex]
self.__subEdges[1].vertices = [self.edgeVertex, self.vertices[1]]
return self.__subEdges
subEdges = property(fget=__getSubEdges)
def __getEdgeVertex(self):
''' '''
Set each edge vertices to be the average of the two neighboring Set each edge vertices to be the average of the two neighboring
face vertices and its two original end vertices. face vertices and its two original end vertices.
''' '''
if not self.__edgeVertex:
# two neighboring face vertices: # two neighboring face vertices:
neighborVertices = [face.centroid for face in self.faces] neighboringFaceVertices = [face.centroid for face in self.faces]
neighboringFaceVertices.extend(self.vertices)
vertices = list(self.vertices) xs = [vertex.x for vertex in neighboringFaceVertices]
vertices.extend(neighborVertices) ys = [vertex.y for vertex in neighboringFaceVertices]
return self.__averageVertices(vertices) zs = [vertex.z for vertex in neighboringFaceVertices]
x = sum(xs)/len(xs)
y = sum(ys)/len(ys)
z = sum(zs)/len(zs)
self.__edgeVertex = Vertex(x, y, z)
self.__edgeVertex.edges.extend(self.__subEdges)
return self.__edgeVertex
edgeVertex = property(fget=__getEdgeVertex)
def __averageVertices(self, vertices): def __averageVertices(self, vertices):
xs = [vertex.x for vertex in vertices]
ys = [vertex.y for vertex in vertices] return
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): class Face(object):
''' '''
@ -139,40 +172,105 @@ class Face(object):
''' '''
def __init__(self): def __init__(self):
self.edges = [] self.edges = []
self.__centroid = None
self.__interiorEdges = []
self.__subFaces = []
def __getCentroid(self): def __getCentroid(self):
# gather all vertex coords if not self.__centroid:
faceVertices = self.__getFaceVertices() # gather all face vertex coords
xs = [vertex.x for vertex in faceVertices] faceVertices = list(set([vertex for edge in self.edges for vertex in edge.vertices]))
ys = [vertex.y for vertex in faceVertices] xs = [vertex.x for vertex in faceVertices]
zs = [vertex.z 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) # average each vertex component
y = sum(ys) / len(ys) x = sum(xs) / len(xs)
z = sum(zs) / len(zs) y = sum(ys) / len(ys)
z = sum(zs) / len(zs)
return Vertex(x, y, z)
self.__centroid = Vertex(x, y, z)
return self.__centroid
centroid = property(fget=__getCentroid) centroid = property(fget=__getCentroid)
def __getFaceVertices(self): def __getSubFaces(self):
return list([vertex for edge in self.edges for vertex in edge.vertices]) self.__setupSubDivisions()
vertices = property(fget=__getFaceVertices) return self.__subFaces
subFaces = property(fget=__getSubFaces)
def __getInteriorEdges(self):
self.__setupSubDivisions()
return self.__interiorEdges
interiorEdges = property(fget=__getInteriorEdges )
def __setupSubDivisions(self):
'''
v0 ev0 v1
*------e0-----*
| | |
| | |
ev3 e|11----f5----e|1 ev1
| | |
| | |
*------e2-----*
v3 ev2 v2
'''
if not self.__subFaces:
# create empty subFaces that will be filled with edge references below
# these need to at least exist so the interior edges have something to reference
self.__subFaces = [Face() for edge in self.edges]
if not self.__interiorEdges:
# set up empty edge objects to be filled below
self.__interiorEdges = [Edge() for edge in self.edges]
# each interior edge connects the exterior edge vertex (mid-point) to the faceVertex (centroid)
for index in range(len(self.edges)):
prevIndex = (index - 1) % len(self.edges)
nextIndex = (index + 1) % len(self.edges)
# end vertices are face centroid and currEdge edgeVertex
self.__interiorEdges[index].vertices = [self.edges[index].edgeVertex,
self.centroid]
# wing edges are the current edge's subEdges (ordered same as vertex order) and the prev and next interior edges
self.__interiorEdges[index].edges = [self.edges[index].subEdges[0],
self.edges[index].subEdges[1],
self.__interiorEdges[prevIndex],
self.__interiorEdges[nextIndex]]
# edge faces are the new subFaces (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.__interiorEdges[index].faces = [self.__subFaces[index],
self.__subFaces[nextIndex]]
# now reference the current edge back into the faces,
# and the edge.subEdges, and the edge.edgeVertex
# current subFace (same index as current interior edge)
# set its edges to reference the same edges used to setup the interior edge
# order will be pretty important on these steps...
self.__subFaces[index].edges = [self.edges[index].subEdges[0],
self.__interiorEdges[index],
self.__interiorEdges[prevIndex],
self.edges[prevIndex].subEdges[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].edgeVertex.edges.append(self.__interiorEdges[index])
self.edges[index].subEdges[0].faces.append(self.__subFaces[index])
self.edges[index].subEdges[0].faces.append(self.__subFaces[index])
class Polygon(object): class Polygon(object):
''' '''
Face splitting should happend on the polygon level(?). It doesn't make sense to split just one face since 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 it needs to average vertices with all adjoinging faces
''' '''
def __init__(self, vertices, edges, faces): def __init__(self):
self.vertices = vertices self.vertices = []
self.edges = edges self.edges = []
self.faces = faces self.faces = []
def __getFaceNeighbors(self, testFace):
for face in self.faces:
testFace.isNeighbor(face)
def catmullClarkRefine(self): def catmullClarkRefine(self):
''' '''
@ -184,126 +282,170 @@ class Polygon(object):
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 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
''' '''
# this calculates and returns the averaged vertex point
print self.faces[0].edges[0].edgeVertex()
# this returns a vertex at the face centroid
print self.faces[0].centroid
# this will get to the first neighborFace...
# each face knows its faceVertex, and all of its edgeVertices
neighborFace = self.faces[0].edges[0].neighborFace(self.faces[0])
print neighborFace.centroid
# each face knows how to subdivide and create a set of subfaces, including interior edges and setup their references correctly... <- not completely finished...
p = Polygon()
edges = []
vertices = []
faces = []
for face in self.faces:
for subFace in face.subFaces:
faces.append(subFace)
for edge in subFace.edges:
edges.append(edge)
for vertex in edge.vertices:
vertices.append(vertex)
for vertex in self.vertices:
faceVertices = []
edgeMidPoints = []
for edge in vertex.edges:
edgeMidPoints.append(edge.midPoint)
for face in edge.faces:
faceVertices.append(face.centroid)
f = sum(list(set(faceVertices)), Vertex())/len(list(set(faceVertices)))
r = sum(list(set(edgeMidPoints)), Vertex())/len(list(set(edgeMidPoints)))
p = vertex
n = len(vertex.edges)
v = (f + (2.0 * r) + (n - 3.0) * p) / n
# print v
vertex.x = v.x
vertex.y = v.y
vertex.z = v.z
# so now what......... # so now what.........
# (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 = number of edges connecting to P
p.faces = faces
p.vertices = vertices
p.edges = edges
# plotting these in excel seems to show the correct values (at first glace...)
# so now what.........
# (F + 2R + (n-3) P) / n # (F + 2R + (n-3) P) / n
# #
# F = average of all face vertices touching P # F = average of all face vertices touching P
# R = average of all edge vertices touching P # R = average of all edge vertices touching P
# P original point # P original point
# n = face vertices or edge vertices (should be the same number) # n = face vertices or edge vertices (should be the same number)
return p
v = [] def createPolygon():
v.append(Vertex(0.0, 1.0, 0.0)) v = []
v.append(Vertex(1.0, 1.0, 0.0)) v.append(Vertex(0.0, 1.0, 0.0))
v.append(Vertex(1.0, 0.0, 0.0)) v.append(Vertex(1.0, 1.0, 0.0))
v.append(Vertex(0.0, 0.0, 0.0)) v.append(Vertex(1.0, 0.0, 0.0))
v.append(Vertex(0.0, 1.0, 1.0)) v.append(Vertex(0.0, 0.0, 0.0))
v.append(Vertex(1.0, 1.0, 1.0))
v.append(Vertex(1.0, 0.0, 1.0)) v.append(Vertex(0.0, 1.0, 1.0))
v.append(Vertex(0.0, 0.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 = []
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())
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 = []
f.append(Face()) f.append(Face())
f.append(Face()) f.append(Face())
f.append(Face()) f.append(Face())
f.append(Face()) f.append(Face())
f.append(Face()) f.append(Face())
f.append(Face()) f.append(Face())
# vertex list # vertex list
v[0].edges = [e[0], e[3], e[4]] v[0].edges = [e[0], e[3], e[4]]
v[1].edges = [e[0], e[5], e[1]] v[1].edges = [e[0], e[5], e[1]]
v[2].edges = [e[1], e[6], e[2]] v[2].edges = [e[1], e[6], e[2]]
v[3].edges = [e[2], e[7], e[3]] v[3].edges = [e[2], e[7], e[3]]
v[4].edges = [e[4], e[11], e[8]] v[4].edges = [e[4], e[11], e[8]]
v[5].edges = [e[5], e[9], e[8]] v[5].edges = [e[5], e[9], e[8]]
v[6].edges = [e[2], e[9], e[10]] v[6].edges = [e[6], e[9], e[10]]
v[7].edges = [e[7], e[10], e[11]] v[7].edges = [e[7], e[10], e[11]]
# face list # face list
f[0].edges = [e[0], e[1], e[2], e[3]] f[0].edges = [e[0], e[1], e[2], e[3]]
f[1].edges = [e[1], e[5], e[9], e[6]] f[1].edges = [e[1], e[5], e[9], e[6]]
f[2].edges = [e[2], e[6], e[10], e[7]] f[2].edges = [e[2], e[6], e[10], e[7]]
f[3].edges = [e[4], e[3], e[7], e[11]] f[3].edges = [e[4], e[3], e[7], e[11]]
f[4].edges = [e[8], e[5], e[0], e[4]] f[4].edges = [e[8], e[5], e[0], e[4]]
f[5].edges = [e[10], e[9], e[8], e[11]] f[5].edges = [e[10], e[9], e[8], e[11]]
#winged edges ordered by face, then by vertex reference #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[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[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[2], v[3]], [f[0], f[2]], [e[3], e[7], e[1], e[6]] e[2].vertices, e[2].faces, e[2].edges = [v[2], v[3]], [f[0], f[2]], [e[1], e[3], e[6], e[7]]
e[3].vertices, e[3].faces, e[3].edges = [v[3], v[0]], [f[3], f[0]], [e[4], e[7], e[0], e[2]] e[3].vertices, e[3].faces, e[3].edges = [v[3], v[0]], [f[3], f[0]], [e[4], e[7], e[0], e[2]]
e[4].vertices, e[4].faces, e[4].edges = [v[0], v[4]], [f[3], f[4]], [e[11], e[3], e[0], e[8]] e[4].vertices, e[4].faces, e[4].edges = [v[0], v[4]], [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[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[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[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[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[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[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]] 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... # 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(v[0].x)
# print id(e[0].vertices[0].x) # print id(e[0].vertices[0].x)
# print id(f[0].edges[0].vertices[0].x) # print id(f[0].edges[0].vertices[0].x)
# v[0].x = 9 # v[0].x = 9
# print id(v[0].x) # print id(v[0].x)
# print id(e[0].vertices[0].x) # print id(e[0].vertices[0].x)
# print id(f[0].edges[0].vertices[0].x) # print id(f[0].edges[0].vertices[0].x)
# print v[0].x # print v[0].x
# print e[0].vertices[0].x # print e[0].vertices[0].x
# print f[0].edges[0].vertices[0].x # print f[0].edges[0].vertices[0].x
p = Polygon()
p.vertices = v
p.edges = e
p.faces = f
return p
polygon = Polygon(v, e, f) polygon = createPolygon()
polygon.catmullClarkRefine() newPolygon = polygon.catmullClarkRefine()
from numpy import *
import pylab
import mpl_toolkits.mplot3d.axes3d as p3
fig = pylab.figure()
# from numpy import * ax = p3.Axes3D(fig)
# import pylab for edge in newPolygon.edges:
# import mpl_toolkits.mplot3d.axes3d as p3 xs = [vertex.x for vertex in edge.vertices]
ys = [vertex.y for vertex in edge.vertices]
# fig = pylab.figure() zs = [vertex.z for vertex in edge.vertices]
# ax = p3.Axes3D(fig) ax.plot_wireframe(xs, ys, zs)
# ax.plot_wireframe(xs, ys, zs) ax.set_xlabel('X')
# ax.set_xlabel('X') ax.set_ylabel('Y')
# ax.set_ylabel('Y') ax.set_zlabel('Z')
# ax.set_zlabel('Z') pylab.show()
# 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)