import rhinoscriptsyntax as rs import math import random
# converts radial vector to cartesian vector def radialToCartesian(angle, distance):
# angle: (float) the degrees from origin
# distance: (float) the distance from origin
rads = angle*math.pi/180 # converts degrees to radians return rs.CreatePoint(math.cos(rads)*distance, math.sin(rads)*distance,0)
# r(psi) for logarithmic spiral def logRPsi(angle, a, k):
#angle: (float) angle in degrees
#a: (float) linear coefficient
#k: (float) exponential coefficient return a*math.e**(k*angle*math.pi/180)
# outputs cartesian coordinates for logarithmic spiral based on angular input def logSpiral(angle, a, k):
#angle: (float) angle in degrees
#a: (float) linear coefficient
#k: (float) exponential coefficient return radialToCartesian(angle, logRPsi(angle, a, k))
# recursive function to create spiral patterns with distribution and scale conforming to geometric series def spiral(levels, geom, origin, numArms, numNodes, ang0, ang_step, rotation, scale, a, k, prob, geoms):
# levels: (int) the remaining number of recursions
# geom: (Guid) the base geometry
# origin: (Point3d) origin of spiral
# numArms: (int) the number of spiral arms
# numNodes: (int) the number of nodes per arm
# ang_step: (int) angular difference increment step
# ang0: (int) base angle
# rotation: (float) the rotation of each node with respect to the previous node
# scale: (tuple[float, float, float]) the scale factors of each node with respect to the previous node
#a: (float) linear coefficient
#k: (float) exponential coefficient
#prob: (float) probability of generating fractal
#geoms: (list[Guid]) list of created geometries
if levels != 0:# if there are no more recursions to do, return input geometry
arm_angle = 360/numArms # the angle between 2 neighboring arms
for armIndex in range(numArms): angle = arm_angle*armIndex # current angle (Psi)
newGeom = geom # create 0-th node in each arm translation = rs.CreatePoint(0,0,0) for nodeIndex in range(numNodes): angle = (angle+ang0+nodeIndex*ang_step)%360 # angular difference of sample points increment geometrically
translation = logSpiral(angle,a,k) # translation from origin centerPt = rs.VectorAdd(origin, translation) # center point of new geometry print(translation)
newGeom = rs.CopyObject(newGeom,translation) # copy node to next position with updated angle and distance
newGeom = rs.RotateObject(newGeom, centerPt, rotation) # rotate new node
newGeom = rs.ScaleObject(newGeom, centerPt, scale) # scale new node geoms.append(newGeom)
if(random.random() < prob*nodeIndex/numNodes):
spiral(levels-1, newGeom, rs.CurveAreaCentroid(newGeom) [0], numArms, numNodes-nodeIndex, ang0, ang_step, rotation, scale, a*0.1, k, prob, geoms)
# rs.ScaleObject(newGeom, centerPt, [0.7,0.7,1])
spiral(levels-1, newGeom, centerPt, numArms, (int)(numNodes/3), ang0, ang_step, rotation, scale, a, k, prob, geoms) # recursively create smaller spirals
# portal function to start fractal recursion def crvFractalSpiral(levels, numArms, numNodes, ang0, ang_factor, rotation, scale, a, k, prob):
geom = rs.GetObject(“input prototype geometry”, rs.filter.curve) # request input geometry as curve geoms = [] centroid = rs.CurveAreaCentroid(geom)[0]
spiral(levels, geom, centroid, 1, numNodes, ang0, ang_factor, rotation, scale, a, k, prob, geoms)
# for geom in geoms:
# rs.RotateObject(geom, centroid, 180, None, True)
crvFractalSpiral(3, 4, 60, 15, 0, 15, [1.05,1.05,1], 0.2, 0.053468, 0.3)
import rhinoscriptsyntax as rs import random
# creates a new layer of patterns based on list of modules def modularPatterns(levels, modules, origin, centroids, numPts, numModules):
distances = [] # list of distances from origin to all centroids
distX = [] # list of x component of distances
distY = [] # list of y component of distances for i in range(numModules): # iterate over modules to store distances distances.append(rs.Distance(origin, centroids[i])) # distance between module centroid and origin
distX.append(origin[0]-centroids[i][0]) # x displacement of module centroid from origin
distY.append(origin[1]-centroids[i][1]) # y displacement of module centroid from origin
# upper & lower bounds of distance data
distance_max = max(distances) # maximum distance distance_min = min(distances)*0.99 # minimum distance, adjusted to avoid division by 0
distance_span = distance_max-distance_min # length of distance domain
distX_span = max(distX)-min(distX) # length of x component domain
distX_avg = sum(distX)/numModules # mean of x component
distY_span = max(distY)-min(distY) # length of y component domain
distY_avg = sum(distY)/numModules # mean of y component for i in range(numModules): # iterate over modules to create new layer of geometries
newDistance = 0.25+(distance_max-distances[i])/(2*distance_span) # inversely map distance list to [0.25,0.75] interval prevPts = rs.DivideCurve(modules[i],numPts) # points on previous layer
centroids[i] = rs.PointAdd(centroids[i], ((distX[i] - distX_avg)/ distX_span,(distY[i] - distY_avg)/distY_span,0)) # attract centroid towards origin based on distance, closer modules are less attracted modules[i] = rs.ScaleObject(modules[i], centroids[i], [newDistance,newDistance,1], True) # scale module about new centroid to create new layer of modules
newPts = rs.DivideCurve(modules[i],numPts) # points on new layer for k in range(2): # shift new point sequence to create curl newPts.insert(0,newPts.pop()) for j in range(numPts): # connect points on previous and new layers # rs.AddCurve([prevPts[j], (prevPts[j+1] if j< numPts-1 else prevPts[0]), newPts[j]]) rs.ObjectLayer(rs.AddCurve([prevPts[j], newPts[j]]),”crvs”) if levels != 0: # recursion to next layer modularPatterns(levels-1, modules, origin, centroids, numPts, numModules)
def createPatterns(numRows, numCols, rowInt, colInt, levels, origin, numPts): pts = [] # 2D pt list modules = [] # module list # modules2 = []
originX = round(origin[0]) # x coord of origin
originY = round(origin[1]) # y coord of origin
extremes = [(0,0,0),(0,numRows*rowInt,0),(numCols*colInt,0,0),(numCols*colInt,numRows*rowInt,0)] # 4 vertices of point matrix
extreme_dist = [] # distances between vertices and origin for extreme in extremes: # max distance between all points and origin must be one of the four vertices extreme_dist.append(rs.Distance(extreme,origin)) # store vertice distance in list
dist_max = max(extreme_dist) # find max distance between point matrix and origin
dist_min = rs.Distance(origin,((originX if originX<numCols-1 else numCols-1),(originY if originY<numRows-1 else numRows-1),0)) # min distance between point matrix and origin
dist_span = dist_max-dist_min # length of distance domain for row in range(numRows): # iteratively initialize point matrix ptsRow = [] for col in range(numCols): coeff = (rs.Distance(origin, (col*colInt, row*rowInt, 0))-dist_ min)/dist_span # standardized distance to origin as coefficient to create attractor effect pt = rs.AddPoint((col+(random.random()-0.5)*coeff)*colInt,(row+(random.random()-0.5)*coeff)*rowInt,0) # jitter points with respect to distance from origin rs.HideObject(pt) ptsRow.append(pt) pts.append(ptsRow) for row in range(numRows-1): # iterate over point matrix to create grid modules for col in range(numCols-1): modules.append(rs.AddCurve([pts[row][col],pts[row+1] [col],pts[row+1][col+1],pts[row][col+1],pts[row][col]],1)) # modules2.append(rs.AddCurve([pts[row][col],pts[row+1] [col],pts[row+1][col+1],pts[row][col+1],pts[row][col]],3)) centroids = [] # list of module centroids for module in modules: centroid = rs.CurveAreaCentroid(module)[0] # module centroid centroids.append(centroid) modularPatterns(levels, modules, origin, centroids, numPts, len(modules)) # call recursive function to generate bone structure geometries
if __name__ == “__main__”: createPatterns(15,15,5,5,3,(17,17,0),16)
import rhinoscriptsyntax as rs
# creates snowflake fractal def flakesFractal(levels, origin, sides, factor, radius, stem, num, angles): circ = rs.AddCircle(origin, radius) # reference circle to create vertices rs.HideObject(circ) # hide reference circle angles = (num*360/sides+angles)%360 # rotation of current layer from original position rs.RotateObject(circ, origin, angles) # rotate circle to make sure vertices point away from 0-th origin vertices = rs.DivideCurve(circ,sides) # create vertices for i in range(sides): # pull vertices closer to origin to form spiral fact = factor**i
vertices[i] = (origin[0]+(vertices[i][0]-origin[0])*fact, origin[1]+(vertices[i][1]-origin[1])*fact, origin[2]+(vertices[i][2]-origin[2])*fact) for i in range(sides): # iterate over all vertices to create curve geometries nextPt = vertices[i+1] if i!=sides-1 else vertices[0] # next point in loop crv = rs.JoinCurves([rs.AddCurve([origin,vertices[i]]), rs.AddCurve([origin,nextPt]), rs.AddCurve([nextPt,origin,vertices[i]])],True) # closed curve between radii rs.ScaleObject(crv,rs.CurveAreaCentroid(crv)[0],[0.9,0.9,1]) # scale curves to create slits in between if(levels != 0 and i != sides-1 and (not stem or i == 0 or i == 1 or i == 2)): # recursively create fractals flakesFractal(levels-1, vertices[i], sides, factor, radius*factor**(sides-2), True, i, angles)
import rhinoscriptsyntax as rs import random
# creates a new layer of patterns based on list of modules def modularPatterns(levels, modules, origin, centroids, numPts, numModules, numRows, numCols,shades,levels_t):
distances = [] # list of distances from origin to all centroids
distX = [] # list of x component of distances distY = [] # list of y component of distances for i in range(numRows-1): # iterate over modules to store distances for j in range(numCols-1):
distances.append(rs.Distance(origin, centroids[(i,j)])) # distance between module centroid and origin
distX.append(origin[0]-centroids[(i,j)][0]) # x displacement of module centroid from origin
distY.append(origin[1]-centroids[(i,j)][1]) # y displacement of module centroid from origin
# upper & lower bounds of distance data
distance_max = max(distances) # maximum distance
distance_min = min(distances)*0.99 # minimum distance, adjusted to avoid division by 0
distance_span = distance_max-distance_min # length of distance domain
distX_span = max(distX)-min(distX) # length of x component domain
distX_avg = sum(distX)/numModules # mean of x component distY_span = max(distY)-min(distY) # length of y component domain distY_avg = sum(distY)/numModules # mean of y component index = 0 # index in distance lists for i in range(numRows-1): # iterate over modules to create new layer of geometries for j in range(numCols-1):
newDistance = 0.2+0.7*(distance_max-distances[index])/distance_ span # inversely map distance list to [0.2,0.9] interval prevPts = rs.DivideCurve(modules[(i,j)],numPts) # points on previous layer centroids[(i,j)] = rs.PointAdd(centroids[(i,j)], ((distX[index] - distX_avg)/distX_span,(distY[index] - distY_avg)/distY_span,0)) # attract centroid towards origin based on distance, closer modules are less attracted modules[(i,j)] = rs.ScaleObject(modules[(i,j)], centroids[(i,j)], [newDistance,newDistance,1], True) # scale module about new centroid to create new layer of modules newPts = rs.DivideCurve(modules[(i,j)],numPts) # points on new layer
for k in range(2): # shift new point sequence to create curl newPts.insert(0,newPts.pop()) for p in range(numPts): # connect points on previous and new layers # rs.AddCurve([prevPts[p], (prevPts[p+1] if p< numPts-1 else prevPts[0]), newPts[p]])
rs.ObjectLayer(rs.AddCurve([prevPts[p], newPts[p]]),”crvs”) insertion = levels_t-levels+2
vertices = rs.CurveEditPoints(modules[(i,j)]) shades[(i,j)].insert(insertion,vertices[1]) shades[(i,j)].insert(insertion+1,vertices[3]) if(levels == 1): shades[(i,j)].insert(insertion+1,vertices[0]) rs.ObjectLayer(rs.AddCurve(shades[(i,j)],1),”shade”)
index += 1
if levels != 0: # recursion to next layer modularPatterns(levels-1, modules, origin, centroids, numPts, numModules, numRows, numCols,shades,levels_t)
def createPatterns(numRows, numCols, rowInt, colInt, levels, origin, numPts): pts = {} # 2D pt hashmap modules = {} # module hashmap centroids = {} # module centroids hashmap shades = {} # modules2 = []
originX = round(origin[0]) # x coord of origin
originY = round(origin[1]) # y coord of origin
extremes = [(0,0,0),(0,numRows*rowInt,0),(numCols*colInt,0,0),(numCols*colInt,numRows*rowInt,0)] # 4 vertices of point matrix
extreme_dist = [] # distances between vertices and origin for extreme in extremes: # max distance between all points and origin must be one of the four vertices extreme_dist.append(rs.Distance(extreme,origin)) # store vertice distance in list
dist_max = max(extreme_dist) # find max distance between point matrix and origin
dist_min = rs.Distance(origin,((originX if originX<numCols-1 else numCols-1),(originY if originY<numRows-1 else numRows-1),0)) # min distance between point matrix and origin
dist_span = dist_max-dist_min # length of distance domain for row in range(numRows): # iteratively initialize point matrix ptsRow = [] for col in range(numCols): coeff = (rs.Distance(origin, (col*colInt, row*rowInt, 0))-dist_ min)/dist_span # standardized distance to origin as coefficient to create attractor effect
pt = rs.AddPoint((col+(random.random()-0.5)*coeff)*colInt,(row+(random.random()-0.5)*coeff)*rowInt,0) # jitter points with respect to distance from origin
rs.HideObject(pt) pts[(row,col)] = pt for row in range(numRows-1): # iterate over point matrix to create grid modules for col in range(numCols-1): modules[(row,col)]=rs.AddCurve([pts[(row,col)],pts[(row+1,col)],p ts[(row+1,col+1)],pts[(row,col+1)],pts[(row,col)]],1)
centroids[(row,col)] = rs.CurveAreaCentroid(modules[(row,col)]) [0] # module centroid
shades[(row,col)] = [pts[(row,col)],pts[(row+1,col)],pts[(row,col +1)],pts[(row,col)]]
# modules2.append(rs.AddCurve([pts[row][col],pts[row+1] [col],pts[row+1][col+1],pts[row][col+1],pts[row][col]],3))
modularPatterns(levels, modules, origin, centroids, numPts, len(modules), numRows, numCols,shades, levels) # call recursive function to generate bone structure geometries if __name__ == “__main__”: createPatterns(15,15,5,5,3,(17,17,0),16)
import rhinoscriptsyntax as rs import random
# creates a new layer of patterns based on list of modules def modularPatterns(levels, modules, origin, centroids, numPts, numModules, numRows, numCols,shades,levels_t):
distances = [] # list of distances from origin to all centroids
distX = [] # list of x component of distances
distY = [] # list of y component of distances for i in range(numRows-1): # iterate over modules to store distances for j in range(numCols-1):
distances.append(rs.Distance(origin, centroids[(i,j)])) # distance between module centroid and origin
distX.append(origin[0]-centroids[(i,j)][0]) # x displacement of module centroid from origin
distY.append(origin[1]-centroids[(i,j)][1]) # y displacement of module centroid from origin
# upper & lower bounds of distance data
distance_max = max(distances) # maximum distance
distance_min = min(distances)*0.99 # minimum distance, adjusted to avoid division by 0
distance_span = distance_max-distance_min # length of distance domain
distX_span = max(distX)-min(distX) # length of x component domain
distX_avg = sum(distX)/numModules # mean of x component distY_span = max(distY)-min(distY) # length of y component domain distY_avg = sum(distY)/numModules # mean of y component index = 0 # index in distance lists for i in range(numRows-1): # iterate over modules to create new layer of geometries for j in range(numCols-1): newDistance = 0.2+0.7*(distance_max-distances[index])/distance_ span # inversely map distance list to [0.2,0.9] interval prevPts = rs.DivideCurve(modules[(i,j)],numPts) # points on previous layer centroids[(i,j)] = rs.PointAdd(centroids[(i,j)], ((distX[index] - distX_avg)/distX_span,(distY[index] - distY_avg)/distY_span,0)) # attract centroid towards origin based on distance, closer modules are less attracted modules[(i,j)] = rs.ScaleObject(modules[(i,j)], centroids[(i,j)], [newDistance,newDistance,1], True) # scale module about new centroid to create new layer of modules newPts = rs.DivideCurve(modules[(i,j)],numPts) # points on new layer
for k in range(2): # shift new point sequence to create curl newPts.insert(0,newPts.pop()) for p in range(numPts): # connect points on previous and new layers # rs.AddCurve([prevPts[p], (prevPts[p+1] if p< numPts-1 else prevPts[0]), newPts[p]])
rs.ObjectLayer(rs.AddCurve([prevPts[p], newPts[p]]),”crvs”) insertion = levels_t-levels+2
vertices = rs.CurveEditPoints(modules[(i,j)]) shades[(i,j)].insert(insertion,vertices[1]) shades[(i,j)].insert(insertion+1,vertices[3]) if(levels == 1): shades[(i,j)].insert(insertion+1,vertices[0]) rs.ObjectLayer(rs.AddCurve(shades[(i,j)],1),”shade”)
index += 1
if levels != 0: # recursion to next layer modularPatterns(levels-1, modules, origin, centroids, numPts, numModules, numRows, numCols,shades,levels_t)
def createPatterns(numRows, numCols, rowInt, colInt, levels, origin, numPts, frameIndex):
pts = {} # 2D pt hashmap modules = {} # module hashmap centroids = {} # module centroids hashmap shades = {} # modules2 = []
originX = round(origin[0]) # x coord of origin
originY = round(origin[1]) # y coord of origin
extremes = [(0,0,0),(0,numRows*rowInt,0),(numCols*colInt,0,0),(numCols*colInt,numRows*rowInt,0)] # 4 vertices of point matrix
extreme_dist = [] # distances between vertices and origin for extreme in extremes: # max distance between all points and origin must be one of the four vertices extreme_dist.append(rs.Distance(extreme,origin)) # store vertice distance in list
dist_max = max(extreme_dist) # find max distance between point matrix and origin
dist_min = rs.Distance(origin,((originX if originX<numCols-1 else numCols-1),(originY if originY<numRows-1 else numRows-1),0)) # min distance between point matrix and origin
dist_span = dist_max-dist_min # length of distance domain for row in range(numRows): # iteratively initialize point matrix ptsRow = [] for col in range(numCols): coeff = (rs.Distance(origin, (col*colInt, row*rowInt, 0))-dist_ min)/dist_span # standardized distance to origin as coefficient to create attractor effect
pt = rs.AddPoint((col+(random.random()-0.5)*coeff)*colInt,(row+(random.random()-0.5)*coeff)*rowInt,0) # jitter points with respect to distance from origin
rs.HideObject(pt)
pts[(row,col)] = pt for row in range(numRows-1): # iterate over point matrix to create grid modules for col in range(numCols-1):
modules[(row,col)]=rs.AddCurve([pts[(row,col)],pts[(row+1,col)],p ts[(row+1,col+1)],pts[(row,col+1)],pts[(row,col)]],1)
centroids[(row,col)] = rs.CurveAreaCentroid(modules[(row,col)])
[0] # module centroid shades[(row,col)] = [pts[(row,col)],pts[(row+1,col)],pts[(row,col +1)],pts[(row,col)]]
# modules2.append(rs.AddCurve([pts[row][col],pts[row+1] [col],pts[row+1][col+1],pts[row][col+1],pts[row][col]],3))
modularPatterns(levels, modules, origin, centroids, numPts, len(modules), numRows, numCols,shades, levels) # call recursive function to generate bone structure geometries
rs.Command(“_-ViewCaptureToFile”+” D:\DesignComputing_week3_1_ frame”+str(frameIndex).zfill(3))
rs.Command(“’_SelAll”)
rs.Command(“_Delete”)
def patternAnimation(numRows, numCols, rowInt, colInt, levels, start, end, numFrames,numPts):
translation = rs.VectorCreate(end,start)
print(translation)
translation = (translation[0]/numFrames,translation[1]/numFrames,translation[2]/numFrames)
print(translation)
for frameIndex in range(numFrames):
createPatterns(numRows, numCols, rowInt, colInt, levels, start, numPts, frameIndex)
start = rs.PointAdd(start,translation)
if __name__ == “__main__”: patternAnimation(15,15,5,5,3,(0,0,0),(50,50,0),240,16)
import rhinoscriptsyntax as rs import random
def basRelief(height,numRows,numCols,rowInt,colInt,randX,randZ,probMirror,crvInt):
crvs = [] startPts = [] endPts = [] srfs = [] x = 0
z = 0
zBase = [] for j in range(numRows): zBase.append(z)
z += rowInt*random.randint(1,3)
flip = True for i in range(numCols):
xDelta = colInt*random.randint(1,5)
x += xDelta colPts = []
if(random.random() < probMirror and i > 0):
crv = rs.ScaleObject(crvs[i-1],rs.CurveMidPoint(crv),(-1,1,1),True)
crv = rs.MoveObject(crv,(xDelta,0,0))
else:
z = 0
for j in range(numRows): colPts.append(rs.AddPoint(x+colInt*randX*(random.random()-0.5),0,z+randZ*rowInt*(random.random()-0.5)))
if z == height: break
z += rowInt*random.randint(1,3)
if z > height or j == numRows-2:
z = height
crv = rs.AddInterpCurve(colPts)
crvs.append(crv)
startPts.append(rs.CurveStartPoint(crv))
endPts.append(rs.CurveEndPoint(crv))
if(i > 0):
rail1 = endArc(startPts[i-1],startPts[i],flip)
rail2 = endArc(endPts[i-1],endPts[i],flip)
sweep = rs.AddSweep2([rail1,rail2],[crvs[i-1],crvs[i]])
srfs.append(sweep)
rs.HideObjects([rail1,rail2])
flip = not flip
srf = rs.JoinSurfaces(srfs)
bounds = rs.BoundingBox(srf)
contours = rs.AddSrfContourCrvs(srf,[(0,-100,0),(0,100,0)],crvInt)
depth = len(contours)*crvInt
for contour in contours:
start = rs.CurveMidPoint(contour)
rs.ExtrudeCurveStraight(contour,start,rs.PointAdd(start,(0,depth,0)))
rs.HideObjects(srfs)
# rs.HideObject(srf)
rs.HideObjects(crvs)
def endArc(pt1,pt2,flip):
x = (pt1[0]+pt2[0])/2
z = (pt1[2]+pt2[2])/2
origin = (x,0,z)
degs = 180 if flip else -180
return rs.AddArc(rs.PlaneFromPoints(origin,pt2,(origin[0],1,origin[2])),rs.Distance(origin,pt2),degs)
if __name__ == “__main__”:
rs.EnableRedraw(False)
basRelief(30,8,20,2,1,1,0.5,0.2,0.5)
rs.EnableRedraw(True)
import rhinoscriptsyntax as rs import Rhino import scriptcontext as sc import System
import math
import random
def populateSrf(srf, uList, vList):
ptsUV = {} # list of uv pts
ptsXYZ = {} for i in range(len(uList)): for j in range(len(vList)): ptsUV[(i,j)] = (uList[i],vList[j])
return ptsUV
def uvTo3D(srf,ptsUV):
pts3D = {} for (i,j) in ptsUV: pts3D[(i,j)] = rs.EvaluateSurface(srf,ptsUV[(i,j)][0],ptsUV[(i,j)] [1])
return pts3D
# divides srf with division interval proportional to meridian distance from axis
def uByRadius(srf, axis, numU):
uOut = []
dists = []
axisSamplePts = rs.DivideCurve(axis,numU)
uDomain = rs.SurfaceDomain(srf,0)
vDomain = rs.SurfaceDomain(srf,1)
v = vDomain[0]
uList = uUniform(srf,numU)[0]
for u in range(numU):
dists.append(rs.Distance(rs.EvaluateSurface(srf,uList[u],v),axisSamplePts[u]))
factor = (uDomain[1]-uDomain[0])/sum(dists)
uCurrent = uDomain[0]
minDist = min(dists)
distSpan = max(dists)-minDist for i in range(numU): uOut.append(uCurrent)
uCurrent += dists[i]*factor dists[i] = (dists[i]-minDist)/distSpan
return (uOut,dists)
def vByRadius(srf, axis, numV):
vOut = [] dists = []
axisSamplePts = rs.DivideCurve(axis,numV)
uDomain = rs.SurfaceDomain(srf,0)
vDomain = rs.SurfaceDomain(srf,1)
u = uDomain[0]
vList = vUniform(srf,numV)[0]
for v in range(numV): dists.append(rs.Distance(rs.EvaluateSurface(srf,u,vList[v]),axisSamplePts[v]))
factor = (vDomain[1]-vDomain[0])/sum(dists)
vCurrent = vDomain[0]
minDist = min(dists)
distSpan = max(dists)-minDist for j in range(numV):
vOut.append(vCurrent)
vCurrent += dists[j]*factor
dists[j] = (dists[j]-minDist)/distSpan return (vOut,dists)
def uUniform(srf, numU):
uOut = [] weights = []
uDomain = rs.SurfaceDomain(srf,0)
step = (uDomain[1]-uDomain[0])/numU
u = 0 for i in range(numU):
uOut.append(u)
u += step weights.append(0.5)
return (uOut,weights)
def vUniform(srf, numV):
vOut = [] weights = []
vDomain = rs.SurfaceDomain(srf,1)
step = (vDomain[1]-vDomain[0])/numV
v = 0 for j in range(numV):
vOut.append(v)
v += step weights.append(0.5)
return (vOut,weights)
def jitterGrid(ptsDict, uWeights, vWeights, factU, factV): for (i,j) in ptsDict: ptsDict[(i,j)] = (ptsDict[(i,j)][0]+uWeights[i]*factU*(random.random()-0.5), ptsDict[(i,j)][1]+vWeights[j]*factV*(random.random()-0.5))
def generateModules(srf, ptsUV, pts3D, uWeights, vWeights, numU, numV, maxFact, maxDist, prob, mutateFact):
mutation = []
for
j in range(1,numV-3):
r = range(0,numU,2) if j%2!=0 else range(1,numU,2) for i in r:
u = ptsUV[(i,j)][0]
v = ptsUV[(i,j)][1]
factor = maxFact*uWeights[i]*vWeights[j]
left = i-1 if i>0 else numU-1
right = i+1 if i< numU-1 else 0
baseCrv = rs.AddCurve([pts3D[(left,j)], pts3D[(i,j-1)], pts3D[(right,j)], pts3D[(i,j+1)], pts3D[(left,j)]],1)
# topCrv = rs.AddCurve([pts3D[(left,j)], pts3D[(i,j-1)], pts3D[(right,j)], pts3D[(i,j+1)], pts3D[(left,j)]],3)
topCrv = rs.AddCurve([pts3D[(i,j+1)], pts3D[(left,j)], pts3D[(i,j-1)], pts3D[(right,j)], pts3D[(i,j+1)]],3)
rs.ScaleObject(topCrv, rs.EvaluateSurface(srf,u,v), rs.VectorScale((1.2,1.2,1.2),factor+0.1))
rand = random.random()
translation = rs.SurfaceNormal(srf, [u,v])
if rand*factor > prob:
translation = rs.VectorScale(translation,factor*maxDist*rand*mutateFact)
rs.MoveObject(topCrv,translation)
loft = rs.AddLoftSrf([baseCrv,topCrv])
cent1 = rs.CurveAreaCentroid(rs.AddCurve([pts3D[(left,j)], pts3D[(i,j-1)], pts3D[(right,j)], pts3D[(left,j)]],1))[0]
cent2 = rs.CurveAreaCentroid(rs.AddCurve([pts3D[(left,j)], pts3D[(right,j)], pts3D[(i,j+1)], pts3D[(left,j)]],1))[0]
center = ((cent1[0]+cent2[0])/2, (cent1[1]+cent2[1])/2, (cent1[2]+cent2[2])/2)
mutation.append((loft,rs.AddLine(center, rs.PointAdd(center,translation)),baseCrv)) else:
rs.MoveObject(topCrv,rs.VectorScale(translation,factor*maxDist*rand))
loft = rs.AddLoftSrf([baseCrv,topCrv])
return mutation
def addSkeleton(geom,axis,interval,scale,depth,thickness,numSpine,scaleGeom,extend):
srf = ScaleObjectEx(geom,rs.CurvePerpFrame(axis,rs.CurveDomain(axis) [0]),[scaleGeom,scaleGeom,1],True)
pts = []
contours = rs.AddSrfContourCrvs(srf, [rs.CurveStartPoint(axis),rs.CurveEndPoint(axis)], interval)
i = 0
while i < len(contours): crv = contours[i]
if rs.IsCurveClosed(crv):
pts.append(rs.DivideCurve(crv,numSpine))
start = pts[i][0]
crvIn = rs.ScaleObject(crv,rs.CurveAreaCentroid(crv)[0],rs.VectorScale([1,1,1],scale),True)
rib = rs.AddPlanarSrf([crv,crvIn])
rs.ExtrudeSurface(rib,rs.AddLine((0,0,0),rs.VectorScale(rs.SurfaceNormal(rib,[0,0]),thickness)))
i += 1 else:
contours.pop(i) for j in range(numSpine):
crvPts = []
for i in range(len(contours)):
crvPts.append(pts[i][j])
spine = rs.AddInterpCurve(crvPts)
spine = rs.ExtendCurveLength(spine,1,2,rs.CurveLength(spine)*extend*random.random())
outer = pts[0][j]
line = rs.AddLine(outer,rs.EvaluateCurve(axis,rs.CurveClosestPoint(axis,outer),0))
srf = rs.ExtrudeCurve(spine,rs.ScaleObject(line,rs.CurveStartPoint(line),rs.VectorScale((1,1,1),depth/rs.CurveLength(line)))) rs.ExtrudeSurface(srf,rs.AddLine((0,0,0),rs.VectorScale(rs.SurfaceNormal(srf,[0,0]),thickness)))
rs.DeleteObject(srf)
def modularize(srf, axis, numU, numV, maxFact, maxDist, prob, mutateFact,jitterU,jitterV,interval1,interval2,scale1,scale2,depth1,depth2,thickness1,thickness2,numSpine1,numSpine2,scaleGeom1,scaleGeom2,scaleRecess,extend):
addSkeleton(srf,axis,interval1,scale1,depth1,thickness1,numSpine1,scaleGeom1,extend)
(vList,vWeights) = vByRadius(srf,axis,numU)
(uList,uWeights) = uUniform(srf,numV)
ptsUV = populateSrf(srf,uList,vList)
jitterGrid(ptsUV,uWeights,vWeights,jitterU,jitterV)
pts3D = uvTo3D(srf,ptsUV)
mutated = generateModules(srf,ptsUV,pts3D,uWeights,vWeights,numU,numV, maxFact, maxDist, prob, mutateFact)
for (loft,line,baseCrv) in mutated:
addSkeleton(loft,line,interval2,scale2,depth2,thickness2,numSpine2,scaleGeom2,extend)
ScaleObjectsEx([loft],rs.CurvePerpFrame(line,rs.CurveDomain(axis) [0]),[1,1,scaleRecess],False)
def ScaleObjectEx(object_id, plane, scale, copy=False): scale = rs.coerce3dpoint(scale, True)
if scale:
xform = Rhino.Geometry.Transform.Scale(plane, scale.X, scale.Y, scale.Z)
object_id = rs.coerceguid(object_id, True) id = sc.doc.Objects.Transform(object_id, xform, not copy) return id
if __name__ == “__main__”: srf = rs.GetObject(“enter srf”) axis = rs.GetObject(“enter axis”, rs.filter.curve)
rs.EnableRedraw(False) mutated = modularize(srf,ax-
# ScaleObjectsEx([srf],rs.CurvePerpFrame(axis,rs.CurveDomain(axis) [0]),[0.5,0.5,1],True)
rs.EnableRedraw(True)