Aug 142014
 

Daniel Piker’s Kangaroo plug-in for Grasshopper allows us to set up and run various kinds of physical simulation within Grasshopper.  Although we will not cover Kangaroo itself on this course, in this session we will look at a way of writing our own Kangaroo-like simulation code, allowing us to write custom simulators should the need arise and also understand how Kangaroo is (probably) working behind the scenes.

A full multi-purpose physics engine is probably a bit beyond what we are capable of producing in an hour, so instead we will focus on a specific physical phenomenon – gravitation.  We will produce code that simulates a set of particles, all of which have a gravity-like attraction towards each other.

As usual, we’ll first set up a C# component with the inputs we need, which are:

C#6_1

pts – List Access – Point3d
dt – Item Access – double
reset – Item Access – bool

Enter into the pts input a set of points which will define the starting positions of all of our particles.

C#6_2

Before we begin coding, it is useful to understand a little more about Object-Orientated Programming, which is so-called because it involves the use of Objects.  An object is a group of different bits of data (properties) and processes (methods) that represent a single conceptual entity.  C# is an object-orientated language and we have been using objects all along – the points, lines, curves and so on that we have been creating and manipulating are all objects, as are the more abstract entities such as Lists and the random number generator we used in a previous example.

As each particle in our simulation will need to have several different properties, we will create a class in order to encapsulate all of that data into a separate object for each particle.

We will write our Particle class in the ‘custom additional code’ section of the scripting component and it will go a little something like this:

C#6_3

That’s a fairly big chunk of code, so we’ll go through it bit-by-bit.  First of all we declare the class definition by writing:

C#6_4
The keyword for creating classes is, obviously ‘class’, which is followed by the name we want to give the class; in this case ‘Particle’.  Everything inside the curly brackets that follow will be part of this class.  The order these things are in does not particularly matter, but we will start by declaring the properties of the class:

C#6_5This works similarly to declaring a local variable inside a function, however we have added the ‘public‘ keyword to the front – this means that these properties will be accessible from outside the class.  If we instead wanted to make it impossible for these properties to be interfered with from outside the class itself, we could instead use the keyword ‘private‘.

We have given the Particle class three properties – ‘position’ is a Point3d and represents the current position of the particle, ‘velocity’ is a Vector3d and represents the current velocity of the particle and ‘trail’ is a list which will be used to hold all previous positions of the particle.

Having declared these three properties, we will now add functions which we can use to manipulate them.  Firstly, we will create a constructor.  A constructor is a function called when we create an instance of the class and whcih is used to set up the initial state of the object.  Whenever we have previously use the new keyword we have been initialising an object and in the process calling some kind of constructor function.  We can pass in information to the constructor to tell it how we want the object to be initialised – for example previously when we have created a new Line object and passed in two points, those were then being consumed by a constructor function which used them to set up the geometry of the line.  We can have multiple constructor functions with different arguments to allow us to set up objects in different ways, however in this case we will only use the one, which takes in a Point3d:

C#6_6Constructors are declared using the name of the class as a function name (in this case ‘Particle’) and omitting a return type.  The inputs to the constructor are declared exactly the same way as the inputs to a function – in this case we declare an argument called ‘startPosition’ of type Point3d.  Within the constructor function we set the Particle’s position property to the startPosition passed in and also initialise the velocity as a new Vector3d (which, without inputs, will start as (0,0,0)) and initialise the trail property as a new List of Point3ds.  This will then set up each particle ready for use.

Note that above the constructor function is some text denoted by three forward slashes.  This is a special kind of comment that, when placed just before a function definition can be used to add metadata about that function and its parameters.  In any decent C# IDE, these special comments will pop up interactively whenever we use the function to give a description of how to use the function and what the input parameters represent and can also be used to automatically generate documentation (such as the RhinoCommon docs, which is entirely derived from these kind of comments in the source code).  Sadly, the C# editor in Grasshopper is not a decent C# IDE, but it is still worth getting into the habit of adding these anyway.

