def constructTetrahedron(cx,cy,cz,side): """ Constructs a tetrahedron mesh. Arguments: ---------- cx, cy, cz : float The center point of the tetrahedron side : float The edge length of the tetrahedron """ mesh = Mesh() coord = 1 / math.sqrt(2) mesh.vertices = [Vertex(+1, 0, -coord), Vertex(-1, 0, -coord), Vertex(0, +1, +coord), Vertex(0, -1, +coord)] for i in range(len(mesh.vertices)): mesh.vertices[i] = vec.scale(mesh.vertices[i], side / 2) mesh.vertices[i] = vec.add(mesh.vertices[i], Vertex(cx, cy, cz)) f1 = Face([mesh.vertices[0], mesh.vertices[1], mesh.vertices[2]]) f2 = Face([mesh.vertices[1], mesh.vertices[0], mesh.vertices[3]]) f3 = Face([mesh.vertices[2], mesh.vertices[3], mesh.vertices[0]]) f4 = Face([mesh.vertices[3], mesh.vertices[2], mesh.vertices[1]]) mesh.faces = [f1, f2, f3, f4] return mesh
def offset(mesh,offset=1,doclose=True): newMesh=Mesh() # calculate vertex normals for vertex in mesh.vertices: vertex.vertex = Vertex(0,0,0) vertex.nfaces = 0 for face in mesh.faces: normal = faceUtils.normal(face) for vertex in face.vertices: vertex.vertex.add(normal) vertex.nfaces += 1 for vertex in mesh.vertices: vertex.vertex.scale(offset / vertex.nfaces) vertex.vertex.add(vertex) # create faces for face in mesh.faces: offsetVertices = [] for vertex in face.vertices: offsetVertices.append(vertex.vertex) offsetVertices.reverse() newFace = Face(offsetVertices) newMesh.faces.append(newFace) newMesh.faces.append(face) # create sides if doclose: for edge in mesh.edges: if edge.face1 == None or edge.face2 == None: offsetVertices = [edge.v1, edge.v2, edge.v2.vertex, edge.v1.vertex] if edge.face2 == None: offsetVertices.reverse() newFace = Face(offsetVertices) newMesh.faces.append(newFace) newMesh.updateAdjacencies() return newMesh
def splitRelMultiple(face, direction, splits): sA = [] sA.append(face.vertices[direction]) lA = face.vertices[direction + 1] sB = [] sB.append(face.vertices[direction + 3]) lB = face.vertices[(direction + 2) % len(face.vertices)] for i in range(len(splits)): sA.append(vec.betweenRel(sA[0], lA,splits[i])) sB.append(vec.betweenRel(sB[0], lB,splits[i])) sA.append(lA) sB.append(lB) result = [] for i in range(len(splits) + 1): if(dir == 1): f = Face([sB[i], sA[i], sA[i+1], sB[i+1]]) faceUtils.copyProperties(face, f) result.append(f) else: f = Face([sB[i], sB[i+1], sA[i+1], sA[i]]) faceUtils.copyProperties(face, f) result.append(f) return result
def extrudeTapered(face, height=0.0, fraction=0.5,doCap=True): """ Extrudes the face tapered like a window by creating an offset face and quads between every original edge and the corresponding new edge. Arguments: ---------- face : mola.core.Face The face to be extruded height : float The distance of the new face to the original face, default 0 fraction : float The relative offset distance, 0: original vertex, 1: center point default 0.5 (halfway) """ center_vertex = faceUtils.center(face) normal = faceUtils.normal(face) scaled_normal = vec.scale(normal, height) # calculate new vertex positions new_vertices = [] for i in range(len(face.vertices)): n1 = face.vertices[i] betw = vec.subtract(center_vertex, n1) betw = vec.scale(betw, fraction) nn = vec.add(n1, betw) nn = vec.add(nn, scaled_normal) new_vertices.append(nn) new_faces = [] # create the quads along the edges num = len(face.vertices) for i in range(num): n1 = face.vertices[i] n2 = face.vertices[(i + 1) % num] n3 = new_vertices[(i + 1) % num] n4 = new_vertices[i] new_face = Face([n1,n2,n3,n4]) new_faces.append(new_face) # create the closing cap face if doCap: cap_face = Face(new_vertices) new_faces.append(cap_face) for new_face in new_faces: faceUtils.copyProperties(face,new_face) return new_faces
def constructTorus(ringRadius, tubeRadius, ringN = 16, tubeN = 16): """ Constructs a torus mesh. Arguments: ---------- ringRadius : float the big radius of the axis tubeRadius : float radius of the the tube along the axis ringN : int resolution along the ring tubeN : int resolution along the tube """ mesh = Mesh() theta = 2 * math.pi / ringN phi = 2 * math.pi / tubeN for i in range (ringN): for j in range (tubeN): mesh.vertices.append(_getTorusVertex(ringRadius, tubeRadius, phi * j, theta * i)) for i in range(ringN): ii = (i + 1) % ringN for j in range(tubeN): jj = (j + 1) % tubeN a = i * tubeN + j b = ii * tubeN + j c = ii * tubeN + jj d = i * tubeN + jj f = Face([mesh.vertices[k] for k in [a, b, c, d]]) mesh.faces.append(f) return mesh
def splitGrid(face,nU,nV): """ splits a triangle, quad or a rectangle into a regular grid """ if len(face.vertices) > 4: print('too many vertices') return face if len(face.vertices) == 4: vsU1 = _getVerticesBetween(face.vertices[0], face.vertices[1], nU) vsU2 = _getVerticesBetween(face.vertices[3], face.vertices[2], nU) gridVertices = [] for u in range(len(vsU1)): gridVertices.append(_getVerticesBetween(vsU1[u], vsU2[u], nV)) faces = [] for u in range(len(vsU1) - 1): vs1 = gridVertices[u] vs2 = gridVertices[u + 1] for v in range(len(vs1) - 1): #f = Face([vs1[v], vs1[v + 1], vs2[v + 1], vs2[v]]) f = Face([vs1[v], vs2[v], vs2[v + 1], vs1[v + 1]]) faceUtils.copyProperties(face, f) faces.append(f) return faces if len(face.vertices) == 3: vsU1 = _getVerticesBetween(face.vertices[0], face.vertices[1], nU) vsU2 = _getVerticesBetween(face.vertices[0], face.vertices[2], nU) gridVertices = [] for u in range(1, len(vsU1)): gridVertices.append(_getVerticesBetween(vsU1[u], vsU2[u], nV)) faces = [] # triangles v0 = face.vertices[0] vs1 = gridVertices[0] for v in range(len(vs1) - 1): f = Face([v0,vs1[v],vs1[v + 1]]) faceUtils.copyProperties(face, f) faces.append(f) for u in range(len(gridVertices) - 1): vs1 = gridVertices[u] vs2 = gridVertices[u + 1] for v in range(len(vs1) - 1): f = Face([vs1[v],vs1[v + 1], vs2[v + 1], vs2[v]]) faceUtils.copyProperties(face, f) faces.append(f) return faces
def constructDodecahedron(cx,cy,cz,radius): """ Constructs a dodecaheron mesh. Arguments: ---------- cx, cy, cz : float The center point of the dodecaheron radius : float The radius of the containing sphere """ mesh = Mesh() phi = (1 + 5 ** 0.5) / 2 mesh.vertices = [Vertex( 1, 1, 1), Vertex( 1, 1,-1), Vertex( 1,-1, 1), Vertex( 1,-1,-1), Vertex(-1, 1, 1), Vertex(-1, 1,-1), Vertex(-1,-1, 1), Vertex(-1,-1,-1), Vertex(0,-phi,-1/phi), Vertex(0,-phi, 1/phi), Vertex(0, phi,-1/phi), Vertex(0, phi, 1/phi), Vertex(-phi,-1/phi,0), Vertex(-phi, 1/phi,0), Vertex( phi,-1/phi,0), Vertex( phi, 1/phi,0), Vertex(-1/phi,0,-phi), Vertex( 1/phi,0,-phi), Vertex(-1/phi,0, phi), Vertex( 1/phi,0, phi)] for i in range(len(mesh.vertices)): mesh.vertices[i] = vec.scale(mesh.vertices[i], radius) mesh.vertices[i] = vec.add(mesh.vertices[i], Vertex(cx,cy,cz)) indices = [2,9,6,18,19, 4,11,0,19,18, 18,6,12,13,4, 19,0,15,14,2, 4,13,5,10,11, 14,15,1,17,3, 1,15,0,11,10, 3,17,16,7,8, 2,14,3,8,9, 6,9,8,7,12, 1,10,5,16,17, 12,7,16,5,13] for i in range(0, len(indices), 5): f = Face([mesh.vertices[indices[i]], mesh.vertices[indices[i + 1]], mesh.vertices[indices[i + 2]], mesh.vertices[indices[i + 3]], mesh.vertices[indices[i + 4]]]) mesh.faces.append(f) return mesh
def _collectNewFaces(mesh): newMesh=Mesh() for face in mesh.faces: v1 = face.vertices[-2] v2 = face.vertices[-1] for v3 in face.vertices: edge1 = mesh.getEdgeAdjacentToVertices(v1,v2) edge2 = mesh.getEdgeAdjacentToVertices(v2,v3) if (edge1 != None) and (edge2!= None): newFace = Face([edge1.vertex, v2.vertex, edge2.vertex, face.vertex]) newFace.color = face.color newFace.group = face.group newMesh.faces.append(newFace) v1 = v2 v2 = v3 newMesh.updateAdjacencies() return newMesh
def splitFrame(face, w): """ Creates an offset frame with quad corners. Works only with convex shapes. Arguments: ---------- face : mola.core.Face The face to be split w : float The width of the offset frame """ faces = [] innerVertices = [] for i in range(len(face.vertices)): if(i == 0): vp = face.vertices[len(face.vertices)-1] else: vp = face.vertices[i - 1] v = face.vertices[i] vn = face.vertices[(i + 1) % len(face.vertices)] vnn = face.vertices[(i + 2) % len(face.vertices)] th1 = vec.angleTriangle(vp,v,vn) th2 = vec.angleTriangle(v,vn,vnn) w1 = w / math.sin(th1) w2 = w / math.sin(th2) vs1 = _getVerticesFrame(v, vn, w1, w2) vs2 = _getVerticesFrame(_getVerticesFrame(vp, v, w1, w1)[2], _getVerticesFrame(vn, vnn, w2, w2)[1], w1, w2) innerVertices.append(vs2[1]) f1 = Face([vs1[0], vs2[0], vs2[1], vs1[1]]) faceUtils.copyProperties(face, f1) f2 = Face([vs1[1], vs2[1], vs2[2], vs1[2]]) faceUtils.copyProperties(face, f2) faces.extend([f1, f2]) fInner = Face(innerVertices) faceUtils.copyProperties(face, fInner) faces.append(fInner) return faces
def constructBox(x1,y1,z1,x2,y2,z2): """ Creates and returns a mesh box with six quad faces. Arguments: ---------- x1,y1,z1 : float The coordinates of the bottom left front corner x2,y2,z2 : float The coordinates of the top right back corner """ mesh = Mesh() v1 = Vertex(x1, y1, z1) v2 = Vertex(x1, y2, z1) v3 = Vertex(x2, y2, z1) v4 = Vertex(x2, y1, z1) v5 = Vertex(x1, y1, z2) v6 = Vertex(x1, y2, z2) v7 = Vertex(x2, y2, z2) v8 = Vertex(x2, y1, z2) mesh.vertices = [v1, v2, v3, v4, v5, v6, v7, v8] f1 = Face([v1, v2, v3, v4]) f2 = Face([v8, v7, v6, v5]) f3 = Face([v4, v3, v7, v8]) f4 = Face([v3, v2, v6, v7]) f5 = Face([v2, v1, v5, v6]) f6 = Face([v1, v4, v8, v5]) mesh.faces = [f1, f2, f3, f4, f5, f6] return mesh
def splitRelFreeQuad(face, indexEdge, split1, split2): """ Splits a quad in two new quads through the points specified by relative position along the edge. Arguments: ---------- face : mola.core.Face The face to be extruded indexEdge : int direction of split, 0: 0->2, 1: 1->3 split1, split2 : float relative position of split on each edge (0..1) """ # only works with quads, therefore return original face if triangular if len(face.vertices) != 4: return face # constrain indexEdge to be either 0 or 1 indexEdge = indexEdge%2 indexEdge1 = (indexEdge + 1) % len(face.vertices) indexEdge2 = (indexEdge + 2) % len(face.vertices) indexEdge3 = (indexEdge + 3) % len(face.vertices) p1 = vec.betweenRel(face.vertices[indexEdge], face.vertices[indexEdge1], split1) p2 = vec.betweenRel(face.vertices[indexEdge2 ], face.vertices[indexEdge3], split2) faces = [] if indexEdge == 0: f1 = Face([face.vertices[0], p1, p2, face.vertices[3]]) f2 = Face([p1, face.vertices[1], face.vertices[2], p2]) faceUtils.copyProperties(face, f1) faceUtils.copyProperties(face, f2) faces.extend([f1, f2]) elif indexEdge == 1: f1 = Face([face.vertices[0], face.vertices[1], p1, p2]) f2 = Face([p2, p1, face.vertices[2], face.vertices[3]]) faceUtils.copyProperties(face,f1) faceUtils.copyProperties(face,f2) faces.extend([f1, f2]) return faces
def extrude(face, height=0.0, capBottom=False, capTop=True): """ Extrudes the face straight by distance height. Arguments: ---------- face : mola.core.Face The face to be extruded height : float The extrusion distance, default 0 capBottom : bool Toggle if bottom face (original face) should be created, default False capTop : bool Toggle if top face (extrusion face) should be created, default True """ normal=faceUtils.normal(face) normal=vec.scale(normal,height) # calculate vertices new_vertices=[] for i in range(len(face.vertices)): new_vertices.append(vec.add(face.vertices[i], normal)) # faces new_faces=[] if capBottom: new_faces.append(face) for i in range(len(face.vertices)): i2=i+1 if i2>=len(face.vertices): i2=0 v0=face.vertices[i] v1=face.vertices[i2] v2=new_vertices[i2] v3=new_vertices[i] new_faces.append(Face([v0,v1,v2,v3])) if capTop: new_faces.append(Face(new_vertices)) for new_face in new_faces: faceUtils.copyProperties(face,new_face) return new_faces
def constructSingleFace(vertices): """ Creates and returns a single face mesh from the vertices. Arguments: ---------- vertices : list of mola.core.Vertex The vertices describing the face """ mesh = Mesh() mesh.vertices = vertices mesh.faces = [Face(vertices)] return mesh
def constructCone(z1, z2, radius1, radius2, nSegments, capBottom=True, capTop=True): """ Creates and returns a conic cylinder. """ delaAngle = math.radians(360.0 / nSegments) angle = 0 verticesBottom = [] verticesTop = [] for i in range(nSegments): x1 = radius1 * math.cos(angle) y1 = radius1 * math.sin(angle) verticesBottom.append(Vertex(x1, y1, z1)) x2 = radius2 * math.cos(angle) y2 = radius2 * math.sin(angle) verticesTop.append(Vertex(x2, y2, z2)) angle += delaAngle mesh = Mesh() mesh.vertices.extend(verticesBottom) mesh.vertices.extend(verticesTop) for i in range(nSegments): i2 = (i + 1) % nSegments mesh.faces.append(Face([verticesBottom[i],verticesBottom[i2],verticesTop[i2],verticesTop[i]])) if capBottom: # centerBottom = Vertex(0, 0, z1) # mesh.vertices.append(centerBottom) # for i in range(nSegments): # i2=(i+1)%nSegments # mesh.faces.append(Face([verticesBottom[i2],verticesBottom[i],centerBottom])) mesh.faces.append(Face(list(reversed(verticesBottom)))) if capTop: # centerTop=Vertex(0,0,z2) # mesh.vertices.append(centerTop) # for i in range(nSegments): # i2=(i+1)%nSegments # mesh.faces.append(Face([verticesTop[i],verticesTop[i2],centerTop])) mesh.faces.append(Face(verticesTop)) return mesh
def marchingCubes(nX, nY, nZ, values, iso): mesh = Mesh() nYZ = nY * nZ index = 0 n = [0] * 8 switcher = { 0: lambda: Vertex(x + _v(n[0], n[1], iso), y + 1, z), 1: lambda: Vertex(x + 1, y + _v(n[2], n[1], iso), z), 2: lambda: Vertex(x + _v(n[3], n[2], iso), y, z), 3: lambda: Vertex(x, y + _v(n[3], n[0], iso), z), 4: lambda: Vertex(x + _v(n[4], n[5], iso), y + 1, z + 1), 5: lambda: Vertex(x + 1, y + _v(n[6], n[5], iso), z + 1), 6: lambda: Vertex(x + _v(n[7], n[6], iso), y, z + 1), 7: lambda: Vertex(x, y + _v(n[7], n[4], iso), z + 1), 8: lambda: Vertex(x, y + 1, z + _v(n[0], n[4], iso)), 9: lambda: Vertex(x + 1, y + 1, z + _v(n[1], n[5], iso)), 10: lambda: Vertex(x, y, z + _v(n[3], n[7], iso)), 11: lambda: Vertex(x + 1, y, z + _v(n[2], n[6], iso)) } for x in range(nX - 1): for y in range(nY - 1): for z in range(nZ - 1): caseNumber = 0 index = z + y * nZ + x * nYZ # collecting the values n[0] = values[index + nZ] # 0,1,0 n[1] = values[index + nYZ + nZ] #1,1,0 n[2] = values[index + nYZ] # 1,0,0 n[3] = values[index] # 0,0,0 n[4] = values[index + nZ + 1] # 0,1,1 n[5] = values[index + nYZ + nZ + 1] # 1,1,1 n[6] = values[index + nYZ + 1] # 1,0,1 n[7] = values[index + 1] # 0,0,1 for i in range(7, -1, -1): if n[i] > iso: caseNumber += 1 if i > 0: caseNumber = caseNumber << 1 # collecting the faces offset = caseNumber * 15 for i in range(offset, offset + 15, 3): if _faces[i] > -1: vs = [] for j in range(i, i + 3): v = switcher[_faces[j]]() mesh.vertices.append(v) vs.append(v) if len(vs) == 3: mesh.faces.append(Face(vs)) return mesh
def importOBJ(filename): """Loads a Wavefront OBJ file. """ mesh = Mesh() group = "" for line in open(filename, "r"): if line.startswith('#'): continue values = line.split() if not values: continue if values[0] == 'g': group = values[1] elif values[0] == 'v': v = [float(c) for c in values[1:4]] #v = map(float, values[1:4]) mesh.vertices.append(Vertex(v[0], v[1], v[2])) elif values[0] == 'f': face = Face([]) face.group = group for v in values[1:]: w = v.split('/') vertex = mesh.vertices[int(w[0]) - 1] face.vertices.append(vertex) mesh.faces.append(face) return mesh
def offsetPlanar(face,offsets): newPts = [] for i in range(len(face.vertices)): iP = i - 1 if(iP < 0): iP = len(face.vertices)-1 iN = (i + 1) % len(face.vertices) v0 = face.vertices[iP] v1 = face.vertices[i] v2 = face.vertices[iN] newPts.append(vec.offsetPoint(v0, v1, v2, offsets[iP], offsets[i])) f = Face(newPts) faceUtils.copyProperties(face, f) return f
def splitRoof(face, height): """ Extrudes a pitched roof Arguments: ---------- face : mola.core.Face The face to be extruded height : mola.core.Vertex Th height of the roof """ faces = [] normal = faceUtils.normal(face) normal = vec.scale(normal,height) if len(face.vertices) == 4: ev1 = vec.center(face.vertices[0], face.vertices[1]) ev1 = vec.add(ev1, normal) ev2 = vec.center(face.vertices[2], face.vertices[3]) ev2 = vec.add(ev2, normal) faces.append(Face([face.vertices[0], face.vertices[1], ev1])) faces.append(Face([face.vertices[1], face.vertices[2], ev2, ev1])) faces.append(Face([face.vertices[2], face.vertices[3], ev2])) faces.append(Face([face.vertices[3], face.vertices[0], ev1, ev2])) for f in faces: faceUtils.copyProperties(face,f) return faces elif len(face.vertices) == 3: ev1 = vec.center(face.vertices[0], face.vertices[1]) ev1 = vec.add(ev1, normal) ev2 = vec.center(face.vertices[1], face.vertices[2]) ev2 = vec.add(ev2, normal) faces.append(Face([face.vertices[0], face.vertices[1], ev1])) faces.append(Face([face.vertices[1], ev2, ev1])) faces.append(Face([face.vertices[1], face.vertices[2], ev2])) faces.append(Face([face.vertices[2], face.vertices[0], ev1, ev2])) for f in faces: faceUtils.copyProperties(face, f) return faces return [face]
def splitOffsets(face,offsets): offsetFace = offsetPlanar(face,offsets) nOffsetFaces = 0 for o in offsets: if(abs(o) > 0): nOffsetFaces += 1 faces = [] for i in range(len(face.vertices)): if(abs(offsets[i]) > 0): i2 = (i + 1) % len(face.vertices) f = Face([face.vertices[i], face.vertices[i2], offsetFace.vertices[i2], offsetFace.vertices[i]]) faceUtils.copyProperties(face, f) faces.append(f) faces.append(offsetFace) for f in faces: if(faceUtils.area(f) < 0): f.vertices.reverse() return faces
def getQuadMesh(self, functionIn, functionOut): faces = [] for x in range(self.nX): for y in range(self.nY): for z in range(self.nZ): index = self.getIndex(x, y, z) if functionIn(self.values[index]): # (x,y) (x1,y) (x1,y1) (x,y1) if x == self.nX - 1 or functionOut( self.get_xyz(x + 1, y, z)): v1 = Vertex(x + 1, y, z) v2 = Vertex(x + 1, y + 1, z) v3 = Vertex(x + 1, y + 1, z + 1) v4 = Vertex(x + 1, y, z + 1) faces.append(Face([v1, v2, v3, v4])) if x == 0 or functionOut(self.get_xyz(x - 1, y, z)): v1 = Vertex(x, y + 1, z) v2 = Vertex(x, y, z) v3 = Vertex(x, y, z + 1) v4 = Vertex(x, y + 1, z + 1) faces.append(Face([v1, v2, v3, v4])) if y == self.nY - 1 or functionOut( self.get_xyz(x, y + 1, z)): v1 = Vertex(x + 1, y + 1, z) v2 = Vertex(x, y + 1, z) v3 = Vertex(x, y + 1, z + 1) v4 = Vertex(x + 1, y + 1, z + 1) faces.append(Face([v1, v2, v3, v4])) if y == 0 or functionOut(self.get_xyz(x, y - 1, z)): v1 = Vertex(x, y, z) v2 = Vertex(x + 1, y, z) v3 = Vertex(x + 1, y, z + 1) v4 = Vertex(x, y, z + 1) faces.append(Face([v1, v2, v3, v4])) if z == self.nZ - 1 or functionOut( self.get_xyz(x, y, z + 1)): v1 = Vertex(x, y, z + 1) v2 = Vertex(x + 1, y, z + 1) v3 = Vertex(x + 1, y + 1, z + 1) v4 = Vertex(x, y + 1, z + 1) faces.append(Face([v1, v2, v3, v4])) if z == 0 or functionOut(self.get_xyz(x, y, z - 1)): v1 = Vertex(x, y + 1, z) v2 = Vertex(x + 1, y + 1, z) v3 = Vertex(x + 1, y, z) v4 = Vertex(x, y, z) faces.append(Face([v1, v2, v3, v4])) mesh = Mesh() mesh.faces = faces return mesh
def extrudeToPoint(face, point): """ Extrudes the face to a point by creating a triangular face from each edge to the point. Arguments: ---------- face : mola.core.Face The face to be extruded point : mola.core.Vertex The point to extrude to """ numV = len(face.vertices) faces = [] for i in range(numV): v1 = face.vertices[i] v2 = face.vertices[(i + 1) % numV] f = Face([v1, v2, point]) faceUtils.copyProperties(face, f) faces.append(f) return faces
def constructIcosahedron(cx,cy,cz,radius): """ Creates and returns a mesh in the form of an icosahedron. Arguments: ---------- cx,cy,cz : float The coordinates of the center point radius : float The radius of the containing sphere """ mesh = Mesh() phi = (1 + 5 ** 0.5) / 2 coordA = 1 / (2 * math.sin(2 * math.pi / 5)) coordB = phi / (2 * math.sin(2 * math.pi / 5)) mesh.vertices = [Vertex(0, -coordA, coordB), Vertex(coordB, 0, coordA), Vertex(coordB, 0, -coordA), Vertex(-coordB, 0, -coordA), Vertex(-coordB, 0, coordA), Vertex(-coordA, coordB, 0), Vertex(coordA, coordB, 0), Vertex(coordA, -coordB, 0), Vertex(-coordA, -coordB, 0), Vertex(0, -coordA, -coordB), Vertex(0, coordA, -coordB), Vertex(0, coordA, coordB)] for i in range(len(mesh.vertices)): mesh.vertices[i] = vec.scale(mesh.vertices[i], radius) mesh.vertices[i] = vec.add(mesh.vertices[i], Vertex(cx,cy,cz)) indices = [1, 2, 6, 1, 7, 2, 3, 4, 5, 4, 3, 8, 6, 5, 11, 5, 6, 10, 9, 10, 2, 10, 9, 3, 7, 8, 9, 8, 7, 0, 11, 0, 1, 0, 11, 4, 6, 2, 10, 1, 6, 11, 3, 5, 10, 5, 4, 11, 2, 7, 9, 7, 1, 0, 3, 9, 8, 4, 8, 0] faces = [] for i in range(0,len(indices),3): f = Face([mesh.vertices[indices[i]], mesh.vertices[indices[i + 1]], mesh.vertices[indices[i + 2]]]) faces.append(f) mesh.faces = faces return mesh