SUBDIVIDE MESH TO ATTRACTORS
import rhinoscriptsyntax as rs
“””
Script written by Ezio Blasetti
Script copyrighted by algorithmicdesign.net
Script version Sunday, June 25, 2011 1:07:59 PM
###########################################################################################
This is a simple recursive subdivision example with use of python classes.
It takes as an input a single mesh, the recursive limmit & a scale for the recursive vector
“””
def averagePts(pts):
av = [0,0,0]
for pt in pts:
av = rs.PointAdd(av,pt)
av = rs.VectorScale(av, 1/(len(pts)))
return rs.PointAdd(av,[0,0,0])
def normalizeAverageDistanceFactor2Attractors(pts, attrs):
listReturn = []
allAvDist = []
minAvDist = 5000000000
maxAvDist = -1
for pt in pts:
sumDist = 0
for attr in attrs:
sumDist += rs.Distance(pt, attr)
avDist = sumDist / len(attrs)
allAvDist.append(avDist)
if avDist < minAvDist : minAvDist = avDist
if avDist > maxAvDist : maxAvDist = avDist
for i in range(len(pts)):
listReturn.append( (allAvDist[i] – minAvDist)/(maxAvDist – minAvDist) )
return listReturn
def intAverageDistanceFactor2Attractors(pts, attrs, max):
listReturn = []
allAvDist = []
minAvDist = 5000000000
maxAvDist = -1
for pt in pts:
sumDist = 0
for attr in attrs:
sumDist += rs.Distance(pt, attr)
avDist = sumDist / len(attrs)
allAvDist.append(avDist)
if avDist < minAvDist : minAvDist = avDist
if avDist > maxAvDist : maxAvDist = avDist
for i in range(len(pts)):
listReturn.append( max – int( ((allAvDist[i] – minAvDist)/(maxAvDist – minAvDist))*(max+1)) )
return listReturn
class sierpinski():
def __init__(self, seedMeshGUID, ATTRS, MAX):
#here we initiate the class by matching the inputs to the variables in the class
self.id = seedMeshGUID
self.max = MAX
#here we make sure that the mesh is made only of triangles
if rs.MeshQuadCount(self.id)>0:
rs.MeshQuadsToTriangles(self.id)
#here we store other information we’ll need later into a few more variables
self.vtxs = rs.MeshVertices(self.id)
self.fVtxs = rs.MeshFaceVertices(self.id)
self.normals = rs.MeshFaceNormals(self.id)
centers = rs.MeshFaceCenters(self.id)
self.faceRecursionCount = intAverageDistanceFactor2Attractors(centers, ATTRS, MAX)
self.newVtxs = self.vtxs[:]
def subdivideFace(self, faceIndex):
“””
this function returns a new mesh -pyramid- for a given faceIndex of a mesh
“””
#here we initiate two new lists to contain the vertices and faceVertices of the pyramid
#newMeshVTXs = []
newMeshFaceVTXs = []
#################################################
faceToSubdivide = self.fVtxs[faceIndex]
#here we call a custom function to calculate the new vertex from the centroid
#centroidPt = self.newPoint4Subd(faceIndex, scale)
pt01 = averagePts([self.vtxs[faceToSubdivide[0]], self.vtxs[faceToSubdivide[1]]])
pt12 = averagePts([self.vtxs[faceToSubdivide[1]], self.vtxs[faceToSubdivide[2]]])
pt20 = averagePts([self.vtxs[faceToSubdivide[2]], self.vtxs[faceToSubdivide[0]]])
#we append in the vertex list the vertices of the parent face
#self.newVtxs.append(self.vtxs[faceToSubdivide[0]])
#self.newVtxs.append(self.vtxs[faceToSubdivide[1]])
#self.newVtxs.append(self.vtxs[faceToSubdivide[2]])
#and the newly calculated centroid
self.newVtxs.append(pt01)
self.newVtxs.append(pt12)
self.newVtxs.append(pt20)
#here we append the faceVertices of the new pyramid
#self.fVtxs.pop(faceIndex)
newMeshFaceVTXs.append((faceToSubdivide[0],len(self.newVtxs)-3 ,len(self.newVtxs)-1))
newMeshFaceVTXs.append((len(self.newVtxs)-3 ,faceToSubdivide[1],len(self.newVtxs)-2))
newMeshFaceVTXs.append((len(self.newVtxs)-1 ,len(self.newVtxs)-2 ,faceToSubdivide[2]))
newMeshFaceVTXs.append((len(self.newVtxs)-3 ,len(self.newVtxs)-2 ,len(self.newVtxs)-1))
#we make the new mesh -pyramid- and return its GUID
return newMeshFaceVTXs
def subdivide(self):
“””
this function will loop through all the faces of the mesh and subdivide them
“””
for j in range(self.max):
faceCount = len(self.fVtxs)
rs.EnableRedraw(False)
#flip = 1
newFaceVtxs = []
newFaceRecCount = []
for i in range(faceCount):
#scale = scale*flip
#this is where we make the new pyramids for each face
currentRec = self.faceRecursionCount[i]
if self.faceRecursionCount[i]>j:
r = self.subdivideFace(i)
for i in range(len(r)):
newFaceRecCount.append(currentRec-1)
newFaceVtxs.extend(r)
else:
newFaceVtxs.append(self.fVtxs[i])
newFaceRecCount.append(currentRec-1)
#flip = flip*(-1)
#this is where we join all the pyramids in one mesh
#self.joinChildren()
rs.DeleteObject(self.id)
self.id = rs.AddMesh(self.newVtxs,newFaceVtxs)
rs.EnableRedraw(True)
#here we update the information of vtxs,faces,normals in the class variables
self.vtxs = rs.MeshVertices(self.id)
self.fVtxs = rs.MeshFaceVertices(self.id)
self.normals = rs.MeshFaceNormals(self.id)
self.newVtxs = self.vtxs[:]
self.faceRecursionCount = newFaceRecCount
def joinChildren(self):
“””
this function will join all the meshes in the self.childrenIDs:
which means it will create a new mesh whih contains all the vertices and faces
of those meshes and delete the old ones. This function basically calculates (sorts out) the two lists
required to make a mesh, namely the mesh vertices and the mesh faceVertices.
Example:
mesh0VTXs = [[0,0,0],[1,0,0],[0,1,0],[0,0,1]]
mesh0FaceVTXs = [[3,0,1],[3,1,2],[3,2,0]]
mesh1VTXs = [[0,0,0],[-1,0,0],[0,1,0],[0,0,-1]]
mesh1FaceVTXs = [[3,0,1],[3,1,2],[3,2,0]]
Result:
mesh0and1VTXs = [[0,0,0],[1,0,0],[0,1,0],[0,0,1],[0,0,0],[-1,0,0],[0,1,0],[0,0,-1]]
mesh0and1FaceVTXs = [[3, 0, 1],[3, 1, 2],[3, 2, 0],[7, 0, 5],[7, 5, 2],[7, 2, 0]]
“””
#here we initiate two new lists to contain the vertices and faceVertices of the new ‘sum’ mesh
newMeshVTXs = []
newMeshFaceVTXs = []
arrayOfMeshes = self.childrenIDs
#for every mesh in the array of meshes to join
for currentMesh in arrayOfMeshes:
#we store its vertices in a list
meshVTXs = rs.MeshVertices(currentMesh)
#and extend the list of the new vertices by adding all of these vertices inside
newMeshVTXs.extend(meshVTXs)
#we store the faceVertices of the current mesh in a list
meshFaceVTXs = rs.MeshFaceVertices(currentMesh)
#we loop through each face in faceVertices list
for face in meshFaceVTXs:
#start a new list for the adjusted face
newFace = []
#loop through each index (vertex) in the current face
for index in face:
#find the right index for the current vertex and append it in the newFace list
newFace.append(newMeshVTXs.index(meshVTXs[index]))
#append the newFace in the list of new faces
newMeshFaceVTXs.append(newFace)
#delete the old meshes
rs.DeleteObjects(arrayOfMeshes)
#restart the children list
self.childrenIDs = []
#delete the parent mesh
rs.DeleteObject(self.id)
#add the new mesh – joined children
self.id = rs.AddMesh(newMeshVTXs, newMeshFaceVTXs)
#return true since everything went good
return True
def main():
mesh = rs.GetObject(“select the mesh to subdivive”,rs.filter.mesh)
max = rs.GetInteger(“Enter the number of maximum recursion: “, 4, 1, 8)
strAttrs = rs.GetObjects(“select some attractors”,rs.filter.point)
attrs = []
for str in strAttrs:
attrs.append(rs.PointCoordinates(str))
###################################################################
mySierpinski = sierpinski(mesh, attrs, max)
###################################################################
mySierpinski.subdivide()
main()
DRAW LINES ON MESH
FREI OTTO