surfaces/surf/subd/cc.py

211 lines
7.5 KiB
Python

from surf.geometry import Vertex, Polygon
def mid_point(self):
vertex_objs = [self.polygon.vertices[v_id] for v_id in self.vertices]
return sum(vertex_objs, Vertex()) / len(self.vertices)
def sub_edges(self):
temp_p = Polygon()
temp_p.edges = [Edge(), Edge()]
temp_p.vertices =
sub_edges[0].vertices = [self.vertices[0], self.edge_vertex]
sub_edges[1].vertices = [self.edge_vertex, self.vertices[1]]
return self.__sub_edges
def edge_vertex(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:
neighboringFaceVertices = [p.faces[f_id].centroid for f_id 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.__edge_vertex = Vertex(x, y, z)
self.__edge_vertex.edges.extend(self.__sub_edges)
return self.__edge_vertex
def centroid(self):
if not self.__centroid:
# gather all face vertex coords
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]
# 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
def sub_faces(self):
self.__setupSubDivisions()
return self.__sub_faces
def interior_edges(self):
self.__setupSubDivisions()
return self.__interior_edges
def __setupSubDivisions(self):
'''
v0 ev0 v1
*------e0-----*
| | |
| | |
ev3 e|11----f5----e|1 ev1
| | |
| | |
*------e2-----*
v3 ev2 v2
'''
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:
# set up empty edge objects to be filled below
self.__interior_edges = [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 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]
]
# now reference the current edge back into the faces,
# and the edge.sub_edges, and the edge.edge_vertex
# 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.__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])
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.sub_faces:
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:
face_vertices = []
edge_mid_points = []
for edge in vertex.edges:
edge_mid_points.append(edge.mid_point)
for face in edge.faces:
face_vertices.append(face.centroid)
f = sum(list(
set(face_vertices)), Vertex()) / len(list(set(face_vertices)))
r = sum(list(
set(edge_mid_points)), Vertex()) / len(list(set(edge_mid_points)))
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)