Recursions with python


i need to rotate a list of surfaces ( stripes ) around a given list of axes and according to a corresponding list of angles

the starting position is for instance this

the list angles is for example this


point is that i want to make it in a recursive manner meaning that the first angle applyes to all stripes while the second to all stripes minus the first and so on, the result i need is this

I have very limited experience with python and limited time for studying and i am not able to achieve the result

if anybody can help me and show me how to solve it i’d appreciate.


20240511 STRIPES ROTATION.3dm (110.6 KB)
20240511 STRIPES (9.5 KB)

The key is to set the input to python component to List Access. This way the list can be processed in the Python script with a for loop.

More details on the input properties here:

In addition to what Scott said, you also probably should use type hints in your python components. I usually do.

Anyway, I made a grasshopper definition that creates the lines as it was easier to control the order the lines get processed, but I guess we could take manually created lines and sort them by location somehow.

I didn’t use pure recursion, but it could be adjusted to use pure recursion if that is necessary for some reason.

I basically pop the first line off the list of lines and rotate all the other lines around the line we popped off using the current angle.

You would add more panels by adding more angles. I wasn’t sure of the orientation, because the Rhino file was strange (you had renamed the viewports so that several had the same name and that confused me about desired orientation). And the angles might need to be negated if they are rotating in the wrong direction. I recommend creating fresh, new Rhino file and then open this grasshopper definition in that new file, that way the viewports will have the default names…unless you need it the way the other file is set up.

I used Rhino 8, but I have Rhino 6 and Rhino 7 if needed. Let me know if you have any questions. If I can help you understand, I will.

Oh, you need to right-click the last component and choose bake to make the panels real objects in Rhino. (10.7 KB)

Hi Scott and thanks for your suggestion, yes i have been using GH for a while now and the concept of list is clear , i also went through several PY tutorial and the need to arrange items in list in order to iterate through them is, let me say, clear now.
My undestanding is that when i set input to “item access” this work pretty much like “graft” in GH , while when i set to “List access” this is pretty much like flattening in GH ( i haven’t tried “tree access” yet )

Other than this what is giving me a very hard time is how to handle these lists in python , logic is say clear now but the syntax is the problem, the help material is great but it is soo much stuff that easy for me to get lost.
As prooved in the past for me, studying a specific case in which i am working is best way to make a step forward on the learning process but as i said i am stuck .

if anyone can show me the right way i appreciate, anyway on saturday i can spend sometime to study and i will post the eventual progress.


yes i try to but as a beginner i have to say that this are criptic

thanks , as i can see you have used the new GH8 editor, i never used it before because to me it makes things more complicated …all tutorials on the web are based on previous GHPY 2.7 editor editor which looks more minimal and easy to me (BTW , the zoom in/out does not work in the new and makes reading hard for me).

BTW 2 i also have 2 errors , i have checked and all inputs are set to List but there is something wrong which i am not able to explain

i am also confused , so many libraries…as i undestand by importing the ghpythonlibcomponents library you have access to i guess gh methods…where have rhinoscriptsyntax gone , most tutorials on the web have been based on tha library until now?


i am struggling man…i feel sooo confused !! too much stuff too little time…for example if i call one of the methods in the script editor i can’t see the help…how can i know what the method’s argumets are ?

in the old editor there was a support editor + there is the page with all methods Rhino - RhinoScriptSyntax

Python 2.7 editor was already confusing me , now with the new editor ( which BTW seems better , for example the error warning seems to have better readibility ) i am adding confusion to confusion.

point is that i really want to learn but i am struggling , facing GH was like drinking a glass of water in camparison…i am soo frustrated.

i feel one step ahead from understanding your script but then new doubts arises and i am never able to achieve any goal, i have commented with AAA your script…i pretty much understand the structure but ithe doubts has increased , i never used these libraries and neither PY 3 + i dont unerstand the error

I didn’t use the rhinoscriptcontext library because it was complaining about GUIDs or something. So I switched to the grasshopper library and it didn’t complain. Don’t worry about the Rhino.Geometry library. I didn’t use it anyway.

Regarding the errors, I feel like you must have changed something in the part of the definition I can’t see.

I cleaned up the code a bit. See if this is easier to understand. (11.8 KB)

Also, you should get a function help window when you open the parens of a function. Like this. I think you might need to update your Rhino.

Hi William and thanks a lot for your quick answer and support

starting from end , i checked the version and it’s the latest available

i actually didn’t change anything , i downloaded your latest script and the erroros are still there :frowning:

