a playground adding surface subdivision methods to scipy
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

#### 240 lines 7.2 KiB Raw Blame History

 `from __future__ import division` `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:` ` - Face-vertex` ` - Winged-edge` ` - Half-edge` ` - Quad-edge` ` - Corner-tables` ` - Vertex-vertex` ` - Face-vertex` `We have chosen to use a winged-edge style mesh for our purpopses.` `'''` `__all__ = [` ` 'Vertex',` ` 'PolygonMesh',` `]` `def cross(a, b):` ` i = a.y * b.z - a.z * b.y` ` j = a.z * b.x - a.x * b.z` ` k = a.x * b.y - a.y * b.x` ` return Vertex(i, j, k)` `def centroid(verts):` ` xs = [v.x for v in verts]` ` ys = [v.y for v in verts]` ` zs = [v.z for v in verts]` ` # average each vertex component` ` x = sum(xs) / len(xs)` ` y = sum(ys) / len(ys)` ` z = sum(zs) / len(zs)` ` return Vertex(x, y, z)` `class Vertex(list):` ` '''` ` A vertex is a position along with other information such as color, normal` ` vector and texture coordinates.` ` For the sake of our algorithms, we will only worry about the (x, y, z)` ` float positions. Eventually we will also keep track of weights.` ` '''` ` def __init__(self, *args, **kwargs):` ` """ The constructor supports the following formats:` ` >>> Vertex([3, 1, 4])` ` V[3, 1, 4]` ` >>> Vertex(2, 7, 2)` ` V[2, 7, 2]` ` >>> Vertex()` ` V[0, 0, 0]` ` """` ` if len(args) == 0:` ` a = [[0, 0, 0]]` ` a.extend(args)` ` super(Vertex, self).__init__(*a, **kwargs)` ` elif len(args) == 1:` ` if len(args) != 3:` ` raise TypeError("Only support 3D at the moment")` ` super(Vertex, self).__init__(*args, **kwargs)` ` elif len(args) == 3:` ` super(Vertex, self).__init__(args, **kwargs)` ` @property` ` def x(self):` ` return self` ` @property` ` def y(self):` ` return self` ` @property` ` def z(self):` ` return self` ` def __eq__(self, other):` ` if(self.x == other.x and self.y == other.y and self.z == other.z):` ` return True` ` else:` ` return False` ` 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)` ` __iadd__ = __add__` ` def __radd__(self, other):` ` return other + self` ` def __mul__(self, other):` ` if isinstance(other, Vertex):` ` return cross(self, other)` ` elif isinstance(other, (float, int)):` ` return Vertex(self.x * other, self.y * other, self.z * other)` ` else:` ` raise TypeError("{0} has an unexpected type: {1}".format(` ` other, type(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)` ` __truediv__ = __div__` ` def __neg__(self):` ` return Vertex(-self.x, -self.y, -self.z)` ` def __unicode__(self):` ` return 'V{0}'.format([self.x, self.y, self.z])` ` __str__ = __unicode__` ` __repr__ = __unicode__` `class PolygonMesh(object):` ` '''` ` A polygon object is a collection of the following lists:` ` - a list containing the 3-space vertex information` ` - a list containing the edge indices ([0, 1] means first and second` ` elements of the vertices list)` ` - a list of the faces (indices of the vertices in a given face)` ` - connectivity information (eventually will be calculated given the verts,` ` edges, and faces)` ` '''` ` def __init__(self, vertices, faces, edges=None, **kwargs):` ` self.vertices = [Vertex(*v) for v in vertices]` ` self.faces = faces` ` self.edges = edges` ` # the strategy for the following members involves lazy-instantiating` ` # them if they weren't passing them in:` ` self._faces_for_edge = kwargs.get('faces for edge', None)` ` self._edges_for_face = kwargs.get('edges for face', None)` ` self._edges_for_vert = kwargs.get('edges for vert', None)` ` self._faces_for_vert = kwargs.get('faces for vert', None)` ` self._edge_map = None` ` @property` ` def faces_for_edge(self):` ` """returns a list of face indices for a given edge index.` ` Intended to be used in the following way:` ` >>> # vs, es, fs, ffe, eff, efv, ffv from blender or similar` ` >>> mesh = Polygon(vs, es, fs, ffe, eff, efv, ffv)` ` >>> mesh.faces_for_edge` ` [0, 1]` ` >>> [self.face[i] for i in mesh.faces_for_edge]` ` [[...], [...], ...]` ` where 0 and 1 are indices into the face list` ` """` ` if self._faces_for_edge is None:` ` self._set_up_face_edge_connectivity()` ` return self._faces_for_edge` ` @property` ` def edges_for_face(self):` ` """returns a list of edge indices for a given face index."""` ` if self._edges_for_face is None:` ` self._set_up_face_edge_connectivity()` ` return self._edges_for_face` ` @property` ` def edges_for_vert(self):` ` """returns a list of edge indices for a given vertex index."""` ` if self._edges_for_vert is None:` ` self._edges_for_vert = [[] for i in range(len(self.vertices))]` ` for i, edge in enumerate(self.edges):` ` for vid in edge:` ` self._edges_for_vert[vid].append(i)` ` return self._edges_for_vert` ` @property` ` def faces_for_vert(self):` ` """returns a list of face indices for a given vert index."""` ` if self._faces_for_vert is None:` ` self._faces_for_vert = [[] for i in range(len(self.vertices))]` ` for i, face in enumerate(self.faces):` ` for vid in face:` ` self._faces_for_vert[vid].append(i)` ` return self._faces_for_vert` ` def _make_edge_map(self):` ` self._edge_map = {}` ` for i, edge in enumerate(self.edges):` ` self._edge_map[tuple(sorted(edge))] = i` ` def _set_up_face_edge_connectivity(self):` ` if self._edge_map is None: ` ` self._make_edge_map()` ` self._edges_for_face = [[] for i in range(len(self.faces))]` ` self._faces_for_edge = [[] for i in range(len(self.edges))]` ` for face_id, face in enumerate(self.faces):` ` for i in range(len(face) -1):` ` cur_edge = tuple(sorted([face[i], face[i+1]]))` ` edge_id = self._edge_map[cur_edge]` ` self._edges_for_face[face_id].append(edge_id)` ` self._faces_for_edge[edge_id].append(face_id)` ` cur_edge = tuple(sorted([face[-1], face]))` ` edge_id = self._edge_map[cur_edge]` ` self._edges_for_face[face_id].append(edge_id)` ` self._faces_for_edge[edge_id].append(face_id)` ` def __unicode__(self):` ` # TODO: perhaps also add connectivity here?` ` d = {` ` 'vertices': self.vertices,` ` 'edges': self.edges,` ` 'faces': self.faces,` ` 'faces_for_vert': self.faces_for_vert,` ` 'edges_for_vert': self.edges_for_vert,` ` }` ` return json.dumps(d)` ` __str__ = __unicode__` ` __repr__ = __unicode__` ` def centroid(self, vert_ids):` ` verts = [self.vertices[vid] for vid in vert_ids]` ``` return centroid(verts) ``` ``` ```