Growing Lines – Example 10.3
Another way to approach growing structures using Grasshopper and the looping Anenome add-on is to incrementally change geometry until a certain condition is met. In this example, I will take a series of lines initially oriented in random or semi-random directions, and then extend them a small increment in each “round”, until they hit another line, at which point they will stop extending. The lines are sort of racing each other. The line that gets to the “intersection” of two lines first, wins, and gets to keep growing. The looser has to stop growing and wait patiently for the other lines to finish growing. This logic will come in handy when we look at a growing, branching structure in the next example.
Setup and the Initial Loop
To start, I am going to draw a randomized field using the exact same logic as example 6.4 except I need to make sure the length of the initial lines is short enough so that no lines are intersecting before the looping starts. In this first case I have an 8×8 grid, and I draw a line along a randomized vector from each one, and a second line in the opposite direction. So each point is associated with two lines.
In the first loop, what I want to do is find the endpoint of each line, using the “Endpoints” component. This is the growth point…you can think of it as the bud on a tree if that helps. If the endpoint (bud) is free and clear, the line will grow a bit, and will live another day. If it is too close to an obstacle though (either another line, or the edge boundary) the bud will die, and the line will stop growing in future rounds.
The way I did this in grasshopper is by using the “Curve Closest Point” component. Pay attention to both the grafts and the flattening here. Each endpoint (these are grafted) are tested against the entire collection of lines, both “live” and “dead” (which are flattened). I had to use a “Sort List” component on the distances coming out of “CrvCP” and test Item “1” to find the closest curve, since item “0” is 0.0 which is the distance of the endpoint to its own curve, which is not a helpful statistic. Item 1 on a sorted list will always be the closest point that is not itself 🙂
I then test this value with a boolean “Larger Than” test to see if it is larger than a proportional factor. In this case, i am growing the lines 5% of their initial lengths each round, so the test needs to be that same distance. If the distance is smaller than this 5% value, the growing line gets dispatched into a “dead” pile which will be looped separately. We need to keep the dead lines together and loop them as well since we need to test against them every round to see if any live points get too close to them.
In the picture above, I have shown the results of this looping process at some fixed intervals. This is when the script is run at a 5% growth rate, which is rather fast. I would recommend working at a faster growth rate at first so you don’t get bogged down, but once you get a pattern you like, to reduce the growth rate to get a more precise drawing.
The “live” lines are shown in green, their endpoints (the buds) are shown with a red X, while the dead lines are black. After 10 rounds, most lines are still growing, but many have died. By round 10, casualties are very high, and only a few lucky lines are still growing, and by round 30, only four are left. By round 44, the game is over, and all geometry is in the “dead” container. This triggers the loop to stop when the “List Length” for the “Live” geometry = 0.
So that is the basic loop. The image above shows the overall loop structure. Channel “D0” on the Loop represents the live Geometry, while channel “D1” represents the dead items. Notice I also plugged the project boundary curve into D1 before the looping started to keep lines from growing outside of this boundary. Also notice how the “List Length” trigger is setup to stop the looping.
Above are some variations I did once the loop was working. In the first 3 images, I only changed the random number seed. In the second three, the initial vector is rotated, while the random variation is much less. The last three I played around with the initial grid spacing, as well as the initial angle structure.
You’ll also notice I did a bit of “post production” after the looping finishes. The lines are first joined together that originated at the same point. next, the lines are offset a small amount based on their overall length, and a loft is created between the two offsets to give the lines thickness. I then color them based on their area/overall length. Longer, more successful lines are green and fat, while the poor lines who didn’t grow much are pale and skinny. Below is the “post production” script.