Next, we’ll add some methods.  These are functions on the object that can be called to manipulate it in various ways.  We will write a function to update the position of the Particle based on its own current properties, called ‘Move’:

C#6_7This function does not return anything (hence the ‘void‘ return type) and takes in a double called ‘dt’ (short for ‘delta time’).  This variable represents (nominally, at least) the time that has passed since the last time the Particle was moved and is used as a scaling factor for the particle’s velocity.  So if, for example, the current velocity was 1m/s and we passed in a dt of 0.5s, we multiply one by the other to find out how far the particle has moved in that time step.

Before we do that, we add the Particle’s current position to the end of the trail list (so that we have a record of all previous locations) and then modify the position by adding the velocity vector multiplied by the time step.

C#6_8Finally, we add a static function to deal with the attraction between particles.  Static functions do not act on a specific instance of a class and nor do they require an instance of the class in order to be called – you can access them just by typing the class name followed by a ‘.’ and the method name (i.e. ‘Particle.Attract(…)’).  We have used static functions before as well – most RhinoCommon classes have some static functions, such as the function to create a curve through a set of points that we have used previously (and will also do later on).  Note that execution-wise there is no particular benefit to making this function a static function on the Particle class rather than an ordinary function in our script component – it is merely a way of organising your code (and I’m doing it here mainly to demonstrate where the static functions on other object types come from).

The function itself takes in two particles and applys a pseudo-gravitational attraction between them over a period of time ‘dt’.  Newton’s law of universal gravitation is:

F = G(m1*m2)/r^2

In other words; the gravitational force between two masses is equal to the gravitation constant G times the mass of the first object times the mass of the second divided by the square of the distance between them.  In our case we don’t care too much about being exact, so I’ve assumed that m1, m2 and G are all equal to one (it’s our own little universe, we can do what we like) and excluded them.  To find the acceleration we need to apply to each particle we then multiply that force by the timestep.

So, to begin with we find the vector that points from our first particle to our second.  We then find the length of that vector (the distance between our points).  Before we continue, we check to make sure that this distance is greater than 0 (otherwise, we would get a divide-by-zero error).

We then unitize the direction vector and multiply that by the timestep over the distance between the points squared – this gives us the acceleration vector to apply to each point.

