2012-03-17 16:19:07 -07:00
# 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 ) :
2012-03-17 23:18:32 -07:00
return " < %.2f , %.2f , %.2f > " % ( self . x , self . y , self . z )
2012-03-17 16:19:07 -07:00
class Edge ( object ) :
'''
'''
def __init__ ( self ) :
self . vertices = [ ]
self . faces = [ ]
self . edges = [ ]
2012-03-18 17:03:07 -07:00
self . __edgeVertex = None
self . __subEdges = [ ]
2012-03-17 16:19:07 -07:00
2012-03-17 23:18:32 -07:00
def neighborFace ( self , neighborFace ) :
if neighborFace == self . faces [ 0 ] :
return self . faces [ 1 ]
else :
return self . faces [ 0 ]
2012-03-18 17:03:07 -07:00
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 ) :
2012-03-17 16:19:07 -07:00
'''
Set each edge vertices to be the average of the two neighboring
face vertices and its two original end vertices .
'''
2012-03-18 17:03:07 -07:00
if not self . __edgeVertex :
# 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 ]
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 )
2012-03-17 16:19:07 -07:00
def __averageVertices ( self , vertices ) :
2012-03-18 17:03:07 -07:00
return
2012-03-17 16:19:07 -07:00
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 = [ ]
2012-03-18 17:03:07 -07:00
self . __centroid = None
self . __interiorEdges = [ ]
self . __subFaces = [ ]
2012-03-17 23:18:32 -07:00
2012-03-17 16:19:07 -07:00
def __getCentroid ( self ) :
2012-03-18 17:03:07 -07:00
if not self . __centroid :
# gather all face vertex coords
faceVertices = list ( set ( [ vertex for edge in self . edges for vertex in edge . vertices ] ) )
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 )
self . __centroid = Vertex ( x , y , z )
return self . __centroid
2012-03-17 16:19:07 -07:00
centroid = property ( fget = __getCentroid )
2012-03-18 17:03:07 -07:00
def __getSubFaces ( self ) :
self . __setupSubDivisions ( )
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 ] )
2012-03-17 23:18:32 -07:00
2012-03-17 16:19:07 -07:00
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
'''
2012-03-18 17:52:24 -07:00
def __init__ ( self ) :
self . vertices = [ ]
self . edges = [ ]
self . faces = [ ]
2012-03-17 16:19:07 -07:00
def catmullClarkRefine ( self ) :
'''
2012-03-17 23:18:32 -07:00
For each face , add a face vertex
2012-03-17 16:19:07 -07:00
Set each face vertex to be the centroid of all original vertices for the respective face .
2012-03-17 23:18:32 -07:00
For each edge , add an edge vertex .
2012-03-17 16:19:07 -07:00
Set each edge vertex to be the average of the two neighbouring face vertices and its two original endvertices .
2012-03-17 23:18:32 -07:00
For each face vertex , add an edge for every edge of the face , connecting the face vertex to each edge vertex for the face .
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
2012-03-17 16:19:07 -07:00
'''
2012-03-18 17:03:07 -07:00
# each face knows how to subdivide and create a set of subfaces, including interior edges and setup their references correctly... <- not completely finished...
2012-03-18 17:52:24 -07:00
p = Polygon ( )
edges = [ ]
vertices = [ ]
faces = [ ]
2012-03-18 17:03:07 -07:00
for face in self . faces :
for subFace in face . subFaces :
2012-03-18 17:52:24 -07:00
faces . append ( subFace )
2012-03-18 17:03:07 -07:00
for edge in subFace . edges :
2012-03-18 17:52:24 -07:00
edges . append ( edge )
2012-03-18 17:03:07 -07:00
for vertex in edge . vertices :
2012-03-18 17:52:24 -07:00
vertices . append ( vertex )
p . faces = faces
p . vertices = vertices
p . edges = edges
2012-03-18 17:03:07 -07:00
# plotting these in excel seems to show the correct values (at first glace...)
2012-03-17 16:19:07 -07:00
2012-03-18 17:52:24 -07:00
# so now what.........
2012-03-17 16:19:07 -07:00
# (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)
2012-03-18 17:52:24 -07:00
return p
2012-03-17 16:19:07 -07:00
2012-03-18 17:52:24 -07:00
def createPolygon ( ) :
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 ) )
2012-03-17 16:19:07 -07:00
2012-03-18 17:52:24 -07:00
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 ( ) )
2012-03-17 16:19:07 -07:00
2012-03-18 17:52:24 -07:00
f = [ ]
f . append ( Face ( ) )
f . append ( Face ( ) )
f . append ( Face ( ) )
f . append ( Face ( ) )
f . append ( Face ( ) )
f . append ( Face ( ) )
2012-03-17 16:19:07 -07:00
2012-03-18 17:52:24 -07:00
# 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 ] ]
2012-03-17 16:19:07 -07:00
2012-03-18 17:52:24 -07:00
# 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 ] ]
2012-03-17 16:19:07 -07:00
2012-03-18 17:52:24 -07:00
#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 [ 2 ] , v [ 3 ] ] , [ f [ 0 ] , f [ 2 ] ] , [ e [ 3 ] , e [ 7 ] , e [ 1 ] , e [ 6 ] ]
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 [ 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 ] ]
2012-03-17 16:19:07 -07:00
2012-03-18 17:52:24 -07:00
# just to prove to myself that the objects are the same, this is what years of pass by value have done to me...
2012-03-17 16:19:07 -07:00
2012-03-18 17:52:24 -07:00
# print id(v[0].x)
# print id(e[0].vertices[0].x)
# print id(f[0].edges[0].vertices[0].x)
2012-03-17 16:19:07 -07:00
2012-03-18 17:52:24 -07:00
# v[0].x = 9
2012-03-17 16:19:07 -07:00
2012-03-18 17:52:24 -07:00
# print id(v[0].x)
# print id(e[0].vertices[0].x)
# print id(f[0].edges[0].vertices[0].x)
2012-03-17 16:19:07 -07:00
2012-03-18 17:52:24 -07:00
# print v[0].x
# print e[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
2012-03-17 16:19:07 -07:00
2012-03-18 17:52:24 -07:00
polygon = createPolygon ( )
newPolygon = polygon . catmullClarkRefine ( )
2012-03-17 16:19:07 -07:00
2012-03-18 17:52:24 -07:00
from numpy import *
import pylab
import mpl_toolkits . mplot3d . axes3d as p3
2012-03-17 16:19:07 -07:00
2012-03-18 17:52:24 -07:00
fig = pylab . figure ( )
ax = p3 . Axes3D ( fig )
for edge in newPolygon . edges :
xs = [ vertex . x for vertex in edge . vertices ]
ys = [ vertex . y for vertex in edge . vertices ]
zs = [ vertex . z for vertex in edge . vertices ]
ax . plot_wireframe ( xs , ys , zs )
ax . set_xlabel ( ' X ' )
ax . set_ylabel ( ' Y ' )
ax . set_zlabel ( ' Z ' )
pylab . show ( )