Quantcast
Channel: Scripting - McNeel Forum
Viewing all articles
Browse latest Browse all 5875

Pattern maker with dynamic preview

$
0
0

@Gijs wrote:

I picked up this script that I once made in rhino script and enhanced it with new options and dynamic preview.
I think the usage is quite self explanatory.

There are a few more things I want to implement as you can see in the comments, but I'm also open for others' suggestions.

"""
This script allows you draw make patterns from multiple curves at once.
It assumes all curves are more or less the same size, and have a reasonable
width and height to begin with.
It will then randomly use the curves to make a pattern.
The pattern is then applied to a boundary curve that must be closed.
It uses getpoint in order to enable dynamic redraw when changing the pattern 
settings.

***********************************
* script written by Gijs de Zwart *
* www.studiogijs.nl               *
* April, 2016                     *
***********************************


implemented:

* user selects 1 or more curves to use as pattern
* user selects boundary to fill (closed curve)
* boundary gets filled with a preview of the endresult
* curves outside the boundary are removed
* curves that intersect with the boundary are removed
* pattern looks at the size of the curve(s) (boundingbox) to get correct spacing
* possibility to enter a margin from the border of the boundary
* possibility to give curve(s) a random scale/ rotation
* possibility to offset each row

to do:
possibility to scale the curve(s) that are used in the boundary
possibility to flip curve(s)
error checking
"""
import rhinoscriptsyntax as rs
import Rhino.Geometry.Curve as Curve
import random as rand
import Rhino
import System.Drawing.Color as Color
import scriptcontext as sc