[Note: With scripts like this that will run in real-time, optimising the code so that it runs quickly and responsively becomes more important.  One optimisation that could be applied here (but that I haven't to keep things clear) would be to eliminate the separate call to Unitize() and instead just increase the power applied to the distance in the subsequent calculation by one (i.e. AtoB = dt/Math.Pow(distance, 3)).  Since the Unitize() function simply divides a vector by its own length this will result in the same answer, but will avoid having to recalculate the Vector length as part of the Unitize() operation.]

Finally we apply the acceleration to the particle velocities.  Since the vector points from particleA to particleB, we add it to particleA’s velocity to accelerate it towards B, but subtract it from particleB’s velocity to move it towards A.

That concludes all the code needed for our particle class – now let’s use it!

First, we’ll need a persistant way of storing our particles.  Just above the Particle class definition, within the ‘Custom Additional Code’ section, add:

C#6_9

This list will be used to store all of our active particles.  The beauty of declaring this outside of any particular function is that it will become a property of the script component class itself and as such will not go out of scope once our RunScript function has ended.  This means that the data will be retained – the next time we trigger an update on the component and RunScript is called, the particles list will still contain exactly the same thing it contained the last time RunScript finished.  This allows us to have a set of Particles that persist between firings of the component.  Each time the component is triggered, we will update the particles in this list slightly.

Now, finally, on to the main RunScript function, which will look like this:

C#6_10

To begin with, we need a way of setting up the initial state of the simulation.  Whether this bit of code will be run or not depends on whether the ‘reset’ input is set to true.  If so, we will use this to restore the simulation to it’s starting condition – otherwise we will allow it to progress using its current state.C#6_11We first overwrite the particles list with a new, empty, list of particles.  For each point that we’ve input we create a new particle by using the new keyword.  We pass in the point as an argument to the constructor that we wrote earlier, which initialises the Particle position to be at that point.  We then add the particle to the particles list.

When the reset option is false, we instead run the actual simulation.

The first thing we need to simulate is the motion of the particles.  To do this we simply iterate through all of the particles and call the Move function, passing in the specified timeStep.  This will update the position of each particle based on its own individual velocity.

C#6_12The next part is slighty more complicated.  We want to adjust the velocity of each particle to attract it towards all other particles.  To do this we need to call the Attract function once for each possible pairing of particles.  To ensure that each pairing only gets processed once we use a pair of nested loops.  The outer loop extracts each particle in the particles list apart from the very last one one-by-one and uses that as particleA.  The inner loop extracts each particle in the list after the position of particleA and uses that as particleB.  By doing this we ensure that each particle pairing is only used once – we do not need to compare particleA to anything before it in the list because those pairings will have already been covered.

C#6_13That’s it – our simulation is now ready to run.  However, we won’t yet be able to see it running, so the final bit of code we need to write outputs the current position of each particle and also uses the trail stored on the particle to create an interpolated curve which describes it’s past path.  We then output these to the A and B outputs of our component.

C#6_14

Ta da!  Our code is complete!  Now close the component and you should see that… nothing has happened.  This is because, in order for our simulation to work it needs to be run over and over and over again.  However, grasshopper will only run the code by default when one of the inputs changes.

To get the component to constantly recalculate, we need to use a Timer component (Params/Util).  Add one of these to the canvas.  Right-click on it and set the interval to 20ms.  Then drag the output from the right hand side of the timer and connect it to the C# script component (the Timer works differently to most other components – you do not have to connect it to a specific input, it works on the component itself).

C#6_15The timer component will now cause our C# component to automatically re-fire every 20 milliseconds.  Toggle reset to true, then to false and you should see the simulation play out before your eyes, with the particles tracing curling paths around one another through space.

C#6_16C#6_17C#6_18

Some notes:

  • You can use this same basic approach to simulate pretty much any physical process you like, simply by modifying the interaction between the particles.  If you wanted to model a bunch of objects all bouncing off of one another, you could replace the Attract() function with code to detect collisions between particles and calculate their resultant velocities based on conservation of momentum.  If you wanted to study boid-like flocking behaviour, replace it instead with code that steers each particle with respect to those around it.  The possibilities are endless!
  • You could simulate the same behaviour without the timer and the mechanisms used to persist data simply by looping inside the component instead.  This will be faster (because Rhino will not be constantly re-drawing the output) but has the disadvantages that you will not be able to see or interact with the process while it is running.  It is therefore what we structural engineers call ‘less fun’.
  • Experiment with tweaking the input parameters.  You will probably see that adjusting the timeStep, as well as speeding up or slowing down the motion of the particles, also has an effect on the final result you get, even with the same set of starting locations.  This is due to a simplification in the way we are modelling the motion of the particles.  We are treating each particle as being accelerated in little instantaneous ‘jumps’, moving in straight lines in between.  In reality, the gravitational attraction is being applied constantly, leading to a slight inaccuracy in the positions of the particles at each step.  Because the subsequent acceleration is dependant on the distance between particles, this leads to further little inaccuracies which over time add up to quite major errors.  To calculate the motion more accuractely is a slightly more complicated process, although as designers rather than astronomers we may decide we can live with the simpler version.
  • I have used a similar orbital simulation when working on the design of the ArcelorMittal Orbit, with the path of a single particle moving around fixed attractor points being used to determine the central ‘spine’ around which the diagrid geometry was generated.  We discovered that the simple form of this was a little too sensitive to initial conditions (a minor tweak to one of the control points would completely change the entire path) and so the model was refined to allow the particle to ‘steer’ itself towards guidance points which allowed us to better adjust the geometry to meet artistic and structural drivers.

FinalOrbitCLFinalOrbitCLStructurezeidega_ArcelorMittal-Orbit-by-Anish-Kapoor-and-Cecil-Balmond_d

 

The example file for this session can be downloaded here:

ParticleSystemExample.zip

 

Jun 242014
 

Everything that we have covered so far could have been achieved, with perhaps a little more hard work and head-scratching, using grasshopper without scripting. However there are certain kinds of algorithm that cannot be achieved within native grasshopper without the use of scripting or specialist plug-ins.

Perhaps the most prominent category of these algorithms are those which rely on recursion in order to generate forms with self-similarity such as fractals, L-systems and so on.

In computer science, ‘recursion’ is a term used to refer to functions whose definition includes a call to itself. For example:

C#5_1

(Whatever you do, don’t try to actually run this snippet – this is an example of infinite recursion and it will keep going ‘forever’ – until your computer runs out of memory and crashes!)

When a recursive function is called, it will perform a set of actions which includes calling itself – which will then perform a set of actions which includes calling itself – which will then perform a set of actions which includes calling itself and so on.

This probably seems like a very strange thing to want to do, but it is actually very useful for a large number of applications. For example, when the computer is parsing your code in the first place, it will recursively break each line down into smaller and smaller chunks until it reaches individual commands that it can then understand and execute.

Geometrically it is ideally suited to generative fractal patterns, where the overall pattern contains many smaller copies of itself. In this example we are going to use it to create a simple fractal branching pattern where a line sprouts two more lines from one end, each of which will then sprout two more lines, each of which will then sprout two more lines and so on.

C#5_2

To begin, create a new C# component as well as a line parameter component and three sliders. On the C# component, set up four inputs as follows: firstly an input called ‘ln’ with it’s type hint set to ‘Line’, which will be used to put in our starting line. Connect the line to this. Next, an input called ‘ang’, which will control the angle of our branches and an input called ‘fact’, which will control the length of our branches – both of these should be of type ‘double’ and should be controlled by two of the sliders. Finally, an input called ‘it’ which will control the number of times the fractal structure will branch. This should be an integer type – set the last slider up accordingly and connect it to the input.

C#5_3

Looking at the script, our RunScript function should now look something like this:

C#5_4

However to begin with we’re not going to touch RunScript. In order to use recursion we’re going to need to define our own function that we can later on call within itself. We’re also going to need somewhere to store our outputs that we can populate from that other function. So, in the white space below RunScript, write:

C#5_5

Here we are declaring two things: a list of lines called outList and a new subroutine called ‘Branch’. Because outList is not declared inside a function its scope is not limited to any one function – we can access it from anywhere inside this component.

The Branch subroutine has pretty much the same inputs as our component itself – a Line ln, two doubles called ang and fact and an integer called it.

Back in RunScript, let’s initialise our outList and set it up to be output to A and hook up our Branch subroutine to the component’s inputs:

C#5_6

Now, when our component starts, Branch() will be called. However, it won’t do anything yet – let’s change that.

Let’s begin by making Branch generate the new lines that branch out of the original. In your Branch function, write the following:

C#5_7

This is a multi-step process, but is really very simple. In order to determine the direction of our branches, we need to find the direction of our starting line. We do this by extracting the front and end points of our line – accessed through the ‘From’ and ‘To’ properties. We then subtract the start from the end point to get the vector that describes the direction and length of the line. Points and Vectors have overloaded operators, meaning that you can use certain mathematical symbols (+,-,* etc.) with them as if they were numbers, in this case to perform vector mathematics.

C#5_8

From this vector we can now calculate the vectors that will describe the path of our branching lines. We do this by first making a copy of vAB, then rotating it by our input angle ‘ang’ and then finally by scaling it by our scale factor ‘fact’. To rotate the vector we use the built-in Rotate() function. This takes in two parameters: the first of which is the angle and the second is the axis about which the rotation will take place. In this case we are only working on the XY plane so we can just rotate about the Z axis – if you wanted to create a 3d branching structure you could do so by replacing this with something else. To represent the Z axis, we create a new vector with components (0,0,1) – i.e. a unit vector pointing directly up along the Z axis.

C#5_9

Now that we have the vectors that provide the direction and size of our branching lines, all we need to do is find the end point of those branches by adding the vector to the end point of our initial line. We can then create a new line between the end point of the old line and the new end-point and we have got our branch. Now all we need to do is add it to our outList so that it will be output from the component.

C#5_10

If you close the script, you should see that from our initial line we have created a ‘Y’ shape. However it only branches once no matter what value we put into ‘it’ because we have not yet implemented the recursion.

C#5_11

Fortunately, recursion is much easier to implement than it is to understand. All we need to do is to add a call to our branch function at the end of the function itself, passing in our new branches instead of the starting line:

C#5_12

So, now each branch will generate two more branches, each of which will generate two more branches, each of which will generate two more branches… and so on. The problem that we have now is that this will continue infinitely – if you let this script run then it will keep going until you run out of memory and then it will crash your computer. To prevent this from happening we need to stop the recursion after a certain number of branches. Note that when we call Branch() in the sample above we are also passing in ‘it – 1’ rather than ‘it’ – so each time we branch ‘it’ in the new function will be one smaller than ‘it’ was in the parent function. We now just need to stop the function from executing once ‘it’ reaches zero by wrapping the whole thing in an if statement.

C#5_13

Now by adjusting the slider which controls it we can control the number of levels of recursion.

C#5_14

We can control the form of the resulting fractal by adjusting the scale factor and the branching angle to generate a range of different patterns.

C#5_15 C#5_16 C#5_17

Note that this is only one example of what is possible with recursion.  You could generate any fractal pattern you like using the same basic structure but changing the geometric operations being performed.  Recursion is also a useful tool whenever trying to program any system that needs to branch (whether geometrically or conceptually) – for example parsing text or mathematics, finding connecting paths through a network and so on.

The example file for this session can be downloaded here:

AADRL C# Example 5 – Fractal Branching

Jun 052014
 

In this session, we will be examining how to build up a custom surface from scratch in C#.  We will first generate a grid of points with randomised z-coordinates.  We will then create curves that pass through columns of those points and eventually loft between these curves to create a surface.

To begin with, create a new C# component and set up three inputs.  These will be called ‘x’, ‘y’ and ‘s’ and should all have their type hint set to ‘int’.  The x and y inputs will be used to control the number of points in the grid in the x and y directions.  The s input will provide a seed value for our random number generator – more on that in a minute.  Plug sliders set to suitable ranges into these inputs.  In the example below, I’ve used the same slider for both x and y so that I will get a square grid.

C#4_1

Also add an additional output, B, to the component.

The code for this example is shown below:

C#4_2

Let’s go through line by line and see what each bit does.

The first thing that we do is declare and initialise an instance of System.Random. This is a class built into the .NET framework that acts as a random number generator.  We will use it later in order to randomise the z coordinates of our points.

C#4_3

As a constructor argument we give it our s input.  To explain what this does it is necessary to explain a little bit how random number generators work.  In a literal sense; they actually don’t work in that the numbers that they output are not genuinely random.  It is not possible (without special hardware, at least) for a computer to actually generate numbers which are truly random.  Instead, an algorithm is used which outputs a sequence of numbers which appear to be random.  To set it off, the generator needs a seed value which acts as an initial input to the generation algorithm and determines the sequence of numbers which will be produced.  If you put the same seed value in twice, you will get the same sequence of numbers out the other end each time.

Generally you want the sequence of numbers to be different each time you run the generator, so for most applications a seed value is used which is unlikely to be repeated (for example; the current system date and time).  However, for parametric design purposes we usually want consistent outputs and so we specify a particular value that we can control as a seed.

Next, we’ll create a new list to hold the curves that we’re going to create:

C#4_4

Not much to say about that, so we’ll move on to the next step – generating a grid of points.  To do this we use two for loops, one inside the other:

C#4_5The outer loop goes through each possible x-coordinate (represented by the variable i) up to our x input variable.  For each individual value of i the inner loop will run, which goes through each possible y-coordinate (represented by the variable j) up to our y input variable.  This will give us a complete set of x and y coordinates describing an x-by-y-size grid with a spacing of 1 unit between each row and column.

We are later going to create a curve that goes through all the points in a column, so within the outer loop we create a list of points called colPoints in which to temporarily store all of the points in that column.  Within the inner loop we add a new Point3d to the end of that list, using i as the x-coordinate and j as the z-coordinate.  For the z-coordinate we use the random number generator rng we created earlier.  There are multiple ways of getting a new random number from System.Random – the NextDouble() function we use here will output the next number in the generated sequence expressed as a double between 0 and 1.

We next use Curve.CreateInterpolatedCurve to create a new curve through the current column of points and we store that new curve in our curves list.  We give it a degree of 3 because we want the curve to be smooth – check out the very first Rhino session notes for a refresher on how curve degrees work.

C#4_6The last } here closes the outer loop.  Note that because we declared our colPoints list inside this loop once the current loop is over it will go out of scope and will be deleted, along with all the points it contains.  That’s OK – we don’t need it anymore.  Our curve that we’ve created was also declared inside the loop and we can no longer access it using that variable name, but because we placed a reference to it in the curves list (which was declared outside) the object itself will not be deleted and we will still be able to use it.

The next (and penultimate) step is to loft through all of the curves in order to create our surface using Brep.CreateFromLoft.

C#4_7Note that the output type from CreateFromLoft is a Brep[].  ‘Brep’ is short for Boundary Representation and is a general class that can represent surfaces, polysurfaces, solids etc.  The [] after the type name indicates that this is an array of Breps.  This is because, even though in this case the loft operation will only create a single surface, it is possible, depending on the input curves, for this function to create multiple polysurfaces.

The first input parameter is our list of curves, which will be lofted to create the surface.  For the next two we enter Point3d.Unset – these arguments allow us to specify points at which to begin and end our loft surface.  We don’t want to do that, but we can’t leave these inputs blank so we instead use Point3d.Unset to let the function know that we only want to use the curves.  The next input is the LoftType enum, which offers us the same options for creating different types of loft that we would get if we were manually using the Rhino ‘Loft’ command.  The final input is a boolean that determines whether the lofted surface should be closed – i.e. whether the end of the surface should loop back round to the start and join up.  We don’t want that, so this is false.

Finally, we output our generated curves and brep to the A and B outputs respectively:

C#4_8That’s it!  Close the code and we should have a freshly generated randomised surface:

C#4_9

Try adjusting the seed value and see how each value produces a very different result, but that we can return to an earlier option by setting the same seed again.

If your surface looks a bit crappy in the grasshopper preview, try adjusting the Preview Mesh Quality option.  Higher quality settings will look much better and display more detail, but will take longer to generate a rendering mesh from the surface (graphics cards cannot draw NURBS surfaces directly – they must be meshed before they can be rendered).

C#4_10

The definition file for this example can be downloaded here:

AADRL 2014 C# Example 4

 

May 142014
 

Example 3B: Dividing and Constructing Curves

In the previous example we used a standard Divide Curve component to obtain evenly spaced points along our input curves.  However, for the sake of completeness and also to demonstrate the way that curves can be manipulated in code, let us now modify our script so that this part of the definition is also done by our script.

So, from the end point of the last example, delete the Divide Curve components and plug the input curves directly into our script component’s x and y parameters.  You will need to edit x and y so that they use Item Access rather than List Access (since we are now only putting in one thing to each input) and change their type hints from Point3d to Curve.  Also add a new input called ‘n’.  Set its type hint to integer – this is going to be our input to control the number of divisions along the curve.  Add a slider with its rounding set to integer to provide an input for this parameter.

C#3_1

Now we need to include the code to subdivide the line.  Since we are going to want to do exactly the same thing to both of our curves but we don’t particularly want to have to write out the same bit of code twice, we will create a new function to do this that we can reuse.

Below the RunScript subroutine that we have been writing in so far there is a blank section where you can add your own subroutines to the component.  Within this section, write the following:

C#3_2

This is a function called ‘SubdivideCurve’ which takes in a curve to subdivide (called ‘x’) and an integer number to subdivide the curve by (called ‘divisionNo’) and returns a list of Point3ds.  This is all determined by the top line which declares the inputs and outputs of the function.  (Some functions (such as ‘RunScript’) have their return type defined as void, which means that they are subroutines which don’t return anything.)

The code that will be run when this function is called is contained within the curly brackets below.

The first step is to declare an array of doubles called ‘tX’.  In C# an array is declared by a pair of square brackets after the type name.  If you wish the array to have a specific size you can include a number inside these brackets to create an array of the specified size.  Generally speaking it’s better to use lists rather than arrays for most things, since they can be resized dynamically and have a larger range of helper methods, however sometimes you have to use arrays because that’s what certain functions give you.  One such function is the one we are using here – the DivideByCount function of curves.

C#3_3

This function takes in the number of divisions and a Boolean which tells it whether or not to include the ends of the curve in the output (in this case we want it to, so the value we put in here is true).  What we get out of this function is an array of numbers (i.e. doubles)  which denote the positions of the division points along the curve.  However, it does not actually give us the points themselves.

The next step is to extract those points from the curve based on the parameters DivideByCount has just given us.  To do this we need to loop through the array of parameters and convert them into the actual points using the PointAt() function of curves.  We then add that point to a list for output.

C#3_4

You use the same approach to extract other information from curves.  For example rather than PointAt() we could use TangentAt() to get the tangent vector of the curve at the specified parameter, FrameAt() or PerpendicularFrameAt() to get a frame plane at that point and so on.

Finally, we use the return keyword to specify what we want our function to produce.  In this case we output our list of points that we have just populated.  After this line the function will end.

C#3_5

Now to use our new function in the RunScript function (otherwise, it will never be run!).  To do this we need to change the first two lines of the function to

C#3_6

This will call our new function, pass in our curves x and y and use n as the number of subdivisions.  The results of that function will then be stored in ptsX and ptsY.  The rest of the script can then run exactly as before – the only difference is that we are creating the subdivision points ourselves.

The complete script should now look like this:

C#3_7

As a final step let us add in an additional output to create a polyline along each side of our zig-zag to replace our original input curves.  Adding a new output is done in much the same way as adding a new input – zoom in until the ‘+’ and ‘-‘ icons appear and the click the bottom ‘+’ to add a new output.  Unlike the inputs you do not need to specify the type of your outputs – their type is always object, which will take whatever you want to assign to it.

Now, add the following to the bottom of RunScript():

C#3_8

The class Curve, as well as being the type used for defining curve objects, also has a set of static functions which make it easy to set up curves in various ways.  To view these, type “Curve.” – the intellisense window should show a list of available options.  The CreateInterpolatedCurve function works in the same way as the Interpolate grasshopper component – it will take in a set of points and a degree and create a curve with that degree that passes through all of those points.

In this case we use that function to create a curve using our ptsX and ptsY lists with a degree of 1 (meaning that the sections of curves between those points will be straight – for a more conventional curvy line we would use a degree of 3 instead).  Those curves, called polyX and polyY are then output to our new ‘B’ output parameter by first placing them into a list called ‘outputChords’.

C#3_9

The complete script should now look like this:

C#3_10

Mar 262014
 

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.

C#2_1

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: