·

Using Curve Attractors and Graph Mapper to Modify Terrain

In this example, we will follow up on the logic of modifying terrain with point attractors and now modify the terrain along one or more linear pieces of curve geometry. We will be using much of the same logic, so if you are struggling with certain aspects it may be useful to attempt the previous example first!

In contrast to point attractors, curve attractors will allow you to modify landform properties in two dimensions instead of just one. In this particular example we will be creating valleys or swales along our curves which gradually descend along the curve, before abruptly returning to the original surface height at the end. We could also have landforms which gradually increase in height along the curve, before sharply going down in the end, which will be one of the variations we experiment with in the end.

Step 1: Define Initial Surface and Attractor Curves

We start in much the same way as in the point attractor terrain tutorial by defining a plane in Rhino, bringing this into Grasshopper with a Surface parameter, and then using the Divide Surface component to define control points. My initial surface is a 100 x 100 unit plane which you can use as well if it helps you follow along.

Instead of drawing points in Rhino, this time I have drawn two gentle curves using the control point curve in Rhino. These are then referenced into Grasshopper with a Curve parameter. Note that the control points have a flattened data structure, while the referenced curves are grafted so that the operations in steps 2 and 3 will be applicable to both curves.

Step 2: Measure Distances to Curve and Remap Values with Graph Mapper

Next, I measure the distances between the control points and each of the curves I’ve drawn using the Curve Closest Point component. The surface control points go into the P (Points) input on this and the referenced curves of course go into C (Curves). I have three outputs on this component. We will concern ourselves in this step only with the D (Distance) outputs. Using the same logic as in the previous example, I Subtract the distances from a variable parameter which will serve as the maximum distance of my modification effects from each source curve. I put a floor on the results using a Maximum component with the inverted distance results fed into input A and the value of ‘0’ fed into input B, which will return the value of ‘0’ for all negative values.

The results of this operation are then remapped using the Remap Domain component together with the Bounds component to give values between 0 and 1 which we can use in the graph mapper. As in the previous example, the results of our maximum operation go into input V, the measured bounds of this go into input S, with the range of ‘0 to 1’ going into T.

The Graph Mapper itself uses a Bezier curve as in the previous example, which will serve as the horizontal section profile along our curve, although this will increase as we move along the curve after completing the next two steps.

Step 3: Reparameterize Curve Points and Remap Values with Graph Mapper

In contrast to the previous example with point attractors, curve attractors allow you to modify the landform’s section profile in two dimensions instead of just one. In this particular example, we want our final landforms to gradually go down along the curve to create drainage swales, before returning to the original height at the very end.

To do this, we will be using the ‘t’ output of our Curve CP component. The ‘t’ parameter gives the linear distance along the curve for each one of the ‘closest points’ identified by the Curve CP component. Note in this example, the largest value of this is around 73, although your results may vary. We want to remap these values to between 0 and 1. We could use the Remap Domain component together with Bounds, but another way to do this is to use the Reparameterize component which automatically remaps a set of values to a domain between 0 and 1. Note we could have also used this on the previous step! A third way to have done this would be to right click our initial referenced source curves, and to have selected the reparameterize option. So often there are more than one ways to do things!

These values are now fed into a graph mapper using the Bezier curve option again. By dragging the control points around in just the right way (Point 1 bottom-left, Points 2 and 3 top-right, point 4 bottom-right), we get a gradually increasing profile up to around the 90% mark, which abruptly plummets to 0 at the end.

Step 4: Scale and Sum Values to Vertically Displace Points

We now have outputs from our two different graphs between 0 and 1. The results of both operations are then brought together using a Multiply component. I then Multiply these results again by a second Multiply component together with a variable parameter which I am calling the ‘elevation change factor.’ Note, if you want to give more or less effect to the results of one of the two graphs, you could multiply these results independently of each other first, but we’ve already established a parameter to govern the horizontal distance effect in Step 2 and to keep things simpler, I’ve opted to have only a single factor for now.

As in the previous example, I now use the Flip Matrix component to reorganize my data structure into sub-lists associated with each of the input curves. The sub-lists will have as many values as the number of input curves. I then use Mass Addition to sum all the values in each sub-list, and then flatten the results of this to make a list of values compatible with my surface division list of points.

Once I have done this, I can now use a Move component to vertically displace my set of points fed into the G (Geometry) input. Since I want my points to go down, I use the Negative component followed by a Vector Z component as the T input on Move. Note that I could use positive values instead if I want landforms going up instead of down.

Step 5: Create a New Surface with Patch and Extract Contour Lines

Now it is time to create my final surface. I could create this in much the same way as in the previous example using the Surface Grid component with the U value set at U+1, but this time I am going to use a Patch surface instead. Patch surface can accept both points and curves. For the first input C (Curve), I am going to use the edge curve of my original surface, extracted from the original surface using the Edges component followed by a Join. For the P input I use my displaced points. Finally, there are two variables on Patch which will effect the properties of my final surface. These are S (stiffness) and F (flexibility). You will need to play around with these values a bit to get your desired output.

Finally, I use the Contour component for surfaces (the one with an S input at the top) to extract contour lines. here I have chosen to cut these along the X axis instead of the default Z-axis just to show a different option. This in effect will slice our surface into a series of section curves like a deli slicer! Some of my favorite physical models have used this technique together with a laser cutter, but that’s beyond the scope of the current tutorial.

Variations

Once it is up and running, you can now play around with variations for a bit. In the first variation, I’ve used the same input curves, but with a smaller factor for maximum elevation change in the vertical direction (Step 4) but with a larger factor in the horizontal direction (Step 2). In the second variation, I have two curves which are much longer, but with a high elevation factor in the vertical direction, and a small factor in the horizontal dimension. the final variation uses a large number of short arcs, but here I’ve chosen to use positive distances instead of negative distances to move my points up instead of down. Play around with it yourself to see what you get!