Example 2B: Switching between two points, If statements
In the last session, we created our own version of the built-in line component. Now let’s take that previous example and move it a bit beyond what we could have just done with the standard component. Let’s make it so that the component is smart, and that if we give it a choice between two end points it will pick the one which is closest to the start.
Add a new point to the Rhino document and a new Point parameter in grasshopper that references it. Now zoom in on the C# component until the tiny + and – symbols appear. Click on a ‘+’ to add a new input parameter.
Name it ‘PtC’ and set its type hint to Point3d. Connect our new point to it.
Change the code inside the script component to look like this:
Now lets look at what’s going on here, shall we?
Firstly, we calculate the distance between PtA and the other two points. The ‘Point3d’ structure has a built-in function to find the distance between the given point and another one. Functions are subroutines that give an output answer – more on those later.
Once we have these distance values stored we need to compare them and then choose which point to connect to PtA. This is where if statements come in handy:
‘(distAB < distAC)’ is the conditional statement that is being evaluated. If it is true (i.e. distAB is lower than distAC) then the first block of code will be executed and the code will then skip forwards to after the if statement. If it isn’t true then the code skips the first block and goes down to ‘else’ and executes the second block of code.
Note that we declare myLine before we go into the if statement without actually assigning anything to it. This is because variables are only valid inside the scope in which they are declared. If we declared myLine inside the if statement we could not then use it outside it.
If we try this out by moving our points around you should find that the line now automatically jumps to the closest point.
This kind of thing can be very useful for getting your definitions to adapt to different circumstances in an intelligent manner. We could achieve the same thing in native grasshopper by using a Dispatch or Pick ‘n’ Choose component in conjunction with a function component returning true or false and a bunch of other components computing the distance, but it can often be easier and neater to do it in code, especially when things get more complicated.
Example 3A: Creating a truss, Lists and Loops
For performing repetitive operations on a large number of inputs grasshopper has lists and trees, but it still cannot be used for many complex iterative operations that would be relatively easy to implement in code.
This next example takes in two lists of points and iterates through them to draw a zig-zag line between them, as you might want to do to create part of a truss structure.
Firstly we will create two lists of points by subdividing curves. Draw two roughly parallel curves in Rhino and bring them into grasshopper via some Curve components. Pass those curves into a pair of Divide Curve components to generate two lists of points.
Now we will bring those two lists into a C# component. Create a new one and set the type hint for both x and y inputs to Point3d. Since we are no longer bringing in single values we need to tell the component to treat x and y as lists of objects rather than individual objects. To do this right click on each input and select the ‘List Access’ option.
If we take a look inside the script editor for that component now we will see that the type of x and y parameters have changed to List<Point3d>. Lists are generic containers that can be used to hold any other type of object. The type to be used is defined inside the angle brackets (‘<’ and ‘>’). They function similarly to arrays but with extra functionality and with the bonus that they will automatically resize themselves when new items are added. Get used to them because you are going to be using them a lot!
Plug the two lists of points into x and y and in the script editor add:
First of all I rename our inputs ptsX and ptsY by defining new Lists of Point3d variables and assigning x and y to them (the reason why I do this will become clear in example 3B).
Since we are going to create more than one line this time around we need to create a new list to hold them all in one place so that they can all be output to A as a group. Lists are a type of object so to create one we need to use the new keyword. We define the type it will contain inside the angle brackets after the type name (in this case, the list will hold lines). Even though we are using the default constructor and aren’t entering any parameters to initialise the list with, we still have to include a pair of empty brackets when creating the new list.
Next we begin our loop – in this case a for loop, meaning that we are going to iterate a particular variable until a certain condition is met. The brackets behind the ‘for’ are split into three sections separated by semicolons.
The first part tells the for loop what to iterate. In this case we create a new integer variable called ‘i’ and set it to a starting value of 0.
Next we tell it when to iterate (and when to stop). In this case we give it the condition to continue iterating while i is lower than the number of points in ptsX – which we retrieve by using the ‘Count’ property of that list.
This means that when i is larger than or equal to the number of points the loop will exit and continue with whatever is next in the script. We do this so that the loop will execute once for each item in the list.
Finally, we tell the loop how to iterate. In this case we use the ++ operator, which in C-like languages means ‘add one to’. We could also have written this as i += 1 and gotten the same result – each time the loop has executed it will add 1 to the current value of i and start again (provided the condition we just gave it in the middle part is still true).
The next part inside the curly brackets is the block of code that will be repeated by the loop.
We start by picking the points from the list that we want to use. You can access a particular item from a list by enclosing its index (its position in the list, starting from 0) in square brackets after the name of the list. In this instance, we are picking the points from ptsX and ptsY that are at position i – meaning that as the loop iterates and i increases we will retrieve every pair of points in the two lists. We store the points in new variables called ptA and ptB and then draw a line between them the same way as we have done previously.
Once we have created our line we use the Add() subroutine to append that line to the back of our output list.
Finally, outside of the loop, we assign our output list to our output object A.
This example so far will create a ‘ladder’ between the two initial curves by joining equivalently numbered points. Essentially we have replicated in code Grasshopper’s default data-matching option, where the first item in each list will be processed together, the second in each list also matched and so on.
The next step in creating the ‘zig-zag’ is to also join up the first list of points with an offset of the second list of points. To do this with grasshopper components we could use the Shift List component to create an offset copy of the initial list. However, in code we can do this in a more direct (and efficient) fashion.
Add the following to the end of the block of code inside the for loop:
This section of code finds the next (the ‘i+1th’) point in the list ptsY and then creates a line between it and our original ptA, then adds that line to our output. This will create the diagonals of our zig-zag truss bracing.
However, if we now press ‘OK’ to close the script editor, we will see that something has gone wrong. The script component has gone red and is no longer outputting any geometry at all!
To find out what has gone wrong hover your mouse either over the ‘out’ output or the small red error speech bubble that will have appeared in the top right of the component. Doing so, you should get something like this:
Why are we getting this error? Well, let’s imagine we have eleven points in each of our input lists, stored in locations 0-10. When i = 10 in our code, ptA will be ptsX(10), ptB will be ptsY(10) and ptC will be ptsY(11), which will be something of a problem because there is no ptsY(11) – our index is outside the bounds of the list.
For our script to run successfully we will need to stop this from happening. We can do this by placing an if statement around the piece of code we just added to make sure it is not trying to add a diagonal when i is already the last item in the list.
So, our complete script should now look like this:
Which should produce our zig-zag lines:
You can download the example grasshopper files for this session here: