Free-form & flat quads with Rhino.Python

Fossile-like structures made of flat quad panels. Panels can be assembled along their folded sides. The script works with free from surfaces (trimmed or not_see conditional minimum distance between any point evaluated within surface domain and the base surface_as per Python Primer example)

CODE:
import rhinoscriptsyntax as rs
import random #import  random module

def SurfaceQuad():
    idSurface=rs.GetObject("Select Surface",8,True,False)
    if not idSurface:return
    intCountU = rs.GetInteger("Number of panels in U direction",20,10)
    if not intCountU:return
    intCountV = rs.GetInteger("Number of panels in V direction",7,5)
    if not intCountV:return
    uDomain=rs.SurfaceDomain(idSurface,0)
    vDomain=rs.SurfaceDomain(idSurface,1)
    uStep=uDomain[1] - uDomain[0]
    uStep=uStep / intCountU
    vStep=vDomain[1] - vDomain[0]
    vStep=vStep / intCountV

    #Tolerance in between panels
    dblTolU = uStep/100
    dblTolV = dblTolU*intCountU/intCountV

    rs.EnableRedraw(False)

    for v in rs.frange(vDomain[0],vDomain[1]-vStep-vDomain[0],vStep):
        for u in rs.frange (uDomain[0],uDomain[1]-uStep-uDomain[0],uStep):
            #Evaluate panel coordinates on idSurface

            ptA=rs.EvaluateSurface(idSurface,u+dblTolU,v+dblTolV)
            ptB=rs.EvaluateSurface(idSurface,u+uStep-dblTolU,v+dblTolV)
            ptC=rs.EvaluateSurface(idSurface,u+uStep-dblTolU,v+vStep-dblTolV)
            ptD=rs.EvaluateSurface(idSurface,u+dblTolU,v+vStep-dblTolV)

            #evaluate normal vectors at A,B,C,D on the surface
            vecNormA=rs.SurfaceNormal(idSurface,[u,v])
            vecNormB=rs.SurfaceNormal(idSurface,[u+uStep,v])
            vecNormC=rs.SurfaceNormal(idSurface,[u+uStep,v+vStep])
            vecNormD=rs.SurfaceNormal(idSurface,[u,v+vStep])

            #Side fixings projecting height
            #SurfaceNormal vectors are unitized by default_so we scale them according to the length of each panel
            dblPanelLength=rs.Distance(ptA,ptB)/10
            vecNormA=rs.VectorScale(vecNormA,dblPanelLength)
            vecNormB=rs.VectorScale(vecNormB,dblPanelLength)
            vecNormC=rs.VectorScale(vecNormC,dblPanelLength)
            vecNormD=rs.VectorScale(vecNormD,dblPanelLength)

            #Condition below prevent from adding a panel when surface is trimmed
            if rs.Distance(ptA,rs.BrepClosestPoint(idSurface,ptA)[0])< 0.1:
                strInfiniPlane=rs.PlaneFromPoints(ptA,ptB,ptD)
            if vecNormC:
                transPtC=rs.PointAdd(ptC,vecNormC)
                arrLine=[ptC,transPtC]
                interSecPtC=rs.LinePlaneIntersection(arrLine,strInfiniPlane)

            #Typical panel function call:
            PanelA(ptA,ptB,interSecPtC,ptD,vecNormA,vecNormB,vecNormC,vecNormD)

def PanelA(a,b,c,d,vecA,vecB,vecC,vecD):
        crv1=rs.AddLine(a,b)
        crv2=rs.AddLine(b,c)
        crv3=rs.AddLine(c,d)
        crv4=rs.AddLine(d,a)

        #Radius for filletted edges of panels
        dblRadius=rs.Distance(a,c)
        dblRadius=dblRadius/20

        #Filleted curves & curve endpoints
        crvFillet1=rs.AddFilletCurve(crv4,crv1,dblRadius)
        crvFilletPts1=rs.CurveFilletPoints(crv4,crv1,dblRadius)
        crvFillet2=rs.AddFilletCurve(crv1,crv2,dblRadius)
        crvFilletPts2=rs.CurveFilletPoints(crv1,crv2,dblRadius)
        crvFillet3=rs.AddFilletCurve(crv2,crv3,dblRadius)
        crvFilletPts3=rs.CurveFilletPoints(crv2,crv3,dblRadius)
        crvFillet4=rs.AddFilletCurve(crv3,crv4,dblRadius)
        crvFilletPts4=rs.CurveFilletPoints(crv3,crv4,dblRadius)

        #Panel nodes distribution and joining curve
        PtPane1=crvFilletPts1[1]
        PtPane2=crvFilletPts2[0]
        PtPane3=crvFilletPts2[1]
        PtPane4=crvFilletPts3[0]
        PtPane5=crvFilletPts3[1]
        PtPane6=crvFilletPts4[0]
        PtPane7=crvFilletPts4[1]
        PtPane8=crvFilletPts1[0]

        newCrv1=rs.AddCurve([PtPane1,PtPane2])
        newCrv2=rs.AddCurve([PtPane3,PtPane4])
        newCrv3=rs.AddCurve([PtPane5,PtPane6])
        newCrv4=rs.AddCurve([PtPane7,PtPane8])

        crvFace=rs.JoinCurves([crvFillet1,newCrv2,crvFillet2,newCrv3,crvFillet3,newCrv4,crvFillet4,newCrv1])

        #Side Fixing Plates
        NewPtPane1=rs.PointAdd(PtPane1,rs.VectorDivide((rs.VectorAdd(vecA,vecB)),2))
        NewPtPane2=rs.PointAdd(PtPane2,rs.VectorDivide((rs.VectorAdd(vecA,vecB)),2))
        NewPtPane3=rs.PointAdd(PtPane3,rs.VectorDivide((rs.VectorAdd(vecB,vecC)),2))
        NewPtPane4=rs.PointAdd(PtPane4,rs.VectorDivide((rs.VectorAdd(vecB,vecC)),2))
        NewPtPane5=rs.PointAdd(PtPane5,rs.VectorDivide((rs.VectorAdd(vecC,vecD)),2))
        NewPtPane6=rs.PointAdd(PtPane6,rs.VectorDivide((rs.VectorAdd(vecC,vecD)),2))
        NewPtPane7=rs.PointAdd(PtPane7,rs.VectorDivide((rs.VectorAdd(vecD,vecA)),2))
        NewPtPane8=rs.PointAdd(PtPane8,rs.VectorDivide((rs.VectorAdd(vecD,vecA)),2))

        Offnewcrv1=rs.AddCurve([NewPtPane1,NewPtPane2])
        Offnewcrv2=rs.AddCurve([NewPtPane3,NewPtPane4])
        Offnewcrv3=rs.AddCurve([NewPtPane5,NewPtPane6])
        Offnewcrv4=rs.AddCurve([NewPtPane7,NewPtPane8])

        arrDivOffCrv1=rs.DivideCurve(Offnewcrv1,5,False)
        ShortOffEdge1=rs.AddCurve((arrDivOffCrv1[2],arrDivOffCrv1[3]))

        arrDivOffCrv2=rs.DivideCurve(Offnewcrv2,5,False)
        ShortOffEdge2=rs.AddCurve((arrDivOffCrv2[2],arrDivOffCrv2[3]))

        arrDivOffCrv3=rs.DivideCurve(Offnewcrv3,5,False)
        ShortOffEdge3=rs.AddCurve((arrDivOffCrv3[2],arrDivOffCrv3[3]))

        arrDivOffCrv4=rs.DivideCurve(Offnewcrv4,5,False)
        ShortOffEdge4=rs.AddCurve((arrDivOffCrv4[2],arrDivOffCrv4[3]))

        arrSideFix1=[ShortOffEdge1,newCrv1]
        if arrSideFix1 is not None:
            SideFix1=rs.AddLoftSrf(arrSideFix1)
        arrSideFix2=[ShortOffEdge2,newCrv2]
        if arrSideFix2 is not None:
            SideFix2=rs.AddLoftSrf(arrSideFix2)
        arrSideFix3=[ShortOffEdge3,newCrv3]
        if arrSideFix3 is not None:
            SideFix3=rs.AddLoftSrf(arrSideFix3)
        arrSideFix4=[ShortOffEdge4,newCrv4]
        if arrSideFix4 is not None:
            SideFix4=rs.AddLoftSrf(arrSideFix4)

        #Panel base plate outline (with filletted corners)
        arrFace=rs.JoinCurves([crvFillet1,newCrv2,crvFillet2,newCrv3,crvFillet3,newCrv4,crvFillet4,newCrv1])

        #Petal pattern
        dblSwitch=random.random()#random number to generate random patterns
        strDiagonal=rs.AddCurve([a,c])
        arrPetalPtBase=rs.CurveMidPoint(strDiagonal)

        #Pattern threshold

        CrvPetalA=rs.AddCurve([arrPetalPtBase,PtPane1,PtPane8,arrPetalPtBase],3)
        CrvPetalB=rs.AddCurve([arrPetalPtBase,PtPane2,PtPane3,arrPetalPtBase],3)
        CrvPetalC=rs.AddCurve([arrPetalPtBase,PtPane4,PtPane5,arrPetalPtBase],3)
        CrvPetalD=rs.AddCurve([arrPetalPtBase,PtPane6,PtPane7,arrPetalPtBase],3)

        if dblSwitch > 0.7:
            rs.SelectObjects([arrFace,CrvPetalA,CrvPetalB,CrvPetalC,CrvPetalD])
            rs.Command ("_PlanarSrf")
            rs.Command ("_SelNone")
        else:
            rs.SelectObjects([arrFace,CrvPetalA])
            rs.Command ("_PlanarSrf")
            rs.Command ("_SelNone")

        #Brackets
        arrBracketBaseLinePt4=rs.DivideCurve(newCrv4,3)
        arrBracketBaseLinePt2=rs.DivideCurve(newCrv2,3)
        arrBracketBase1=rs.DivideCurve(rs.AddCurve([arrBracketBaseLinePt4[2],arrBracketBaseLinePt2[1]]),7)
        FoldBracket1=rs.AddSrfPt([arrBracketBase1[3],arrBracketBase1[4],arrDivOffCrv1[2],arrDivOffCrv1[3]])

        arrBracketBaseLinePt1=rs.DivideCurve(newCrv1,3)
        arrBracketBaseLinePt3=rs.DivideCurve(newCrv3,3)
        arrBracketBase2=rs.DivideCurve(rs.AddCurve([arrBracketBaseLinePt1[2],arrBracketBaseLinePt3[1]]),7)
        FoldBracket2=rs.AddSrfPt([arrBracketBase2[3],arrBracketBase2[4],arrDivOffCrv2[2],arrDivOffCrv2[3]])

        arrBracketBase3=rs.DivideCurve(rs.AddCurve([arrBracketBaseLinePt2[2],arrBracketBaseLinePt4[1]]),7)
        FoldBracket3=rs.AddSrfPt([arrBracketBase3[3],arrBracketBase3[4],arrDivOffCrv3[2],arrDivOffCrv3[3]])

        arrBracketBase4=rs.DivideCurve(rs.AddCurve([arrBracketBaseLinePt3[2],arrBracketBaseLinePt1[1]]),7)
        FoldBracket4=rs.AddSrfPt([arrBracketBase4[3],arrBracketBase4[4],arrDivOffCrv4[2],arrDivOffCrv4[3]])

        #Clean up
        rs.DeleteObjects([Offnewcrv1,Offnewcrv2,Offnewcrv3,Offnewcrv4,ShortOffEdge1,ShortOffEdge2,ShortOffEdge3,ShortOffEdge4])
        rs.DeleteObjects([crv1,crv2,crv3,crv4,newCrv1,newCrv2,newCrv3,newCrv4,crvFillet1,crvFillet2,crvFillet3,crvFillet4,strDiagonal])

SurfaceQuad()
Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s