├── 001-Twisted Vases.py ├── 002-Matrix Wall.py ├── 003-Waffle Surfaces Part 1 ├── 3 - waffleSrfs part1.py └── wafflePart1.gh ├── 004-Waffle Surfaces Part 2 ├── 4-Waffle Surface.py └── Waffle Surface.gh ├── 005-Bezier Shells ├── Bezier Shells.gh └── Bezier Shells.py ├── 007-Hard-edge Fluidity ├── zahaWav.gh └── zahaWavSimp.py ├── 008-Hexa-fabric Canopy ├── hexaPattern.gh └── hexaPattern.py ├── 009-Hexagon Cells ├── ghfile.gh └── script.py ├── 010-Folding Wall ├── voronoi.gh └── voronoi.py ├── 011-Pentagon Growth ├── pentagon.gh └── script.py ├── 012-Leaves ├── leaves.3dm ├── leaves.gh └── leaves.py └── 06-Euclidean Panels ├── Euclidean Panels.gh └── Euclidean Panels.py /001-Twisted Vases.py: -------------------------------------------------------------------------------- 1 | import rhinoscriptsyntax as rs 2 | from random import random 3 | 4 | def generateMatrix(xMax, yMax, zMax, showPoints = False): 5 | ptMatrix = {} 6 | for z in range(zMax): 7 | for y in range(yMax): 8 | for x in range(xMax): 9 | ptMatrix[(x, y, z)] = (x * 8, y * 8, z * 8) 10 | 11 | if showPoints: 12 | rs.AddPoints(list(ptMatrix.values())) 13 | return ptMatrix 14 | 15 | def generateCrvs(matrix, xMax, yMax, zMax): 16 | crvDict = {} 17 | for i in range(yMax): 18 | crvDict[i] = [] 19 | 20 | for y in range(yMax): 21 | for x in range(xMax-1): 22 | for z in range(zMax-1): 23 | ptA = matrix[(x, y, z)] 24 | ptB = matrix[(x+1, y, z)] 25 | ptC = matrix[(x+1, y, z+1)] 26 | ptD = matrix[(x, y, z+1)] 27 | pts = [ptA, ptB, ptC, ptD, ptA] 28 | crv = rs.AddCurve(pts) 29 | scaleCrv(crv) 30 | crvDict[y].append(crv) 31 | 32 | return crvDict 33 | 34 | def loftCrv(crvDict, yMax): 35 | result = [] 36 | for i in range(len(crvDict[0])): 37 | crvs = [crvDict[y][i] for y in range(yMax)] 38 | result.append(rs.AddLoftSrf(crvs)) 39 | return result 40 | 41 | def scaleCrv(crv, max=1.1, min=0.5): 42 | cen = rs.CurveAreaCentroid(crv)[0] 43 | xFactor = random() * (max - min) + min 44 | zFactor = random() * (max - min) + min 45 | rs.ScaleObject(crv, cen, (xFactor, 1, zFactor)) 46 | 47 | xMax = 8 48 | yMax = 3 49 | zMax = 6 50 | 51 | ptMatrix = generateMatrix(xMax, yMax, zMax) 52 | crvDict = generateCrvs(ptMatrix, xMax, yMax, zMax) 53 | srf = loftCrv(crvDict, yMax) -------------------------------------------------------------------------------- /002-Matrix Wall.py: -------------------------------------------------------------------------------- 1 | import rhinoscriptsyntax as rs 2 | from random import randint 3 | 4 | def generateMatrix(xNum, yNum, zNum, showTag=False, showPt=False): 5 | ptDict = {} 6 | for z in range(zNum): 7 | for y in range(yNum): 8 | for x in range(xNum): 9 | ptDict[(x, y, z)] = (x*10, y*5, z*10) 10 | if showPt: 11 | rs.AddPoints(list(ptDict.values())) 12 | if showTag: 13 | for key in ptDict: 14 | rs.AddTextDot(key, ptDict[key]) 15 | return ptDict 16 | 17 | def drawPolyline(ptDict, y=1): 18 | polylines = [] 19 | xMax = max([key[0] for key in ptDict]) 20 | zMax = max([key[2] for key in ptDict]) 21 | for z in range(zMax): 22 | for x in range(xMax): 23 | ptA = ptDict[(x, y, z)] 24 | ptB = ptDict[(x+1, y, z)] 25 | ptC = ptDict[(x+1, y, z+1)] 26 | ptD = ptDict[(x, y, z+1)] 27 | polylines.append(rs.AddPolyline([ptA, ptB, ptC, ptD, ptA])) 28 | return polylines 29 | 30 | def subDiv(poly, showPt=False, showTag=False): 31 | srf = rs.AddPlanarSrf(poly) 32 | rs.RebuildSurface(srf, (3, 3), (4, 4)) 33 | pts = rs.SurfaceEditPoints(srf) 34 | newPtsDict = {} 35 | x=0 36 | for i in range(len(pts)): 37 | if i>0 and i%4 == 0: 38 | x+=1 39 | newPtsDict[(x, i%4)] = pts[i] 40 | 41 | x= randint(0, 2) 42 | y= randint(0, 2) 43 | xStep = randint(1, 2) 44 | yStep = randint(1, 2) 45 | if x == 2: xStep=1 46 | if y == 2: yStep=1 47 | 48 | ptA = newPtsDict[(x, y)] 49 | ptB = newPtsDict[(x+xStep), y] 50 | ptC = newPtsDict[(x+xStep), (y+yStep)] 51 | ptD = newPtsDict[x, (y+yStep)] 52 | newPoly = rs.AddPolyline([ptA, ptB, ptC, ptD, ptA]) 53 | rs.DeleteObjects([poly, srf]) 54 | 55 | if showPt: 56 | rs.AddPoints(pts) 57 | if showTag: 58 | for key in newPtsDict: 59 | rs.AddTextDot(key, newPtsDict[key]) 60 | 61 | return newPoly 62 | 63 | def solid(fPoly, bPoly): 64 | fPolyO = rs.OffsetCurve(fPoly, rs.CurveAreaCentroid(fPoly)[0], 0.2, (0, 1, 0)) 65 | bPolyO = rs.OffsetCurve(bPoly, rs.CurveAreaCentroid(bPoly)[0], 0.2, (0, 1, 0)) 66 | srf1 = rs.AddLoftSrf([fPoly, fPolyO]) 67 | srf2 = rs.AddLoftSrf([fPoly,bPoly]) 68 | srf3 = rs.AddLoftSrf([fPolyO,bPolyO]) 69 | srf4 = rs.AddLoftSrf([bPoly,bPolyO]) 70 | obj = rs.JoinSurfaces([srf1, srf2, srf3, srf4], True) 71 | return obj 72 | 73 | def main(): 74 | xNum = 8 75 | yNum = 2 76 | zNum = 6 77 | 78 | ptDict = generateMatrix(xNum, yNum, zNum, False) 79 | backPoly = drawPolyline(ptDict) 80 | frontPoly = drawPolyline(ptDict, 0) 81 | 82 | for i in range(len(frontPoly)): 83 | frontPoly[i] = subDiv(frontPoly[i]) 84 | solid(frontPoly[i], backPoly[i]) 85 | 86 | rs.Command("_SelCrv") 87 | rs.Command("_Delete") 88 | 89 | rs.EnableRedraw(False) 90 | rs.Command("_SelAll") 91 | rs.Command("_Delete") 92 | main() 93 | rs.EnableRedraw(True) -------------------------------------------------------------------------------- /003-Waffle Surfaces Part 1/3 - waffleSrfs part1.py: -------------------------------------------------------------------------------- 1 | import rhinoscriptsyntax as rs 2 | from math import pi, sin 3 | 4 | def createSrf(xNum = 10, yNum = 10, xStep = 5, yStep = 5): 5 | startAng = 0 6 | xPeriod = 2 * pi 7 | yPeriod = 2 * pi 8 | curves = [] 9 | for y in range(yNum + 1): 10 | pts = [] 11 | for x in range(xNum + 1): 12 | xAngStep = xPeriod / xNum 13 | pts.append((x * xStep, y * yStep, 2 * sin(x * xAngStep + startAng))) 14 | curves.append(rs.AddCurve(pts)) 15 | startAng += yPeriod / yNum 16 | return rs.AddLoftSrf(reversed(curves)) 17 | 18 | 19 | def divideSrf(srf): 20 | uDomain = rs.SurfaceDomain(srf, 0) 21 | vDomain = rs.SurfaceDomain(srf, 1) 22 | 23 | uSteps = u 24 | vSteps = v 25 | 26 | srfPts = {} 27 | polys = [] 28 | normals = [] 29 | 30 | for j in range(len(vSteps)): 31 | for i in range(len(uSteps)): 32 | uPos, vPos = uSteps[i], vSteps[j] 33 | currU = uDomain[0] + uPos * (uDomain[1] - uDomain[0]) 34 | currV = vDomain[0] + vPos * (vDomain[1] - vDomain[0]) 35 | 36 | pt = rs.EvaluateSurface(srf, currU, currV) 37 | srfPts[(i, j, 0)] = pt 38 | normal = normalPt(srf, [currU, currV], amp) 39 | normals.append(normal) 40 | srfPts[(i, j, 1)] = rs.PointAdd(pt, normal) 41 | 42 | if i > 0 and j > 0: 43 | for n in range(2): 44 | ptA = srfPts[(i, j, n)] 45 | ptB = srfPts[(i, j-1, n)] 46 | ptC = srfPts[(i-1, j-1, n)] 47 | ptD = srfPts[(i-1, j, n)] 48 | polys.append(rs.AddPolyline([ptA, ptB, ptC, ptD, ptA])) 49 | 50 | return srfPts, polys 51 | 52 | 53 | def normalPt(srf, uv, amplitude): 54 | normal = rs.SurfaceNormal(srf, uv) 55 | normal = rs.VectorScale(normal, amplitude) 56 | return normal 57 | 58 | 59 | srf = createSrf(10, 10, xStep, yStep) 60 | srfPts, polys= divideSrf(srf) 61 | srfPts = rs.AddPoints(list(srfPts.values())) -------------------------------------------------------------------------------- /003-Waffle Surfaces Part 1/wafflePart1.gh: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tingsong-ou/RhinoPython-GhPython/85ab0ad686bda42718638b84b6667a508095a2e2/003-Waffle Surfaces Part 1/wafflePart1.gh -------------------------------------------------------------------------------- /004-Waffle Surfaces Part 2/4-Waffle Surface.py: -------------------------------------------------------------------------------- 1 | import rhinoscriptsyntax as rs 2 | from math import pi, sin 3 | from random import random, seed 4 | 5 | seed(rSeed) 6 | 7 | #--------FUNCTIONS-------- 8 | 9 | #CREATING THE CURVED SURFACE 10 | def createSrf(xNum = 10, yNum = 10, xStep = 5, yStep = 5): 11 | startAng = 0 12 | xPeriod = 2 * pi 13 | yPeriod = 2 * pi 14 | curves = [] 15 | for y in range(yNum + 1): 16 | pts = [] 17 | for x in range(xNum + 1): 18 | xAngStep = xPeriod / xNum 19 | pts.append((x * xStep, y * yStep, 2 * sin(x * xAngStep + startAng))) 20 | curves.append(rs.AddCurve(pts)) 21 | startAng += yPeriod / yNum 22 | return rs.AddLoftSrf(reversed(curves)) 23 | 24 | 25 | #SUBDIVIDING SURFACE 26 | def divideSrf(srf): 27 | uDomain = rs.SurfaceDomain(srf, 0) 28 | vDomain = rs.SurfaceDomain(srf, 1) 29 | 30 | uSteps = u #u is a GhPython input 31 | vSteps = v #v is a GhPython input 32 | 33 | srfPts = {} 34 | polys = [] 35 | normals = [] 36 | 37 | for j in range(len(vSteps)): 38 | for i in range(len(uSteps)): 39 | uPos, vPos = uSteps[i], vSteps[j] 40 | if uPos != 0 and uPos != 1 and vPos != 0 and vPos != 1: 41 | uPos += random() * 0.04 - 0.02 42 | vPos += random() * 0.04 - 0.02 43 | currU = uDomain[0] + uPos * (uDomain[1] - uDomain[0]) 44 | currV = vDomain[0] + vPos * (vDomain[1] - vDomain[0]) 45 | 46 | pt = rs.EvaluateSurface(srf, currU, currV) 47 | srfPts[(i, j, 0)] = pt 48 | normal = normalPt(srf, [currU, currV], amp) 49 | normals.append(normal) 50 | srfPts[(i, j, 1)] = rs.PointAdd(pt, normal) 51 | 52 | if i > 0 and j > 0: 53 | for n in range(2): 54 | ptA = srfPts[(i, j, n)] 55 | ptB = srfPts[(i, j-1, n)] 56 | ptC = srfPts[(i-1, j-1, n)] 57 | ptD = srfPts[(i-1, j, n)] 58 | polys.append(rs.AddPolyline([ptA, ptB, ptC, ptD, ptA])) 59 | 60 | return srfPts, polys 61 | 62 | 63 | #CALCULATING THE SURFACE NORMAL ON SPECIFIC UV POSITION 64 | def normalPt(srf, uv, amplitude): 65 | normal = rs.SurfaceNormal(srf, uv) 66 | normal = rs.VectorScale(normal, amplitude * (1 + random() * 0.5)) 67 | return normal 68 | 69 | 70 | def scalePoly(poly, scale): 71 | pts = rs.CurveEditPoints(poly)[:-1] 72 | ptsX = [pt[0] for pt in pts] 73 | ptsY = [pt[1] for pt in pts] 74 | ptsZ = [pt[2] for pt in pts] 75 | ptNum = len(pts) 76 | avgCen = (sum(ptsX)/ptNum, sum(ptsY)/ptNum, sum(ptsZ)/ptNum) 77 | 78 | outPoly = rs.ScaleObject(poly, avgCen, (scale, scale, scale), True) 79 | 80 | return outPoly 81 | 82 | #--------EXECUSION-------- 83 | 84 | #VISUALIZATION THE RESULT 85 | srf = createSrf(10, 10, xStep, yStep) 86 | srfPts, polys= divideSrf(srf) 87 | srfPts = rs.AddPoints(list(srfPts.values())) 88 | 89 | polysA = [polys[i] for i in range(len(polys)) if i % 2 == 0] 90 | polysB = [polys[i] for i in range(len(polys)) if i % 2 == 1] 91 | 92 | outSrfs = [] 93 | 94 | for i in range(len(polysA)): 95 | newSrfs = [] 96 | polyAO = scalePoly(polysA[i], 0.9) 97 | polyBO = scalePoly(polysB[i], 0.9) 98 | newSrfs += rs.AddLoftSrf([polysB[i], polyBO]) 99 | newSrfs += rs.AddLoftSrf([polysA[i], polyAO]) 100 | newSrfs += rs.AddLoftSrf([polysA[i], polysB[i]]) 101 | newSrfs += rs.AddLoftSrf([polyAO, polyBO]) 102 | outSrfs.append(rs.JoinSurfaces(newSrfs)) 103 | 104 | -------------------------------------------------------------------------------- /004-Waffle Surfaces Part 2/Waffle Surface.gh: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tingsong-ou/RhinoPython-GhPython/85ab0ad686bda42718638b84b6667a508095a2e2/004-Waffle Surfaces Part 2/Waffle Surface.gh -------------------------------------------------------------------------------- /005-Bezier Shells/Bezier Shells.gh: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tingsong-ou/RhinoPython-GhPython/85ab0ad686bda42718638b84b6667a508095a2e2/005-Bezier Shells/Bezier Shells.gh -------------------------------------------------------------------------------- /005-Bezier Shells/Bezier Shells.py: -------------------------------------------------------------------------------- 1 | import rhinoscriptsyntax as rs 2 | import Rhino.Geometry as rhg 3 | import Rhino.Collections as rhc 4 | from random import randint, random, seed 5 | 6 | seed(rSeed) 7 | 8 | def addBezierShell(poly): 9 | beziers = [] 10 | pts = rs.CurveEditPoints(poly) 11 | startPt = randint(0, 1) 12 | 13 | for i in range(startPt, len(pts)-1, 2): 14 | pta = rhg.Point3d(pts[i]) 15 | ptb = rhg.Point3d(pts[i+1]) 16 | span = rs.Distance(pta, ptb) * zFactor 17 | aHandle = rhg.Point3d(pta[0], pta[1], pta[2] + span + (random() * 2 - 1) * span) 18 | bHandle = rhg.Point3d(ptb[0], ptb[1], ptb[2] + span + (random() * 2 - 1) * span) 19 | ptList = rhc.Point3dList(pta, aHandle, bHandle, ptb) 20 | bezier = rhg.BezierCurve(ptList) 21 | bezier = bezier.ToNurbsCurve() 22 | 23 | if i == startPt + 2: bezier.Reverse() 24 | 25 | beziers.append(bezier) 26 | return beziers 27 | 28 | shells = [] 29 | for poly in polys: 30 | shells += addBezierShell(poly) 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /007-Hard-edge Fluidity/zahaWav.gh: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tingsong-ou/RhinoPython-GhPython/85ab0ad686bda42718638b84b6667a508095a2e2/007-Hard-edge Fluidity/zahaWav.gh -------------------------------------------------------------------------------- /007-Hard-edge Fluidity/zahaWavSimp.py: -------------------------------------------------------------------------------- 1 | import rhinoscriptsyntax as rs 2 | from random import random 3 | 4 | def divCrv(crv, vNum, dir): 5 | pts = [] 6 | crvLen = rs.CurveLength(crv) 7 | lenStep = float(crvLen / (vNum)) #I can remove * 2 later 8 | if dir == 0: 9 | pts = rs.DivideCurveLength(crv, lenStep / 3) 10 | else: 11 | tempPts = rs.DivideCurveLength(crv, lenStep / 6) 12 | newStart = rs.CurveClosestPoint(crv, tempPts[1]) 13 | newEnd = rs.CurveClosestPoint(crv, tempPts[-2]) 14 | crv = rs.TrimCurve(crv, [newStart, newEnd], False) 15 | pts = rs.DivideCurveLength(crv, lenStep / 3) 16 | 17 | endPt = rs.CurveEndPoint(crv) 18 | if pts[-1] != endPt: 19 | pts.append(endPt) 20 | return pts 21 | 22 | 23 | def addCrvs(srf, ptDict, uNum, i, offStart, offEnd): 24 | crvs = [] 25 | for j in range(offStart, offEnd, 1): 26 | pts = [] 27 | for k in range(uNum + 1): 28 | if k % 2 == 0: 29 | pts.append(ptDict[k][i]) 30 | else: 31 | pts.append(ptDict[k][i + j]) 32 | crvs.append(rs.AddInterpCurve(pts)) 33 | return crvs 34 | 35 | 36 | def drawEdges(ptDict, uNum, srf): 37 | crvs = [] 38 | for i in range(len(ptDict[0])): 39 | if i % 3 == 0 and i != 0 and i != len(ptDict[0]) - 1: 40 | crvs += addCrvs(srf, ptDict, uNum, i, -2, 2) 41 | ''' 42 | for j in range(-2, 2, 1): 43 | pts = [] 44 | for k in range(uNum + 1): 45 | if k % 2 == 0: 46 | pts.append(ptDict[k][i]) 47 | else: 48 | pts.append(ptDict[k][i + j]) 49 | crvs.append(rs.AddInterpCurve(srf,pts)) 50 | ''' 51 | elif i == 0: 52 | crvs += addCrvs(srf, ptDict, uNum, i, 0, 2) 53 | elif i == len(ptDict[0]) - 1: 54 | crvs += addCrvs(srf, ptDict, uNum, i, -2, 0) 55 | else: 56 | pts = [] 57 | for k in range(uNum+1): 58 | if k % 2 == 0: 59 | pts.append(ptDict[k][i]) 60 | else: 61 | pts.append(ptDict[k][i - (i % 3 - 1)]) 62 | crvs.append(rs.AddInterpCurve(pts)) 63 | return crvs 64 | 65 | 66 | def divSrf(srf, uNum, vNum, srfOffset): 67 | crvs = [] 68 | ptDict = {} 69 | uDom = rs.SurfaceDomain(srf, 0) 70 | vDom = rs.SurfaceDomain(srf, 1) 71 | 72 | uStep = (uDom[1] - uDom[0]) / uNum 73 | 74 | for i in range(uNum + 1): 75 | baseCrv = rs.ExtractIsoCurve(srf, (uDom[0] + i * uStep, 0), 1)[0] 76 | pts = divCrv(baseCrv, vNum, i % 2) 77 | for j in range(len(pts)): 78 | if (j + i % 2 * 2) % 3 != 0: 79 | norm = rs.BrepClosestPoint(srf, pts[j])[3] 80 | norm = rs.VectorUnitize(norm) 81 | if i == 0 or i == uNum: norm = (norm[0], norm[1], 0) 82 | norm = rs.VectorScale(norm, srfOffset * (0.2 + random() * 1.2)) 83 | rs.MoveObject(pts[j], norm) 84 | ptDict[i] = pts 85 | crvs += drawEdges(ptDict, uNum, srf) 86 | 87 | return crvs 88 | 89 | 90 | #Main 91 | srfs = [] 92 | uNum = int(uNum) 93 | vNum = int(vNum) 94 | if vNum < 2: vNum = 2 95 | if uNum < 4: uNum = 4 96 | if vNum % 2 != 0: vNum += 1 97 | 98 | crvs = divSrf(srf, uNum, vNum, offDist) 99 | 100 | for i in range(len(crvs) - 1): 101 | srfs += rs.AddLoftSrf([crvs[i], crvs[i+1]]) 102 | 103 | if rs.IsSurfaceClosed(srf, 1): 104 | srfs += rs.AddLoftSrf([crvs[0], crvs[-1]]) -------------------------------------------------------------------------------- /008-Hexa-fabric Canopy/hexaPattern.gh: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tingsong-ou/RhinoPython-GhPython/85ab0ad686bda42718638b84b6667a508095a2e2/008-Hexa-fabric Canopy/hexaPattern.gh -------------------------------------------------------------------------------- /008-Hexa-fabric Canopy/hexaPattern.py: -------------------------------------------------------------------------------- 1 | import rhinoscriptsyntax as rs 2 | from random import random, seed 3 | 4 | seed(100) 5 | 6 | def offsetPts(ptDict, attrPt, magnitude, srf): 7 | maxDist = max([rs.Distance(attrPt, pt) for pt in ptDict.values()]) 8 | minDist = min([rs.Distance(attrPt, pt) for pt in ptDict.values()]) 9 | for pt in ptDict.values(): 10 | norm = rs.BrepClosestPoint(srf, pt)[3] 11 | plane = rs.PlaneFromNormal(pt, norm) 12 | randVec = (random() - 0.5, random() - 0.5, random() - 0.5) 13 | newLoc = rs.PointAdd(pt, randVec) 14 | newLoc = rs.PlaneClosestPoint(plane, newLoc) 15 | moveVec = rs.VectorSubtract(newLoc, pt) 16 | moveVec = rs.VectorUnitize(moveVec) 17 | 18 | dist = rs.Distance(attrPt, pt) 19 | remapDist = int((dist - minDist) / (maxDist - minDist) * 1000) / 1000 20 | rs.MoveObject(pt, rs.VectorScale(moveVec, remapDist * magnitude)) 21 | 22 | def drawHexa(ptDict): 23 | polys = [] 24 | vMax = max([key[0] for key in ptDict]) 25 | uMax = max([key[1] for key in ptDict]) 26 | for v in range(vMax - 1): 27 | for u in range(v%2, uMax - v % 2, 2): 28 | pt1 = ptDict[v, u] 29 | pt2 = ptDict[v, u+1] 30 | pt3 = ptDict[v+1, u+1] 31 | pt4 = ptDict[v+2, u+1] 32 | pt5 = ptDict[v+2, u] 33 | pt6 = ptDict[v+1, u] 34 | pts = [pt1, pt2, pt3, pt4, pt5, pt6, pt1] 35 | polys.append(rs.AddPolyline(pts)) 36 | return polys 37 | 38 | 39 | def divDom(srf, uNum, vNum): 40 | pts = {} 41 | uDom = rs.SurfaceDomain(srf, 0) 42 | vDom = rs.SurfaceDomain(srf, 1) 43 | uStep = (uDom[1] - uDom[0]) / uNum 44 | vStep = (vDom[1] - vDom[0]) / vNum 45 | 46 | for v in range(vNum + 1): 47 | vParam = vDom[0] + v * vStep 48 | uIndex = 0 49 | for u in range(uNum + 1): 50 | if u % 3 == 1 and v % 2 == 0: 51 | uParam = uDom[0] + (u - 0.5) * uStep 52 | pts[v, uIndex] = rs.EvaluateSurface(srf, uParam, vParam) 53 | uIndex += 1 54 | uParam = uDom[0] + (u + 0.5) * uStep 55 | pts[v, uIndex] = rs.EvaluateSurface(srf, uParam, vParam) 56 | uIndex += 1 57 | elif u % 3 != 1 and v % 2 == 1: 58 | uParam = uDom[0] + u * uStep 59 | pts[v, uIndex] = rs.EvaluateSurface(srf, uParam, vParam) 60 | uIndex += 1 61 | return pts 62 | 63 | 64 | 65 | 66 | uNum = int(uNum) 67 | vNum = int(vNum) 68 | 69 | 70 | if uNum < 5: uNum = 5 71 | if uNum > 5 and (uNum - 5) % 3 != 0: 72 | uNum += 3 - (uNum - 5) % 3 73 | 74 | a = divDom(srf, uNum, vNum) 75 | offsetPts(a, attrPt, magnitude, srf) 76 | c = drawHexa(a) 77 | 78 | b = a.keys() 79 | a = a.values() 80 | 81 | -------------------------------------------------------------------------------- /009-Hexagon Cells/ghfile.gh: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tingsong-ou/RhinoPython-GhPython/85ab0ad686bda42718638b84b6667a508095a2e2/009-Hexagon Cells/ghfile.gh -------------------------------------------------------------------------------- /009-Hexagon Cells/script.py: -------------------------------------------------------------------------------- 1 | import rhinoscriptsyntax as rs 2 | from random import seed, uniform, randint 3 | 4 | seed(rSeed) 5 | 6 | def getAverageCenter(pts): 7 | cenX = sum([pts[i][0] for i in range(len(pts) - 1)]) / (len(pts) - 1) 8 | cenY = sum([pts[i][1] for i in range(len(pts) - 1)]) / (len(pts) - 1) 9 | cenZ = sum([pts[i][2] for i in range(len(pts) - 1)]) / (len(pts) - 1) 10 | return (cenX, cenY, cenZ) 11 | 12 | #------Pattern A-------- 13 | def patternA(hexa, offsetDist): 14 | crvs = [] 15 | srfs = [] 16 | pts = rs.PolylineVertices(hexa) 17 | cenPt = getAverageCenter(pts) 18 | 19 | newPts = [] 20 | for i in range(len(pts)): 21 | moveVec = rs.VectorSubtract(cenPt, pts[i]) 22 | moveVec = rs.VectorUnitize(moveVec) 23 | moveVec = rs.VectorScale(moveVec, offsetDist) 24 | newPt = rs.PointAdd(pts[i], moveVec) 25 | newPts.append(newPt) 26 | crv = rs.AddCurve(newPts) 27 | crvs.append(crv) 28 | 29 | #Creating surface 30 | crvPara = rs.CurveClosestPoint(crv, pts[0]) 31 | crvPt = rs.EvaluateCurve(crv, crvPara) 32 | secLine = rs.AddLine(pts[0], crvPt) 33 | srf = rs.AddSweep2([crv, hexa], [secLine]) 34 | srfs += srf 35 | 36 | return crvs, srfs 37 | 38 | 39 | #------Pattern B-------- 40 | def patternB(hexa): 41 | crvs = [] 42 | srfs = [] 43 | pts = rs.PolylineVertices(hexa) 44 | cenPt = getAverageCenter(pts) 45 | 46 | for i in range(len(pts) - 1): 47 | pta = pts[i] 48 | ptb = pts[i+1] 49 | ptList = [pta, cenPt, ptb] 50 | crv = rs.AddCurve(ptList) 51 | crvs.append(crv) 52 | 53 | #Creating surface 54 | outline = rs.AddPolyline([pta, cenPt, ptb]) 55 | srf = rs.AddLoftSrf([outline, crv]) 56 | srfs += srf 57 | 58 | return crvs, srfs 59 | 60 | #------Pattern C-------- 61 | def patternC(hexa): 62 | crvs = [] 63 | srfs = [] 64 | pts = rs.PolylineVertices(hexa) 65 | cenPt = getAverageCenter(pts) 66 | 67 | for i in range(len(pts) - 1): 68 | pta = pts[i] 69 | ptb = pts[i+1] 70 | ptList = [pta, cenPt, ptb, pta] 71 | crv = rs.AddCurve(ptList, 2) 72 | crvs.append(crv) 73 | 74 | #Creating surface 75 | outline = rs.AddPolyline(ptList) 76 | crvPara = rs.CurveClosestPoint(crv, cenPt) 77 | crvPt = rs.EvaluateCurve(crv, crvPara) 78 | secLine = rs.AddLine(cenPt, crvPt) 79 | srf = rs.AddSweep2([outline, crv], [secLine]) 80 | srfs += srf 81 | 82 | return crvs, srfs 83 | 84 | 85 | #--------Pattern D-------- 86 | def patternD(hexa): 87 | crvs = [] 88 | srfs = [] 89 | pts = rs.PolylineVertices(hexa) 90 | cenPt = getAverageCenter(pts) 91 | 92 | for i in range(len(pts) - 1): 93 | pta = pts[i] 94 | ptb = pts[i+1] 95 | ptList = [pta, ptb, cenPt, 0] 96 | subCen = getAverageCenter(ptList) 97 | segA = rs.AddCurve([pta, subCen, cenPt]) 98 | segB = rs.AddCurve([cenPt, subCen, ptb]) 99 | segC = rs.AddCurve([ptb, subCen, pta]) 100 | crv = rs.JoinCurves([segA, segB, segC])[0] 101 | crvs.append(crv) 102 | 103 | #Creating surface 104 | srf = rs.AddEdgeSrf([segA, segB, segC]) 105 | srfs.append(srf) 106 | return crvs, srfs 107 | 108 | 109 | 110 | #Excuting 111 | crvs = [] 112 | srfs = [] 113 | 114 | for hexa in hexagons: 115 | pattern = randint(0, 3) 116 | if pattern == 0: 117 | offsetDist = uniform(0.8, 2.5) 118 | crvs += patternA(hexa, offsetDist)[0] 119 | srfs += patternA(hexa, offsetDist)[1] 120 | elif pattern == 1: 121 | crvs += patternB(hexa)[0] 122 | srfs += patternB(hexa)[1] 123 | elif pattern == 2: 124 | crvs += patternC(hexa)[0] 125 | srfs += patternC(hexa)[1] 126 | else: 127 | crvs += patternD(hexa)[0] 128 | srfs += patternD(hexa)[1] 129 | -------------------------------------------------------------------------------- /010-Folding Wall/voronoi.gh: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tingsong-ou/RhinoPython-GhPython/85ab0ad686bda42718638b84b6667a508095a2e2/010-Folding Wall/voronoi.gh -------------------------------------------------------------------------------- /010-Folding Wall/voronoi.py: -------------------------------------------------------------------------------- 1 | import Rhino.Geometry as rg 2 | from random import random, uniform, sample, seed, randint 3 | import ghpythonlib.treehelpers as th 4 | 5 | seed(1000) 6 | 7 | #Step 1: move vertices, making shape dynamic 8 | def moveVertices(polyline): 9 | ptNum = polyline.PointCount 10 | pts = [] 11 | planePts = [] 12 | #Getting points and moving vectors 13 | for i in range(ptNum): 14 | pts.append(polyline.Point(i)) 15 | if len(planePts) <= 3: 16 | planePts.append(pts[i]) 17 | plane = rg.Plane(planePts[0], planePts[1], planePts[2]) 18 | dir = plane.ZAxis 19 | 20 | #Update point position 21 | for i in range(ptNum): 22 | scalar = uniform(0.0, 2.0) 23 | vec = dir * scalar 24 | pts[i] = pts[i] + vec 25 | pts[-1] = pts[0] 26 | 27 | #Preserving plane for future modifications 28 | return pts, plane 29 | 30 | 31 | #Step 2: Cell type A 32 | #Dividing a polygon into three parts: halfA, halfB, curve 33 | def divPolygon(vertices, plane): 34 | midIdx = len(vertices) // 2 35 | startPt = vertices[0] 36 | endPt = vertices[midIdx] 37 | 38 | #get polygon centroid 39 | centroid = getCentroid(vertices) 40 | 41 | xOff = plane.XAxis * uniform(0.0, 2.0) 42 | yOff = plane.YAxis * uniform(0.0, 2.0) 43 | zOff = plane.ZAxis * uniform(1.0, 3.0) 44 | 45 | centroid[0] += xOff[0] + yOff[0] + zOff[0] 46 | centroid[1] += xOff[1] + yOff[1] + zOff[1] 47 | centroid[2] += xOff[2] + yOff[2] + zOff[2] 48 | 49 | curve = rg.Curve.CreateInterpolatedCurve([startPt, centroid, endPt], 3) 50 | curve = jagCurve(curve, plane, 24) 51 | curve = rg.PolylineCurve(curve) 52 | 53 | halfA = rg.PolylineCurve(vertices[:midIdx+1]) 54 | halfB = rg.PolylineCurve(vertices[midIdx:]) 55 | halfB.Reverse() 56 | return [curve, halfA, halfB] 57 | 58 | 59 | 60 | #Step 3: Cell type B 61 | def offsetPolygon(vertices, plane): 62 | centroid = getCentroid(vertices) 63 | dist = uniform(0.3, 0.4) 64 | height = uniform(1.0, 2.0) 65 | newPts = [] 66 | 67 | for i in range(len(vertices)): 68 | v = vertices[i] 69 | vec = (centroid - v) * dist 70 | vec += plane.ZAxis * height 71 | newPts.append(v + vec) 72 | 73 | curve = rg.NurbsCurve.Create(True, 3, newPts[:-1]) 74 | curve = jagCurve(curve, plane, 30, 1) 75 | curve = rg.PolylineCurve(curve) 76 | 77 | outer = rg.PolylineCurve(vertices) 78 | inner = rg.Circle(plane, centroid, uniform(0.3, 1)) 79 | 80 | #Change curve seam (I can do this at the end)!!! 81 | startT = curve.ClosestPoint(vertices[0])[1] 82 | curve.ChangeClosedCurveSeam(startT) 83 | 84 | inner = inner.ToNurbsCurve() 85 | inStartT = inner.ClosestPoint(vertices[0])[1] 86 | inner.ChangeClosedCurveSeam(inStartT) 87 | 88 | 89 | return [curve, outer, inner] 90 | 91 | 92 | 93 | 94 | #Get centroid from a serise of vertices 95 | def getCentroid(vertices): 96 | centroid = [0, 0, 0] 97 | for i in range(len(vertices) - 1): 98 | centroid[0] += vertices[i][0] 99 | centroid[1] += vertices[i][1] 100 | centroid[2] += vertices[i][2] 101 | centroid = [val / (len(vertices) - 1) for val in centroid] 102 | return rg.Point3d(centroid[0], centroid[1], centroid[2]) 103 | 104 | 105 | 106 | #Making a smooth curve jaggy 107 | def jagCurve(curve, plane, divisions, mode = 0): 108 | totalLen = curve.GetLength() 109 | lenStep = totalLen / divisions 110 | #These are parameters 111 | 112 | #This is the c# array pattern 113 | ts = curve.DivideByLength(lenStep, True) 114 | ts = [t for t in ts] 115 | if mode == 1: ts.append(curve.Domain[1]) 116 | 117 | offDist = uniform(0.2, 0.5) 118 | pts = [] 119 | for i in range(len(ts)): 120 | t = ts[i] 121 | newPt = curve.PointAt(t) 122 | if i % 2 != 0 and i != (len(ts)-1): 123 | if mode == 1: vec = -plane.ZAxis 124 | else: 125 | vec = curve.CurvatureAt(t) 126 | vec.Unitize() 127 | vec = -plane.ZAxis + vec 128 | vec = vec * offDist 129 | newPt = newPt + vec 130 | pts.append(newPt) 131 | return pts 132 | 133 | 134 | 135 | 136 | ##Operations 137 | 138 | 139 | newCells = [] 140 | planes = [] 141 | newBases = [] 142 | 143 | for poly in cells: 144 | vertices, plane = moveVertices(poly) 145 | planes.append(plane) 146 | newBases.append(rg.PolylineCurve(vertices)) 147 | if randint(0, 1) == 0: 148 | newCells.append(divPolygon(vertices, plane)) 149 | else: 150 | newCells.append(offsetPolygon(vertices, plane)) 151 | 152 | newCells = th.list_to_tree(newCells) 153 | -------------------------------------------------------------------------------- /011-Pentagon Growth/pentagon.gh: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tingsong-ou/RhinoPython-GhPython/85ab0ad686bda42718638b84b6667a508095a2e2/011-Pentagon Growth/pentagon.gh -------------------------------------------------------------------------------- /011-Pentagon Growth/script.py: -------------------------------------------------------------------------------- 1 | import Rhino.Geometry as rg 2 | import random 3 | import ghpythonlib.treehelpers as th 4 | from math import * 5 | 6 | random.seed(seed) 7 | 8 | #Generating Pentagon 9 | def genPenta(line): 10 | iter = 0 11 | oriPts = [line.From, line.To] 12 | pentaPts = [line.To] 13 | while iter < 3: 14 | vec = rg.Point3d.Subtract(line.To, line.From) 15 | rad = radians(72); 16 | nextX = vec[0] * cos(rad) - vec[1] * sin(rad); 17 | nextY = vec[0] * sin(rad) + vec[1] * cos(rad); 18 | newPt = rg.Point3d(nextX, nextY, 0) 19 | newPt += line.To 20 | newLine = rg.Line(line.To, newPt) 21 | line = newLine 22 | pentaPts.append(line.To) 23 | iter += 1 24 | pentaPts.append(oriPts[0]) 25 | return pentaPts 26 | 27 | 28 | #Adding Edge to avaliable edge set 29 | def addEdges(pentaPts, edgeSet): 30 | for i in range(len(pentaPts)): 31 | ptA = pentaPts[i] 32 | ptB = pentaPts[(i+1)%len(pentaPts)] 33 | newEdge = rg.Line(ptA, ptB) 34 | edgeSet.add(newEdge) 35 | 36 | 37 | #Moving pts 38 | def movePts(pentaPts): 39 | newPts = pentaPts[:] 40 | for i in range(1, len(pentaPts)-1): 41 | pt = pentaPts[i] 42 | xOff = random.uniform(-0.7, 0.7) 43 | yOff = random.uniform(-0.7, 0.7) 44 | zOff = random.uniform(-1.0, 3.0) 45 | newPts[i] = rg.Point3d(pt[0] + xOff, pt[1] + yOff, pt[2] + zOff) 46 | return newPts 47 | 48 | 49 | #Check intersection 50 | def checkIntersection(pentagonA, pentagonB): 51 | pPentaA = [rg.Point3d(pt[0], pt[1], 0) for pt in pentagonA] 52 | pPentaB = [rg.Point3d(pt[0], pt[1], 0) for pt in pentagonB] 53 | 54 | #Shorten PolylineA 55 | tempA = rg.PolylineCurve(pPentaA) 56 | dom = tempA.Domain 57 | tempA = tempA.Trim(dom[0] + 0.1, dom[1] - 0.1) 58 | pPentaA[0] = tempA.PointAtStart 59 | pPentaA[-1] = tempA.PointAtEnd 60 | 61 | #Create Closed Polygons 62 | polyA = rg.PolylineCurve(pPentaA + [pPentaA[0]]) 63 | polyB = rg.PolylineCurve(pPentaB + [pPentaB[0]]) 64 | 65 | plane = rg.Plane.WorldXY 66 | rel = rg.Curve.PlanarClosedCurveRelationship(polyA, polyB, plane, 0.01) 67 | 68 | return rel != rg.RegionContainment.Disjoint 69 | 70 | 71 | 72 | avalEdges = {line} 73 | pentagons = [] 74 | currItr = 0 75 | 76 | while currItr < iter: 77 | currItr += 1 78 | randEdge = random.choice(list(avalEdges)) 79 | randEdge.Flip() 80 | newPenta = genPenta(randEdge) 81 | newPenta = movePts(newPenta) 82 | 83 | #Check Collision 84 | isCollide = False 85 | for penta in pentagons: 86 | intersect = checkIntersection(newPenta, penta) 87 | if intersect: isCollide = True 88 | if isCollide: continue 89 | 90 | pentagons.append(newPenta) 91 | addEdges(newPenta, avalEdges) 92 | avalEdges.remove(randEdge) 93 | 94 | 95 | a = th.list_to_tree(pentagons) -------------------------------------------------------------------------------- /012-Leaves/leaves.3dm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tingsong-ou/RhinoPython-GhPython/85ab0ad686bda42718638b84b6667a508095a2e2/012-Leaves/leaves.3dm -------------------------------------------------------------------------------- /012-Leaves/leaves.gh: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tingsong-ou/RhinoPython-GhPython/85ab0ad686bda42718638b84b6667a508095a2e2/012-Leaves/leaves.gh -------------------------------------------------------------------------------- /012-Leaves/leaves.py: -------------------------------------------------------------------------------- 1 | import Rhino.Geometry as rg 2 | import Rhino.Collections as rc 3 | from random import randint, uniform, seed 4 | import ghpythonlib.treehelpers as th 5 | 6 | seed(rSeed) 7 | 8 | #------------HELPER FUNCTIONS------- 9 | 10 | #Step 1: generating pts and handles 11 | def getPtNHandle(curve, startT, handleScale, reversed = False): 12 | ptPara = curve.NormalizedLengthParameter(startT)[1] 13 | pt = curve.PointAt(ptPara) 14 | vec = curve.TangentAt(ptPara) 15 | vec.Unitize() 16 | 17 | span = curve.Domain[1] - curve.Domain[0] 18 | interv = rg.Interval(ptPara, ptPara + handleScale) 19 | 20 | if interv[1] > curve.Domain[1]: 21 | interv = rg.Interval(ptPara - handleScale, ptPara) 22 | 23 | scale = curve.GetLength(interv) 24 | vec *= scale 25 | 26 | if reversed: vec *= -1 27 | handle = pt + vec 28 | return pt, handle 29 | 30 | 31 | #Step 2: generating Bezier curve 32 | def genBezierCrv(ptA, ptB, handleA, handleB): 33 | pts = rc.Point3dList([ptA, handleA, handleB, ptB]) 34 | bzCrv = rg.BezierCurve(pts) 35 | bzCrv = bzCrv.ToNurbsCurve() 36 | return bzCrv 37 | 38 | #Step 3: creating leaf 39 | def genLeaf(curveA, curveB, aPara, bPara, aFac, bFac): 40 | crvs = [] 41 | count = randint(3, 4) 42 | for i in range(count): 43 | minFac = uniform(aFac, aFac + 0.5) 44 | maxFac = uniform(bFac, bFac + 0.5) 45 | scales = [minFac, maxFac] 46 | 47 | if i == 1: 48 | scales[0], scales[1] = scales[1], scales[0] 49 | if i >= 2: 50 | midFac = (minFac + maxFac) / 2 51 | scales[0] = uniform(midFac - 1.5, midFac + 1.5) 52 | scales[1] = uniform(midFac - 1.5, midFac + 1.5) 53 | 54 | ptA, handleA = getPtNHandle(curveA, aPara, scales[0]) 55 | ptB, handleB = getPtNHandle(curveB, bPara, scales[1], True) 56 | 57 | crv = genBezierCrv(ptA, ptB, handleA, handleB) 58 | crvs.append(crv) 59 | return crvs 60 | 61 | 62 | #---------------PROGRAM------------------- 63 | 64 | step = int(step * 100) 65 | aParas = [i/100 for i in range(0, 80, step)] 66 | bParas = [i/100 for i in range(20, 100, step)] 67 | 68 | leaves = [] 69 | 70 | for i in range(1, len(curves), 2): 71 | currCrv = curves[i] 72 | leftCrv = curves[i-1] 73 | 74 | try: 75 | rightCrv = curves[i+1] 76 | except: 77 | rightCrv = None 78 | 79 | for j in range(len(aParas)): 80 | aPara = aParas[j] 81 | bPara = bParas[j] 82 | leftLeaves = genLeaf(currCrv, leftCrv, aPara, bPara, aFac, bFac) 83 | leaves.append(leftLeaves) 84 | if rightCrv: 85 | rightLeaves = genLeaf(currCrv, rightCrv, aPara, bPara, aFac, bFac) 86 | leaves.append(rightLeaves) 87 | 88 | a = th.list_to_tree(leaves) 89 | -------------------------------------------------------------------------------- /06-Euclidean Panels/Euclidean Panels.gh: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tingsong-ou/RhinoPython-GhPython/85ab0ad686bda42718638b84b6667a508095a2e2/06-Euclidean Panels/Euclidean Panels.gh -------------------------------------------------------------------------------- /06-Euclidean Panels/Euclidean Panels.py: -------------------------------------------------------------------------------- 1 | import rhinoscriptsyntax as rs 2 | 3 | def drawRect(xPos, yPos, width, height): 4 | plane = rs.WorldXYPlane() 5 | plane = rs.MovePlane(plane, (xPos, yPos, 0)) 6 | rect = rs.AddRectangle(plane, width, height) 7 | return [rect] 8 | 9 | def divSquare(xPos, yPos, width, thrd, ratio): 10 | rects = [] 11 | itr = 0 12 | xEndPos = width + xPos 13 | yEndPos = width + yPos 14 | rects += drawRect(xPos, yPos, width, width) 15 | while width > thrd: 16 | itr += 1 17 | if itr % 2 == 1: 18 | while xPos + width * ratio < xEndPos + 0.1: 19 | rects += divRect(xPos, yPos, width * ratio, thrd, ratio) 20 | xPos += width * ratio 21 | width = xEndPos - xPos 22 | else: 23 | while yPos + width / ratio < yEndPos + 0.1: 24 | rects += divRect(xPos, yPos, width, thrd, ratio) 25 | yPos += width / ratio 26 | width = yEndPos - yPos 27 | return rects 28 | 29 | def divRect(xPos, yPos, width, thrd, ratio): 30 | rects = [] 31 | itr = 0 32 | xEndPos = xPos + width 33 | yEndPos = yPos + width / ratio 34 | rects += drawRect(xPos, yPos, width, width/ratio) 35 | while width > thrd: 36 | itr += 1 37 | if itr % 2 == 0: 38 | while xPos + width < xEndPos + 0.1: 39 | rects += divSquare(xPos, yPos, width, thrd, ratio) 40 | xPos += width 41 | width = xEndPos - xPos 42 | else: 43 | while yPos + width < yEndPos + 0.1: 44 | rects += divSquare(xPos, yPos, width, thrd, ratio) 45 | yPos += width 46 | width = yEndPos - yPos 47 | return rects 48 | 49 | 50 | 51 | numA = x 52 | numB = y 53 | thrd = limit 54 | if thrd < 30: thrd = 30 55 | ratio = float(numA / numB) 56 | if(numA != numB): 57 | a = divSquare(0, 0, 500, thrd, ratio) --------------------------------------------------------------------------------