Offset multiple curves Python

Hi,

I am lost. Should I use a for loop to offset multiple curves? I don’t understand how to allow a for loop to access each curve in a list sequentially.

I am trying to use Python’s ‘len’ to gather the length of the curves selected to offset. The script is unfinished as I can only get it to work for one curve.

Thank you for the help!

import rhinoscriptsyntax as rs

crvList = []

crvs = rs.GetObjects("selectCrvs")
offsetDistance = .0625
crvList.append(crvs)

crvList2 = []

for i in range(len
    offsetA = rs.OffsetCurve(crvList, [0,1,0], offsetDistance )
    offsetB = rs.OffsetCurve(crvList, [0,-1,0], -offsetDistance )
    crvList2.append(offsetA)
    crvList2.append(offsetB)
    
    print crvList

rs.DeleteObject(crvs)
rs.ObjectLayer(crvList,"Thin")

I think I’m missing something rudimentary.
In this code I cannot figure out how to add multiple lines.

import rhinoscriptsyntax as rs

crvList = []
crvList2 = []
crvList3 = []

obj = rs.GetObjects("selectCrvs")
crvList.append(obj)

divideA = rs.DivideCurveLength(obj[0], .5, True, True)
divideB = rs.DivideCurveLength(obj[1], .5, True, True)
crvList2.append(divideA)
crvList3.append(divideB)

lines = rs.AddLine(divideA, divideB)

print lines

This does not work like Grasshopper with automatic list matching.

divideA and divideB are lists (of 3d points). To add lines between the corresponding points, you need to iterate through both lists and add one line at a time, you cannot just feed the two lists to rs.AddLine().

for i in range(len(divideA)):
    rs.AddLine(divideA[i],divideB[i])

However, if the two curves are not the same length, the point list length may not be the same, so you will get an error if divideA is has more elements than divideB.

HYH, --Mitch

Thank you Helvetosaur,

Your usage of the ‘for loop’ here makes sense; however, I am still confused when I adapt it to divide multiple curves. It works sufficiently, but I am a bit confused how the variable ‘i’ causes this to work.

obj = rs.GetObjects("crvs")

for i in range(len(obj)):
    rs.DivideCurve(obj[i],10,True,True)

The variable ‘i’ is used as a counter here. The function ‘range’ creates a series of numbers starting by default from 0 to the number specified, in this case the length of your list 'crvs". The for loop iterates through list indices and does its thing on each item in the list.

If you only have one list to iterate through, you do not necessarily need to use a counter.

objs = rs.GetObjects("crvs")
for obj in objs:
    pointlist=rs.DivideCurve(obj,10,True,True)

The for loop will iterate through each item in the list once that way.

The reason I used a counter in the first example is that to make the lines, I was iterating through two lists (A and B), in parallel and wanted to make sure that the indices for each list were the same at each iteration.

HTH, --Mitch

Thanks Helvotosaur,

I appreciate the explanation. One final question is concerns how Python handles multiple lists.
For instance, I don’t understand why this code here does not yield 22 pts, but 11. I am inputting two lines to divide. I thought I would get two separate lists, but I think I am going about it wrong and don’t understand exactly how Python handles this type of list. I wish to choose indices from each list and draw perp lines like ‘flip matrix’ does in Grasshopper.

thanks again, I really appreciate your insight.

import rhinoscriptsyntax as rs

obj = rs.GetObjects("choose curve") #input two lines

for i in range(len(obj)):
    divide = rs.DivideCurve(obj[i], 10, True, True)
    
print len(divide)

Well, again, Grasshopper has many automatic/intelligent features that scripting doesn’t.

What is happening in your loop is that the variable ‘divide’ is indeed receiving the result of DivideCurve(), but every time it loops, the data in the variable is replaced - so you only get the last result. If you need to collect the different results, you will first need to create an empty container, and then add (append) the results at every iteration.

objs = rs.GetObjects("choose curves") #input two lines
div_pts=[]
for i in range(len(objs)):
    divide = rs.DivideCurve(objs[i], 10, True, True)
    div_pts.append(divide)

The above will get you a nested list - a list of lists - each list having the divide points of each of the curves in ‘objs’. If you want to then draw lines between the corresponding items in each list (I’ll assume just two input curves for the moment so we can draw a line) it’s not too hard, but you need to use an advanced user trick or two. First, in order to simulate the results of your “flip matrix” GH component, we can use the really cool python function “zip” along with an asterisk which represents list or tuple “unpacking”… Zip “zips” together items from multiple lists; the ‘*’ “unpacks” each sublist in a nested list first so that zip can put together the corresponding items. The result will get you 11 lists of two corresponding points. Then you can iterate through those and make lines.

objs = rs.GetObjects("Choose curves",4, minimum_count=2, maximum_count=2) 
div_pts=[]
for i in range(len(objs)):
    divide = rs.DivideCurve(objs[i], 10, True, True)
    div_pts.append(divide)

pairs=zip(*div_pts)
for item in pairs:
    rs.AddLine(item[0],item[1])

HTH, --Mitch

1 Like