i have to report that also the help is not working in my editor , i tried with F1 , double clicking atc but it’s not showing up

You can change “update frequency” to Service Release Candidate and then click on check now to get a later build. I don’t know if it will solve the issue, though.

Regarding the error, it’s like you’re getting null objects, but I don’t know why.

Also, I rewrote the scripts using rhinoscriptcontext, that might help you a bit. It made the code a little bit simpler, too. (14.8 KB)

1 Like

thanks again for your valuable support William , i realy appreciate !!!
actually after updating as you suggetsed i have both scripts working and doing almost what i need to , so the real problem was exacltyl the unupdated Rhino version

Another good news :smiley:, the help works

last but not least i see the result of the script and it all make sense now , yes this si very close to what i want the logic i want to obtain , the only difference is that your script is rotating on XY plane while my wish is to update the rotation plane or axis and rotate according to the rotate lines coming out form previous iteration from which the loft is generated.

I am sorry i realized only now that my explanation above was not clear but this is the reason why i was talking about recursions…if i am not wrong being the rotation axis dependent on modified ( rotate line ) a recursive logic is necessary

I have to thank You because i also learnt the list.pop method which i never used before

1 Like

I’m glad updating fixed the help function for you and that my script is close to what you want.

I have updated the script to allow changing orientation (Y-axis or Z-axis), and I have replaced the code that created the loft surfaces with a loft component (but you will have to explode it if you want separate panels)

I have also added more comments to the python script. (14.1 KB)

It might not be obvious, but my code does always use the previous line as the point of rotation. Well, the start point of the previous line, at least.

Here is a Rhino .3dm file that shows how the lines would look after each iteration of my code. In each iteration, the red line is the center of rotation.

code iteration visual.3dm (126.2 KB)

1 Like

this is soo helpful , i really appreciate , the comments are super useful!!!

Hi William, you are right , actually what i meant to say was that the script was not using the line but the point + plane to rotate

