Refactored into modules and test scripts.
This commit is contained in:
parent
6a69a99706
commit
2f4d648f55
0
surf/__init__.py
Normal file
0
surf/__init__.py
Normal file
@ -1,464 +1,286 @@
|
|||||||
# import scipy
|
from __future__ import division
|
||||||
|
import pprint
|
||||||
'''
|
import json
|
||||||
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:
|
http://en.wikipedia.org/wiki/Polygon_mesh
|
||||||
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.
|
Polygon meshes may be represented in a variety of ways, using different methods to store the vertex, edge and face data. These include:
|
||||||
Half-edge meshes: Similar to winged-edge meshes except that only half the edge traversal information is used.
|
Face-vertex meshes: A simple list of vertices, and a set of polygons that vertex to the vertices it uses.
|
||||||
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.
|
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.
|
||||||
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.
|
Half-edge meshes: Similar to winged-edge meshes except that only half the edge traversal information is used.
|
||||||
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.
|
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-----*
|
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
|
e|4 f4 e|5
|
||||||
*-----e4-----*-----e0-----*-----e5-----*
|
| |
|
||||||
| | | |
|
v4 v|0 v|1 v5
|
||||||
| | | |
|
*-----e4-----*-----e0-----*-----e5-----*
|
||||||
e11| f3 e|3 f0 e|1 f1 e|9
|
| | | |
|
||||||
| | | |
|
| | | |
|
||||||
| | | |
|
e11| f3 e|3 f0 e|1 f1 e|9
|
||||||
*-----e7-----*-----e2-----*-----e6-----*
|
| | | |
|
||||||
v7 v|3 v|2 v6
|
| | | |
|
||||||
| |
|
*-----e7-----*-----e2-----*-----e6-----*
|
||||||
e|7 f2 e|6
|
v7 v|3 v|2 v6
|
||||||
| |
|
| |
|
||||||
v|7 v|6
|
e|7 f2 e|6
|
||||||
*-----e10----*
|
| |
|
||||||
| |
|
v|7 v|6
|
||||||
| |
|
*-----e10----*
|
||||||
e|11 f5 e|9
|
| |
|
||||||
| |
|
| |
|
||||||
| |
|
e|11 f5 e|9
|
||||||
*-----e8-----*
|
| |
|
||||||
v4 v5
|
| |
|
||||||
v0 - <0,1,0>
|
*-----e8-----*
|
||||||
v1 - <1,1,0>
|
v4 v5
|
||||||
v2 - <1,0,0>
|
v0 - <0,1,0>
|
||||||
v3 - <0,0,0>
|
v1 - <1,1,0>
|
||||||
v4 - <0,1,1>
|
v2 - <1,0,0>
|
||||||
v5 - <1,1,1>
|
v3 - <0,0,0>
|
||||||
v6 - <1,0,1>
|
v4 - <0,1,1>
|
||||||
v7 - <0,0,1>
|
v5 - <1,1,1>
|
||||||
|
v6 - <1,0,1>
|
||||||
face list
|
v7 - <0,0,1>
|
||||||
f0 - e0, e1, e2, e3
|
|
||||||
f1 - e1, e5, e9, e6
|
face list
|
||||||
f2 - e2, e6, e10, e7
|
f0 - e0, e1, e2, e3
|
||||||
f3 - e4, e3, e7, e11
|
f1 - e1, e5, e9, e6
|
||||||
f4 - e8, e5, e0, e4
|
f2 - e2, e6, e10, e7
|
||||||
f5 - e10, e9, e8, e11
|
f3 - e4, e3, e7, e11
|
||||||
|
f4 - e8, e5, e0, e4
|
||||||
winged edges ordered by face, then by vertex reference
|
f5 - e10, e9, e8, e11
|
||||||
edge list
|
|
||||||
e0 - v0, v1; f0, f4; e3, e1, e4, e5
|
winged edges ordered by face, then by vertex reference
|
||||||
e1 - v1, v2; f0, f1; e0, e2, e5, e6
|
edge list
|
||||||
e2 - v3, v2; f0, f2; e3, e7, e1, e6
|
e0 - v0, v1; f0, f4; e3, e1, e4, e5
|
||||||
e3 - v0, v3; f3, f0; e4, e7, e0, e2
|
e1 - v1, v2; f0, f1; e0, e2, e5, e6
|
||||||
e4 - v4, v0; f3, f4; e11, e3, e0 e8
|
e2 - v3, v2; f0, f2; e3, e7, e1, e6
|
||||||
e5 - v5, v1; f4, f1; e8, e0, e9, e1
|
e3 - v0, v3; f3, f0; e4, e7, e0, e2
|
||||||
e6 - v2, v6; f1, f2; e1, e9, e2, e10
|
e4 - v4, v0; f3, f4; e11, e3, e0 e8
|
||||||
e7 - v7, v3; f3, f2; e11, e3, e10, e2
|
e5 - v5, v1; f4, f1; e8, e0, e9, e1
|
||||||
e8 - v4, v5, f4, f5; e4, e5, e11, e9
|
e6 - v2, v6; f1, f2; e1, e9, e2, e10
|
||||||
e9 - v5, v6; f1, f5; e5, e6, e8, e10
|
e7 - v7, v3; f3, f2; e11, e3, e10, e2
|
||||||
e10 - v7, v6; f2, f5; e7, e6, e11, e9
|
e8 - v4, v5, f4, f5; e4, e5, e11, e9
|
||||||
e11 - v4, v7; f3, f5; e4, e7, e8, 10
|
e9 - v5, v6; f1, f5; e5, e6, e8, e10
|
||||||
|
e10 - v7, v6; f2, f5; e7, e6, e11, e9
|
||||||
vertex list
|
e11 - v4, v7; f3, f5; e4, e7, e8, 10
|
||||||
v0 - e0, e3, e4
|
|
||||||
v1 - e0, e5, e1
|
vertex list
|
||||||
v2 - e1, e6, e2
|
v0 - e0, e3, e4
|
||||||
v3 - e2, e7, e3
|
v1 - e0, e5, e1
|
||||||
v4 - e4, e11, e8
|
v2 - e1, e6, e2
|
||||||
v5 - e5, e9, e8
|
v3 - e2, e7, e3
|
||||||
v6 - e2, e9, e10
|
v4 - e4, e11, e8
|
||||||
v7 - e7, e10, e11
|
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.
|
class Vertex(object):
|
||||||
'''
|
'''
|
||||||
def __init__(self, x=0, y=0, z=0):
|
A vertex is a position along with other information such as color, normal vector and texture coordinates.
|
||||||
self.x = x
|
'''
|
||||||
self.y = y
|
def __init__(self, x=0, y=0, z=0):
|
||||||
self.z = z
|
self.x = x
|
||||||
self.edges = []
|
self.y = y
|
||||||
|
self.z = z
|
||||||
def __repr__(self):
|
self.edges = []
|
||||||
return "<%.2f, %.2f, %.2f>" % (self.x, self.y, self.z)
|
|
||||||
|
def __repr__(self):
|
||||||
def __add__(self, other):
|
return "<%.2f, %.2f, %.2f>" % (self.x, self.y, self.z)
|
||||||
# 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 __add__(self, other):
|
||||||
|
# for now just assume type(other) = Vertex... bad, I know
|
||||||
def __radd__(self, other):
|
return Vertex(self.x + other.x, self.y + other.y, self.z + other.z)
|
||||||
return self.__add__(other)
|
|
||||||
|
def __radd__(self, other):
|
||||||
def __mul__(self, other):
|
return self.__add__(other)
|
||||||
# for now just assume type(other) = int or float
|
|
||||||
return Vertex(self.x * other, self.y * other, self.z * other)
|
def __mul__(self, other):
|
||||||
|
# for now just assume type(other) = int or float
|
||||||
def __rmul__(self, other):
|
return Vertex(self.x * other, self.y * other, self.z * other)
|
||||||
return self.__mul__(other)
|
|
||||||
|
def __rmul__(self, other):
|
||||||
def __div__(self, other):
|
return self.__mul__(other)
|
||||||
# same assumption as __mult__
|
|
||||||
return Vertex(self.x / other, self.y / other, self.z / other)
|
def __div__(self, other):
|
||||||
|
# same assumption as __mult__
|
||||||
class Edge(object):
|
return Vertex(self.x / other, self.y / other, self.z / other)
|
||||||
'''
|
|
||||||
'''
|
class Edge(object):
|
||||||
def __init__(self):
|
'''
|
||||||
self.vertices = []
|
'''
|
||||||
self.faces = []
|
def __init__(self):
|
||||||
self.edges = []
|
self.vertices = []
|
||||||
self.__edgeVertex = None
|
self.faces = []
|
||||||
self.__subEdges = []
|
self.edges = []
|
||||||
|
self.__edgeVertex = None
|
||||||
def neighborFace(self, neighborFace):
|
self.__subEdges = []
|
||||||
if neighborFace == self.faces[0]:
|
|
||||||
return self.faces[1]
|
def neighborFace(self, neighborFace):
|
||||||
else:
|
if neighborFace == self.faces[0]:
|
||||||
return self.faces[0]
|
return self.faces[1]
|
||||||
def __getMidPoint(self):
|
else:
|
||||||
return sum(self.vertices, Vertex())/len(self.vertices)
|
return self.faces[0]
|
||||||
midPoint = property(fget=__getMidPoint)
|
def __getMidPoint(self):
|
||||||
|
return sum(self.vertices) / len(self.vertices)
|
||||||
def __getSubEdges(self):
|
midPoint = property(fget=__getMidPoint)
|
||||||
if not self.__subEdges:
|
|
||||||
self.__subEdges = [Edge(), Edge()]
|
def __getSubEdges(self):
|
||||||
self.__subEdges[0].vertices = [self.vertices[0], self.edgeVertex]
|
if not self.__subEdges:
|
||||||
self.__subEdges[1].vertices = [self.edgeVertex, self.vertices[1]]
|
self.__subEdges = [Edge(), Edge()]
|
||||||
return self.__subEdges
|
self.__subEdges[0].vertices = [self.vertices[0], self.edgeVertex]
|
||||||
subEdges = property(fget=__getSubEdges)
|
self.__subEdges[1].vertices = [self.edgeVertex, self.vertices[1]]
|
||||||
|
return self.__subEdges
|
||||||
def __getEdgeVertex(self):
|
subEdges = property(fget=__getSubEdges)
|
||||||
'''
|
|
||||||
Set each edge vertices to be the average of the two neighboring
|
def __getEdgeVertex(self):
|
||||||
face vertices and its two original end vertices.
|
'''
|
||||||
'''
|
Set each edge vertices to be the average of the two neighboring
|
||||||
if not self.__edgeVertex:
|
face vertices and its two original end vertices.
|
||||||
# two neighboring face vertices:
|
'''
|
||||||
neighboringFaceVertices = [face.centroid for face in self.faces]
|
if not self.__edgeVertex:
|
||||||
neighboringFaceVertices.extend(self.vertices)
|
# two neighboring face vertices:
|
||||||
xs = [vertex.x for vertex in neighboringFaceVertices]
|
neighboringFaceVertices = [face.centroid for face in self.faces]
|
||||||
ys = [vertex.y for vertex in neighboringFaceVertices]
|
neighboringFaceVertices.extend(self.vertices)
|
||||||
zs = [vertex.z for vertex in neighboringFaceVertices]
|
xs = [vertex.x for vertex in neighboringFaceVertices]
|
||||||
x = sum(xs)/len(xs)
|
ys = [vertex.y for vertex in neighboringFaceVertices]
|
||||||
y = sum(ys)/len(ys)
|
zs = [vertex.z for vertex in neighboringFaceVertices]
|
||||||
z = sum(zs)/len(zs)
|
x = sum(xs)/len(xs)
|
||||||
self.__edgeVertex = Vertex(x, y, z)
|
y = sum(ys)/len(ys)
|
||||||
self.__edgeVertex.edges.extend(self.__subEdges)
|
z = sum(zs)/len(zs)
|
||||||
return self.__edgeVertex
|
self.__edgeVertex = Vertex(x, y, z)
|
||||||
edgeVertex = property(fget=__getEdgeVertex)
|
self.__edgeVertex.edges.extend(self.__subEdges)
|
||||||
|
return self.__edgeVertex
|
||||||
def __averageVertices(self, vertices):
|
edgeVertex = property(fget=__getEdgeVertex)
|
||||||
|
|
||||||
return
|
def __averageVertices(self, vertices):
|
||||||
|
|
||||||
class Face(object):
|
return
|
||||||
'''
|
|
||||||
A face is a closed set of edges, in which a triangle face has three edges, and a quad face has four edges.
|
class Face(object):
|
||||||
'''
|
'''
|
||||||
def __init__(self):
|
A face is a closed set of edges, in which a triangle face has three edges, and a quad face has four edges.
|
||||||
self.edges = []
|
'''
|
||||||
self.__centroid = None
|
def __init__(self):
|
||||||
self.__interiorEdges = []
|
self.edges = []
|
||||||
self.__subFaces = []
|
self.__centroid = None
|
||||||
|
self.__interiorEdges = []
|
||||||
def __getCentroid(self):
|
self.__subFaces = []
|
||||||
if not self.__centroid:
|
|
||||||
# gather all face vertex coords
|
def __getCentroid(self):
|
||||||
faceVertices = list(set([vertex for edge in self.edges for vertex in edge.vertices]))
|
if not self.__centroid:
|
||||||
xs = [vertex.x for vertex in faceVertices]
|
# gather all face vertex coords
|
||||||
ys = [vertex.y for vertex in faceVertices]
|
faceVertices = list(set([vertex for edge in self.edges for vertex in edge.vertices]))
|
||||||
zs = [vertex.z for vertex in faceVertices]
|
xs = [vertex.x for vertex in faceVertices]
|
||||||
|
ys = [vertex.y for vertex in faceVertices]
|
||||||
# average each vertex component
|
zs = [vertex.z for vertex in faceVertices]
|
||||||
x = sum(xs) / len(xs)
|
|
||||||
y = sum(ys) / len(ys)
|
# average each vertex component
|
||||||
z = sum(zs) / len(zs)
|
x = sum(xs) / len(xs)
|
||||||
|
y = sum(ys) / len(ys)
|
||||||
self.__centroid = Vertex(x, y, z)
|
z = sum(zs) / len(zs)
|
||||||
return self.__centroid
|
|
||||||
centroid = property(fget=__getCentroid)
|
self.__centroid = Vertex(x, y, z)
|
||||||
|
return self.__centroid
|
||||||
def __getSubFaces(self):
|
centroid = property(fget=__getCentroid)
|
||||||
self.__setupSubDivisions()
|
|
||||||
return self.__subFaces
|
def __getSubFaces(self):
|
||||||
subFaces = property(fget=__getSubFaces)
|
self.__setupSubDivisions()
|
||||||
|
return self.__subFaces
|
||||||
def __getInteriorEdges(self):
|
subFaces = property(fget=__getSubFaces)
|
||||||
self.__setupSubDivisions()
|
|
||||||
return self.__interiorEdges
|
def __getInteriorEdges(self):
|
||||||
interiorEdges = property(fget=__getInteriorEdges )
|
self.__setupSubDivisions()
|
||||||
|
return self.__interiorEdges
|
||||||
def __setupSubDivisions(self):
|
interiorEdges = property(fget=__getInteriorEdges )
|
||||||
'''
|
|
||||||
v0 ev0 v1
|
def __setupSubDivisions(self):
|
||||||
*------e0-----*
|
'''
|
||||||
| | |
|
v0 ev0 v1
|
||||||
| | |
|
*------e0-----*
|
||||||
ev3 e|11----f5----e|1 ev1
|
| | |
|
||||||
| | |
|
| | |
|
||||||
| | |
|
ev3 e|11----f5----e|1 ev1
|
||||||
*------e2-----*
|
| | |
|
||||||
v3 ev2 v2
|
| | |
|
||||||
'''
|
*------e2-----*
|
||||||
if not self.__subFaces:
|
v3 ev2 v2
|
||||||
# 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
|
if not self.__subFaces:
|
||||||
self.__subFaces = [Face() for edge in self.edges]
|
# 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
|
||||||
if not self.__interiorEdges:
|
self.__subFaces = [Face() for edge in self.edges]
|
||||||
# set up empty edge objects to be filled below
|
|
||||||
self.__interiorEdges = [Edge() for edge in self.edges]
|
if not self.__interiorEdges:
|
||||||
|
# set up empty edge objects to be filled below
|
||||||
# each interior edge connects the exterior edge vertex (mid-point) to the faceVertex (centroid)
|
self.__interiorEdges = [Edge() for edge in self.edges]
|
||||||
for index in range(len(self.edges)):
|
|
||||||
prevIndex = (index - 1) % len(self.edges)
|
# each interior edge connects the exterior edge vertex (mid-point) to the faceVertex (centroid)
|
||||||
nextIndex = (index + 1) % len(self.edges)
|
for index in range(len(self.edges)):
|
||||||
|
prevIndex = (index - 1) % len(self.edges)
|
||||||
# end vertices are face centroid and currEdge edgeVertex
|
nextIndex = (index + 1) % len(self.edges)
|
||||||
self.__interiorEdges[index].vertices = [self.edges[index].edgeVertex,
|
|
||||||
self.centroid]
|
# end vertices are face centroid and currEdge edgeVertex
|
||||||
|
self.__interiorEdges[index].vertices = [self.edges[index].edgeVertex,
|
||||||
# wing edges are the current edge's subEdges (ordered same as vertex order) and the prev and next interior edges
|
self.centroid]
|
||||||
self.__interiorEdges[index].edges = [self.edges[index].subEdges[0],
|
|
||||||
self.edges[index].subEdges[1],
|
# wing edges are the current edge's subEdges (ordered same as vertex order) and the prev and next interior edges
|
||||||
self.__interiorEdges[prevIndex],
|
self.__interiorEdges[index].edges = [self.edges[index].subEdges[0],
|
||||||
self.__interiorEdges[nextIndex]]
|
self.edges[index].subEdges[1],
|
||||||
|
self.__interiorEdges[prevIndex],
|
||||||
# edge faces are the new subFaces (current and next faces), the current will be define below
|
self.__interiorEdges[nextIndex]]
|
||||||
# and the next will be defined on the next iteration (or already defined on the last iteration)
|
|
||||||
self.__interiorEdges[index].faces = [self.__subFaces[index],
|
# edge faces are the new subFaces (current and next faces), the current will be define below
|
||||||
self.__subFaces[nextIndex]]
|
# and the next will be defined on the next iteration (or already defined on the last iteration)
|
||||||
|
self.__interiorEdges[index].faces = [self.__subFaces[index],
|
||||||
# now reference the current edge back into the faces,
|
self.__subFaces[nextIndex]]
|
||||||
# and the edge.subEdges, and the edge.edgeVertex
|
|
||||||
|
# now reference the current edge back into the faces,
|
||||||
# current subFace (same index as current interior edge)
|
# and the edge.subEdges, and the edge.edgeVertex
|
||||||
# set its edges to reference the same edges used to setup the interior edge
|
|
||||||
# order will be pretty important on these steps...
|
# current subFace (same index as current interior edge)
|
||||||
self.__subFaces[index].edges = [self.edges[index].subEdges[0],
|
# set its edges to reference the same edges used to setup the interior edge
|
||||||
self.__interiorEdges[index],
|
# order will be pretty important on these steps...
|
||||||
self.__interiorEdges[prevIndex],
|
self.__subFaces[index].edges = [self.edges[index].subEdges[0],
|
||||||
self.edges[prevIndex].subEdges[1]]
|
self.__interiorEdges[index],
|
||||||
|
self.__interiorEdges[prevIndex],
|
||||||
# just set one of the vertex edges, the other belongs to another face and will get added when that face is run
|
self.edges[prevIndex].subEdges[1]]
|
||||||
self.edges[index].edgeVertex.edges.append(self.__interiorEdges[index])
|
|
||||||
|
# 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].subEdges[0].faces.append(self.__subFaces[index])
|
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):
|
self.edges[index].subEdges[0].faces.append(self.__subFaces[index])
|
||||||
'''
|
|
||||||
Face splitting should happend on the polygon level(?). It doesn't make sense to split just one face since
|
class Polygon(object):
|
||||||
it needs to average vertices with all adjoinging faces
|
'''
|
||||||
'''
|
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):
|
'''
|
||||||
self.vertices = []
|
|
||||||
self.edges = []
|
def __init__(self, v=None, e=None, f=None):
|
||||||
self.faces = []
|
self.vertices = v or []
|
||||||
|
self.edges = e or []
|
||||||
def catmullClarkRefine(self):
|
self.faces = f or []
|
||||||
'''
|
|
||||||
For each face, add a face vertex
|
def __unicode__(self):
|
||||||
Set each face vertex to be the centroid of all original vertices for the respective face.
|
d = {
|
||||||
For each edge, add an edge vertex.
|
'vertices': self.vertices,
|
||||||
Set each edge vertex to be the average of the two neighbouring face vertices and its two original endvertices.
|
'edges': self.edges,
|
||||||
For each face vertex, add an edge for every edge of the face, connecting the face vertex to each edge vertex for the face.
|
'faces': self.faces,
|
||||||
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
|
}
|
||||||
'''
|
return pprint.pformat(d)
|
||||||
|
|
||||||
|
__str__ = __unicode__
|
||||||
|
__repr__ = __unicode__
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# 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)
|
|
||||||
|
|
||||||
newVertices = []
|
|
||||||
for vertex in self.vertices:
|
|
||||||
faceVertices = []
|
|
||||||
edgeMidPoints = []
|
|
||||||
for edge in vertex.edges:
|
|
||||||
print edge.midPoint
|
|
||||||
edgeMidPoints.append(edge.midPoint)
|
|
||||||
for face in edge.faces:
|
|
||||||
print face.centroid
|
|
||||||
faceVertices.append(face.centroid)
|
|
||||||
|
|
||||||
print edgeMidPoints
|
|
||||||
|
|
||||||
print vertex
|
|
||||||
print faceVertices
|
|
||||||
f = sum(list(set(faceVertices)), Vertex())/len(list(set(faceVertices)))
|
|
||||||
# print f
|
|
||||||
r = sum(list(set(edgeMidPoints)), Vertex())/len(list(set(edgeMidPoints)))
|
|
||||||
# print r
|
|
||||||
p = vertex
|
|
||||||
# print p
|
|
||||||
n = len(vertex.edges)
|
|
||||||
# print n
|
|
||||||
v = (f + 2.0 * r + (n - 3.0) * p) / n
|
|
||||||
# print v
|
|
||||||
# print v
|
|
||||||
newVertices.append(v)
|
|
||||||
|
|
||||||
for vertex, newVertex in zip(self.vertices, newVertices):
|
|
||||||
vertex.x = newVertex.x
|
|
||||||
vertex.y = newVertex.y
|
|
||||||
vertex.z = newVertex.z
|
|
||||||
# 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 = 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)
|
|
||||||
return p
|
|
||||||
|
|
||||||
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))
|
|
||||||
|
|
||||||
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[6], 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[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[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]]
|
|
||||||
|
|
||||||
# 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
|
|
||||||
p = Polygon()
|
|
||||||
p.vertices = v
|
|
||||||
p.edges = e
|
|
||||||
p.faces = f
|
|
||||||
return p
|
|
||||||
|
|
||||||
polygon = createPolygon()
|
|
||||||
newPolygon = polygon.catmullClarkRefine()
|
|
||||||
|
|
||||||
from numpy import *
|
|
||||||
import pylab
|
|
||||||
import mpl_toolkits.mplot3d.axes3d as p3
|
|
||||||
|
|
||||||
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()
|
|
0
surf/subd/__init__.py
Normal file
0
surf/subd/__init__.py
Normal file
70
surf/subd/cc.py
Normal file
70
surf/subd/cc.py
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
from surf.geometry import *
|
||||||
|
|
||||||
|
def refine(poly):
|
||||||
|
'''
|
||||||
|
For each face, add a face vertex
|
||||||
|
Set each face vertex to be the centroid of all original vertices for the respective face.
|
||||||
|
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.
|
||||||
|
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
|
||||||
|
'''
|
||||||
|
|
||||||
|
|
||||||
|
# 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 poly.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)
|
||||||
|
|
||||||
|
newVertices = []
|
||||||
|
for vertex in poly.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
|
||||||
|
newVertices.append(v)
|
||||||
|
|
||||||
|
for vertex, newVertex in zip(poly.vertices, newVertices):
|
||||||
|
vertex.x = newVertex.x
|
||||||
|
vertex.y = newVertex.y
|
||||||
|
vertex.z = newVertex.z
|
||||||
|
# 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 = 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)
|
||||||
|
return Polygon(vertices, edges, faces)
|
84
surf/util.py
Normal file
84
surf/util.py
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
from surf.geometry import Vertex, Edge, Face, Polygon
|
||||||
|
|
||||||
|
def cube():
|
||||||
|
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[6], 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[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[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]]
|
||||||
|
|
||||||
|
# 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
|
||||||
|
return Polygon(v, e, f)
|
24
test/test00.py
Normal file
24
test/test00.py
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
from surf.util import cube
|
||||||
|
from surf.subd import cc
|
||||||
|
polygon = cube()
|
||||||
|
refined_poly = cc.refine(polygon)
|
||||||
|
|
||||||
|
print polygon
|
||||||
|
print refined_poly
|
||||||
|
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# import pylab
|
||||||
|
# import mpl_toolkits.mplot3d.axes3d as p3
|
||||||
|
#
|
||||||
|
# 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()
|
11
test/test01.py
Normal file
11
test/test01.py
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
from __future__ import division
|
||||||
|
from surf.geometry import Vertex
|
||||||
|
|
||||||
|
v1 = Vertex(0.5, 0.25, 1/3.0)
|
||||||
|
v2 = Vertex(1, 1, 1)
|
||||||
|
|
||||||
|
print v1, v2, (v1 + v2) / 2
|
||||||
|
print v1, v2, (v1 + v2) / 2.0
|
||||||
|
|
||||||
|
v = sum((v1, v2), Vertex()) / len((v1, v2))
|
||||||
|
print v, type(v)
|
Loading…
Reference in New Issue
Block a user