In Rhino3D Grasshopper, Map to Surface is a powerful way to project curves on any given surface. A diagonal quad grid on a cylindrical vault will serve as an example.
The basic idea behind Map to Surface is that you take a curve (or a set of curves) and map it – together with its base surface – onto a desired target surface. In most use cases you will have curves and a target surface upfront. The base surface however – in Grasshopper called source surface – will be something you’ll have to create.
As an alternative approach, to achieve a similar result without Map to Surface I wrote an article on using surface division plus extracting points for polyline creation.
New to Grasshopper? I suggest you read this article in the first place.
Need more learning resources? Check this out.
Disclaimer
As you will see in my screenshots most components carry a title above them displaying their name. This is because I use a plugin called Bifocals. It’s a teacher thing 😉
Also you’ll see my Grasshopper tab titles abbreviated because there’s not enough horizontal space. I will mention the titles in full in my script though.
Contents
Map the Curve Grid to the Target Surface
What Map to Surface does not do
Alternate Method for Arc Definition
Alternate Grid: Remove Triangle Lines
Create the Curve Grid
Lets start with the curve. In our example, where we want to see diagonal quads as an end result, we use Grasshoppers Triangular Grid component (Vector – Grid):
Place it on your canvas. In case you see a plane preview coming with it …
… better shut it off via Display – Preview Plane Size – 0:
(The plane preview makes sense often times – but not here.)
Now produce 2 Number Sliders ranging from 5 to 100 – use integers.
Plug them into both E (xtent) inputs of your TriGrid component:
With this small sub-definition you will be able to dial the quad density on your later surface:
New to Grasshopper? I suggest you read this article in the first place.
Need more learning resources? Check this out.
Create the Source Surface
Map to Surface is our key tool in this whole process. It needs 2 surfaces:
- The source surface embedding the original curves
- The target surface of our final geometry
With our triangle curve pattern given, we produce the source surface first. Basically all we have to do is to
- Create a bounding box containing all curves
- Extract the bounding box’s base plane
Actually though, there are some more steps to solve.
With our TriGrid component we have a set of “folders” containing groups of curves:
In this example, each “folder” contains 8 curves which corresponds to our Extent Y input value. Not to be seen here: The number of “folders” (written {0;0;0}, {0;0;1} and so on) corresponds to our Extent X value.
What you see here is actually Grasshopper’s standard list structure. In Grasshopper jargon it’s called a data tree (the list) consisting of branches (the “folders” as I called them above) which contain items (in this case, the curves).
Let’s try something: Apply a Bounding Box component to C output of your TriGrid component (Surface – Primitive – Bounding Box):
As you probably know, a bounding box is the smallest possible cube containing a given geometry. In our example, the geometry is flat, so the bounding box will likely be a simple 2D-plane.
When connected to TriGrid, a Panel shows us that each single triangle has been wrapped in a bounding box of its own:
This is exactly the opposite of what we need: 1 bounding box containing all triangles.
OK – as said above a tree (consisting of branches consisting of items) is probably not suitable here.
Let’s see what happens when we group our triangles. Pick a Group component from Transform – Util:
Now put it between TriGrid and Bounding Box:
Result: All items inside a branch have been successfully grouped, but we still have all the branches – and the according number of bounding boxes.
So, here’s the trick – and some of you probably know: In order to get rid of the branch-item-hierarchy in our list we apply a Flatten algorithm to the C output of TriGrid.
We can do this either in an explicit or an implicit way. The latter works as shown:
That is, you right-click C and choose Flatten. The alternative, if you are a beginner and like things explicit, is to use a Flatten Tree component from Set – Tree:
Connect it directly to C (TriGrid), and its output to Group:
Finally, here we are. 1 Bounding Box for our all our triangles:
To remind ourselves, the bounding box is just a means to an end – the retrieval of the surface that contains our triangles.
A bounding box is also called a BREP – an abstract concept of shape representation. Again, it is a minimal cube around any given geometry.
Rhino3D Grasshopper offers an algorithm which retrieves faces, edges and vertices (points) of such a BREP. It’s called Deconstruct Brep (Surface – Analysis):
Connect it to your bounding box:
The outputs of Deconstruct Brep give us Faces, Edges and Vertices. All we want is F – remember, the base face containing our curves and thus supplying the Source Surface for Map to Surface.
And for once things turn out easy – F produces exactly 1 result. This will be our curves’ base surface:
New to Grasshopper? I suggest you read this article in the first place.
Need more learning resources? Check this out.
Create the Target Surface
Normally, when dealing with Map to Surface, you may already have a target surface and are going to map curves to it. In this scenario however, we created the curves and then it’s base surface upfront without having a target surface.
So let’s get this done and produce a half-cylindrical surface. We could do something more freestyle but I want to keep things simple for this tutorial.
To produce a cylindrical vault in X-direction: In Rhino3D, draw a semicircle in the Right viewport:
As you can see, the arc’s size is not related to the size of our triangle surface. The arc will be the basis of an extrusion in the next step – thus producing our target surface. In most cases, you’ll have an idea about your desired vault height and diameter, so this is what the circle size should relate to.
Anyway, in the end, when you apply the Map to Surface command, the triangle pattern will be scaled to fit. So its initial size is not relevant.
Now, back to our vault: Pick a Curve parameter and link it to your Rhino3D semicircle:
Pick an Extrude component from Surface – Primitive and connect it to the Curve component:
For Grasshopper to “know” in which direction to extrude you need to tell her via UnitY (Vector – Vector):
We’re not done yet: Grasshopper extrudes humbly, but only 1 unit. Produce a Number Slider ranging from 10.000 to 200. (Remember that Grasshopper’s decimal sign is point, not comma. Writing 10.000 means that your number slider will start at 10 and allow for real numbers.)
Your result:
New to Grasshopper? I suggest you read this article in the first place.
Need more learning resources? Check this out.
Map the Curve Grid to the Target Surface
Now everything is ready for Mapping. We have
- A set of curves to be mapped to a surface
- A source surface containing the set of curves
- A target surface (our vault) for the curves to be mapped to
The key component in this whole process is Map to Surface. Pick it from Transform – Morph:
Connect it:
Map to Surface has inputs C, S and T which are connected like this:
- C: TriGrid C output, either unflattened or flattened
- S: Deconstruct Brep F output
- T: Extrude E output
The result:
Seems fine – play around with your Extent sliders to see Map to Surface in action.
There is one last thing, however: When you zoom in on the result, you can see that the triangle distribution needs some care:
In this image, the first and last triangle cell in Y-direction have not the same orientation. How so? Look at the ExtentY number slider:
It shows an odd number. Dial in an even number and the problem disappears.
Luckily Rhino3D Grasshopper makes it easy to fix this kind of problem. Just double-click the slider’s name, and in the slider’s settings pick E for Even numbers:
Now whatever you dial will always be an even number.
A similar problem concerns the triangle cell distribution in Y-direction:
Here it’s just the other way round. Open the ExtentX slider’s settings and pick O (Odd numbers):
Everything should be fine.
You successfully mapped a set of curves onto a target surface.
As you see, the curve pattern can be scaled as needed and instantly fills the target surface accordingly.
Likewise, you may change the target surface’s size like its extension in Y-direction as much as you like and the curve pattern will always cover it.
New to Grasshopper? I suggest you read this article in the first place.
Need more learning resources? Check this out.
What Map to Surface does not do
Map to Surface does not change straight lines (degree-1-curves) into curves (degree-3-or-more-curves) which lie completely in the target surface.
Instead, it fits the curve surface onto the convex side of the target surface:
Keep this in mind.
Alternate Method for Arc Definition
This is not really important to our subject. It’s just that for reasons of autonomy I would rather not link a static arc from Rhino3D to extrude my target surface.
Instead, I’d like a tidy little definition that allows me to dial in a semicircle’s diameter (Arc SED) which then produces the extrusion. As a result, my target surface where the triangular grid is mapped to can itself be changed all the time ad libitum. Here’s the definition – very simple – that you may recreate or not, just as you like:
Mind you, D input of Arc SED provides the arc’s tangents in its start and end points. By default, it is set to 0,0,1 which means they are vertical – so no need to change the default here.
New to Grasshopper? I suggest you read this article in the first place.
Need more learning resources? Check this out.
Alternate Grid: Remove Triangle Lines
We created the grid with a tool called TriGrid – which is supposed to create triangles. So all the lines we see in our result are chained triangle edges.
What if we want to get rid of some of the lines, let’s say the horizontal ones?
Well first of all when we talk about removing (or rather hiding) lines we talk about the lines in our original Triangular grid. Every element of the grid will map to our target surface anyway.
The workflow I want to show you is based on the direction of the lines we want to hide. As you see, they follow the X-direction.
Basically, we will filter all lines according to their angle – the ones in X-direction will be hidden, the rest stay visible.
As said, we will do this in the base grid, so turn Preview off for everything but the grid:
Also it may be a good idea to change into Top view:
(As you see, I turned CPlane grid and axes off and the background to white. For tweaking everything related to grid display in Rhino3D, just type grid and check your options.)
Now let’s concentrate on TriGrid and its flattened curve output. In a connected panel you see the output consists of Polyline Curves. Most probably these are not single lines. And as expected, a List Item component reveals that they actually represent our triangles:
To search for lines with a given angle (X) we need to disjoint our triangles. Pick Explode from Curve – Util:
Connect it to the flattened polyline list:
Each polyline has now been split into 3 lines sorted into paths, which resemble the former polylines.
We have what we need, a bunch of single lines.
Now for this angle thing. Remember, we want to kick out all the lines in X-direction. As soon as we deal with angles in a situation like this, we actually have to think vectors.
So first of all let’s turn all lines into vectors. Pick a Vector parameter from the Param tab:
Since we want to compare each line’s direction (translate: each vector’s direction) to our X-direction, we need a component which measures angles. Pick Angle from Vector – Vector:
Connect it to your Vector parameter (which contains all your grid lines as vectors):
As you want to compare your line vectors to X, plug a Unit X component into Angle’s B input.
And just to be sure that we leave no loophole for some of our lines, plug an Absolute component between Vector and Angle:
This Absolute component changes vectors with negative direction into positive vectors – this way Angle works the same way for all our lines.
Now we need a component which sorts our lines into 2 groups:
- The lines that are running in X direction
- All the other lines
What we need is an algorithm which basically goes like this: If condition A then B, if not then C. Pick an Equality component (Math – Operators):
Plug it into Angle’s output like this:
As Equality is supposed to look for lines parallel to X, we need to look for results that equal 0. And that’s why we feed its B input with 0.
Now we get 2 lists as output: The first puts out if a line is parallel to X (True) or not (False). True and False are Boolean expressions in this case meaning basically “fulfilled” and “not fulfilled”. The other output does the reverse thing.
OK, we are getting somewhere.
Remember: All we want to do is hide some lines – the ones running in X-direction.
Our lines are representetd by our Explode component. It produces a list of lines we can work on.
Now you already know List Item quite a bit, which allows to retrieve items from a list.
What we need here, though, is a component that will hide items from a list.
And, since with the outputs of our Equality component we have True-False-lists we can make good use of Cull Pattern (Set – Sequence):
Again: We need to hide items from our line list represented by Explode, so connect Explode S to Cull Pattern L.
And: Cull Pattern expects a list of True/False for its P input to decide which items to hide. Being a hide component, it will hide everything that is False.
In the second output Equality marks an X-parallel line as False. Since we want to hide these guys we have to take this output and connect it to Cull Pattern P.
And don’t worry if you get mixed up with this True-False thing – in case you choose the other output you’ll notice that it’s wrong immediately.
Anyway, if you un-preview everything but Cull Pattern, this is the result:
Here we are, finally.
Switch on your target surface and mapping, and turn preview off for everything else.
And by all means, reconnect your Map to Surface C input to Cull Pattern’s L output:
Now what a lovely sight is this?
Again, for an alternative to achieve a similar result see this other article of mine.
New to Grasshopper? I suggest you read this article in the first place.
Need more learning resources? Check this out.
Finale: Border Edges
This one is super easy and short. You need edges defining the borders of your surface?
Well, to Grasshopper, an extrusion again can be considered a BREP (= Boundary Representation). And Deconstruct Brep extracts Faces, Vertices and Edges, remember?
As promised, that was short and easy.
Again, for an alternative approach to achieve a similar result see this other article of mine.
New to Grasshopper? I suggest you read this article in the first place.
Need more learning resources? Check this out.
Mapped Curves go 3D!
Just to have some joy with our newfound shape: Let’s turn those abstract curves into 3D geometry!
Pick a Pipe component (Surface – Freeform):
Plug border edge curves and your map curves both into Pipe’s input. Hold the SHIFT key while plugging the second input:
The result is – with Pipe – always bulky:
Produce a Number Slider with 0.01<0.1 and plug it into Pipe’s R input:
This looks much better. As a reminder, you can Bake this whole Pipe stuff:
Again, for an alternative approach to achieve a similar result see this other article of mine.
New to Grasshopper? I suggest you read this article in the first place.
Need more learning resources? Check this out.
Leave a Reply
You must be logged in to post a comment.