def RunCommand():

    class fillcrv():
        def __init__(self,crv):
            bbox=crv.GetBoundingBox(True)
            self.crv=crv
            self.width=bbox.Max.X-bbox.Min.X
            self.height=bbox.Max.Y-bbox.Min.Y
            self.h_space=self.width
            self.v_space=self.height
            self.lower=bbox.Min


    def getSpace(offset, space):
        #returns horizontal and vertical space and row offset (skew)
        h_space=0
        v_space=0
        for crv in curves:
            if h_space<crv.h_space:
                h_space=crv.h_space

            if v_space<crv.v_space:
                v_space=crv.v_space
        h_space+= h_space*space/100
        v_space+= v_space*space/100
        h_skew=h_space*offset/100
        return [h_space,v_space,h_skew]

    def CalcStartCondition(boundary):
        #returns width, height and startpoint transformation
        #and changes boundary to offset margin if requested

        bbox=boundary.GetBoundingBox(True)
        cen_boundary=bbox.Center
        plane=Rhino.Geometry.Plane.WorldXY
        plane.Origin = bbox.Min

        b_width=bbox.Max.X-bbox.Min.X

        b_height=bbox.Max.Y-bbox.Min.Y

        #calculate translation vector from curve to boundary
        start=bbox.Min-curves[0].lower

        return [b_width, b_height, start, boundary]

    def CreatePatternCurves(v_amount, h_amount, v_space, h_space, h_skew, start, boundary):
        #creates patterned curves in rectangular grid
        trans=start
        reset=start[0]
        odd=0
        i=0

        patterncurves=[]
        for y in range(0,v_amount):

            #reset transformation in x-direction
            trans[0]=reset

            if odd%2==1:
                trans[0]+=h_skew
            odd+=1
            for x in range(0,h_amount):

                i=rand.randint(0,len(curves)-1)
                copy=curves[i].crv.Duplicate()
                copy.Translate(trans)
                cen=copy.GetBoundingBox(True).Center

                random = optRandom.CurrentValue

                if random and copy!=None:
                    rnd=rand.randint(90,110)/100
                    rot_rnd=rand.uniform(-.1,.1)
                    scale=Rhino.Geometry.Transform.Scale(cen,rnd)
                    rotation=Rhino.Geometry.Transform.Rotation(rot_rnd, cen)
                    copy.Transform(scale)
                    copy.Transform(rotation)

                #check if point to copy is inside boundary and margin
                margin=optMargin.CurrentValue

                if boundary.Contains(cen) == Rhino.Geometry.PointContainment.Inside:

                    #check if it intersects with the boundarycurve:
                    #uses intersection tolerance to leave a margin
                    intersection_tolerance = margin+0.01
                    overlap_tolerance = 0.0
                    intersections = Rhino.Geometry.Intersect.Intersection.CurveCurve(
                                        boundary,
                                        copy,
                                        intersection_tolerance,
                                        overlap_tolerance
                                        )
                    if not intersections:
                        patterncurves.append(copy)

                #increment horizontal transform
                trans[0]+=h_space

            #increment vertical transform
            trans[1]+=v_space

        return patterncurves

    def fillBoundary(crv,boundary, offset, space, random):
        #returns pattern curves within boundary
        b_width, b_height, start, boundary = CalcStartCondition(boundary)
        #determine horizontal and vertical spacing and skew
        h_space,v_space,h_skew = getSpace(offset, space)

        # calculate amount of curves needed
        h_amount=int(b_width/h_space)+1

        v_amount=int(b_height/v_space)+1
        #create the pattern
        patterncurves=CreatePatternCurves(v_amount, h_amount, v_space, h_space, h_skew, start, boundary)
        return patterncurves


    def OnDynamicDraw(sender, e):
        #try:
        random=optRandom.CurrentValue
        offset=optOffset.CurrentValue
        space=optSpace.CurrentValue
        h_space,v_space,h_skew = getSpace(offset, space)
        patterncurves = fillBoundary(curves, boundary, offset, space, random)

        for curve in patterncurves:
            e.Display.DrawCurve(curve, Color.LightCyan, 1)
        """
        except Exception as ex:
            template = "An exception of type {0} occured. Arguments:\n{1!r}"
            message = template.format(type(ex).__name__, ex.args)
            print message
            return
        """

    def addPatternToRhino():
        if boolCanOffset==False:
            print "couldn't offset curve, used boundary instead"
        patterncurves = fillBoundary(curves, boundary, offset, space, random)
        for i in range(0, len(patterncurves)):
            sc.doc.Objects.AddCurve(patterncurves[i])
        sc.doc.Views.Redraw()

    boundary = rs.GetObject("select boundarycurve to fill", rs.filter.curve)
    if not boundary:
        return
    boundary = rs.coercecurve(boundary)
    crvs=rs.GetObjects("select curves to use as pattern", rs.filter.curve)
    if not crvs:
        return
    if not boundary.IsClosed:
        return

    curves=[]
    for crv in crvs:
        crv=rs.coercecurve(crv)
        crv=fillcrv(crv)
        curves.append(crv)

    gp=Rhino.Input.Custom.GetPoint()
    gp.SetCommandPrompt("pattern properties")

    optMargin=Rhino.Input.Custom.OptionDouble(0,0,100)
    gp.AddOptionDouble("margin",optMargin)

    optRandom = Rhino.Input.Custom.OptionToggle(True, "Off", "On")
    gp.AddOptionToggle("add_randomness", optRandom)

    optOffset = Rhino.Input.Custom.OptionInteger(50,0,100)
    gp.AddOptionInteger("offset_percentage",optOffset)

    optSpace = Rhino.Input.Custom.OptionInteger(50,0,500)
    gp.AddOptionInteger("space_percentage",optSpace)
    gp.DynamicDraw+=OnDynamicDraw

    #start collecting user options
    while True:
        gp.Get()
        if gp.Result()==Rhino.Input.GetResult.Option:
            continue
        break

    random=optRandom.CurrentValue
    offset=optOffset.CurrentValue
    margin=optMargin.CurrentValue
    space=optSpace.CurrentValue
    boolCanOffset=True

    addPatternToRhino()
if( __name__ == "__main__" ):
    RunCommand()

Posts: 3

Participants: 2

Read full topic


Viewing all articles
Browse latest Browse all 5875

Trending Articles