i apologize but i have a few more questions, and this is a great learning opportunity, if you could answer i’d really appreciate :

  • whats the reason for using ghpythonlib.components rather than rhinoscriptsyntax ?
    ( is it correct to say that the first allow using GH methods inside the written code while the latter allow using python ? )

  • does calling rhinoscriptsyntax inside PY2 component automatically imply that i have to use python2.7 while importing same library in to PY3 component imply the use of Python 3 thus meaning that the same library work either on python 2 and python 3?

  • could you explain what’s the utility of the “.ToNurbsCurve” on line 20 ( i tried to get rid of it but i get an error but if i call the rs.CurveStartPoint method and look at the help it does not show this string on the arguments and i cannot find it on the rs methods either but i think i found it on rhinocommon help ( ). is it as passing a line through a crv component in GH ?

thanks again


William , could you take a look to attached definition ?

i tried to add the possibility to rotate within respect to the Line ( orientation = 2 ) but it does not work.

many thanks (13.7 KB)


what i meant to say was that the script was not using the line but the point + plane to rotate

As long as the lines maintain their original orientation (parallel to the Y axis or parallel to the Z axis), it does not matter. If you want each line to have its own rotation, then, yes, we must use the whole line as the axis of rotation, this can be done, I’m sure. But it will be more complicated.

whats the reason for using ghpythonlib.components rather than rhinoscriptsyntax ?
( is it correct to say that the first allow using GH methods inside the written code while the latter allow using python ? )

Both are simply libraries that python can use. ghpythonlib.components gives python access to grasshopper components. rhinoscriptsyntax gives python access to most (all?) of the Rhino Common library, which you can access by the line import Rhino rhinoscriptsyntax is usually easier to use than Rhino Common.

You can use whichever you want. Many of the grasshopper components do the same things that regular Rhino commands do (rotate, move, scale, etc). rhinoscriptsyntax seems easier to use to me, so I generally choose that one unless there is a specific grasshopper function that rhinoscriptsyntax can’t do.

In this case, I was getting an error with rhinoscriptsyntax and I don’t know why. So I switched to the grasshopper library and it worked. However, later I did it with rhinoscriptsyntax and it worked, too. So I was probably doing something wrong the first time.

does calling rhinoscriptsyntax inside PY2 component automatically imply that i have to use python2.7 while importing same library in to PY3 component imply the use of Python 3…

I’m not 100% certain, but I think so.

…thus meaning that the same library work either on python 2 and python 3?

Python3 stuff will not work in the python2 component. And there might be some iron python 2 stuff that doesn’t work in a python 3 component, but I’m not 100% certain about that.

could you explain what’s the utility of the “.ToNurbsCurve”

Yes, the rs.CurveStartPoint() function was expecting a Curve object. ToNurbsCurve() converts the Line object to a Curve object. You often need to do that to Arcs and Circles, too, as they are not considered Curve objects either.

1 Like

With regards to rotating with respect to the lines, I think it might help if I understood what you are ultimately trying to do with this. Like, what are you trying to make? What’s the end goal?

HI William,

first of all many thanks for above very useful informations.
what i am trying to do is to estimate the projected aerodinamical parameters of a inflatable kyte that i’d like to design and make.

in short i will start from a flat piece of fabric , apply rods along the folding lines ( our rotation lines ) and shape the frame and wiring in order to attempt achieving such a 3D shape.

immagine that right now you are starting from flat and then transforming the panels by rotating along lines in order to get the 3D shape…if i take the generated 3D polisrf and flatten if back again on a plane it should match the flat polisurface from which it was generated .


i have been able to modify your script and use the line as axes for rotation :smiley:

I had to remove the change to choose the different rotation options because when declaring the axis as third choice there was something not working but other than that this is what i need and i want to thank You very much because without your support I’d never been able to achieve this result.

many thanks for your time and for the very clear explanation and commented scripts

kindest regards (15.8 KB)

1 Like

You’re welcome. Yes, using the line to create a vector is exactly how you would do that. So, I’m glad you figured it out. I was going to do that for you today, but you figured it out already. Good job.

However, I think it’s worth noting that as long as all the lines are parallel to the Y axis, there is no need to calculate the vector for each line because the direction for ALL the vectors (in this case) are parallel to the Y-axis. So you can just use the generic Y vector (0, 1, 0). It is only the direction of the vector that matters in the rs.RotateObject() function, the point called center_of_rotation provides the location for the rotation to occur. And so the results, as you can see, are exactly the same.

Now, if you plan on rotating the lines so that they are no longer parallel to the Y-axis, then, yes, in that case, it becomes necessary to get the vector of the line (just as you have done).

Also, since you removed the orientation feature, and if you will always have your lines parallel to the Y-axis, you can simplify the part that creates the first line by removing the python node and plugging surface height into the Y slot of the second point component…like so…

Something else I like to do is add a container for the final object and put under the inputs, so that I can quickly bake the final object after adjusting the inputs. I set the wire display to hidden on that component for neatness.

Here is a version that makes those two adjustments. (13.7 KB)

And here is a version that might not be useful for your kite construction, but it makes use of the feature you added where you use the vector of the previous line for the rotation axis. In this one, the lines are twisted so as to no longer be parallel to the Y-axis and thus in this case we NEED the vector of each line. (16.7 KB)

thanks Bro , you drove me on the right rout but it was a great achievement to me :grinning:

yes i see what you mean but as you pointed out Y parallel lines is not expected to be a common case , due to panels torsion I will be mostly rotating around generic lines so this upgrade was let me say a must to me

I will mostly design the flat view of the kyte and after that i will apply the arc shape so the flat lines to start from does not need to be created in to the script but will most likely refenced from rhino

very useful suggestion , makes lot of sense , thanks

you anticipated me William , this was something i was about to implement , thanks , i only have 1 question: why doesn’t the list twisted_lines contains also a copy of the unrotated lines ?
the last argument on the method call is set to Copy=True and the result is appended to the list; i was expecting to have the original object + the transformed ( rotated ) copy both inside the list

(sorry, somehow I accidentally posted this way before I was done writing it, so I deleted that post)

I had originally intended to set copy equal to false. But it wasn’t working for some reason, so I set copy to true and created a new list from the copied and rotated lines. I think when copy is set to true, only the copy gets rotated, but i’m not 100% sure about that.

However, I have gone back and redid it the way I wanted to originally ( with copy set to false) and it seems to be working fine now, and the code is simpler.

import rhinoscriptsyntax as rs 

# rotation vector for twisting will be X axis of world
vector = (1,0,0)

# twist angle will be multiplied by the index
for i in range(len(lines)):
    rotation_angle = twist_angle * i 
    crv = lines[i].ToNurbsCurve()
    center_point = rs.CurveMidPoint(crv)
    rs.RotateObject(lines[i], center_point, rotation_angle, axis=vector, copy=False)

twisted_lines = lines (17.1 KB)

I’m definitely curious to see how this turns out for you.

1 Like