# Roof with Holes

## Introduction

Possible result of this tutorial
LEVEL: BEGINNER
Expected Time: 30 min

In this tutorial you will learn how to create holes in a roof. We assume that you have already created a roof in Rhino. This can be a rectangular shape, or a more organic form. However, it is important that you are using a surface and not a solid. Before we start, let’s think about the design aspects that are important.

• The holes must be randomly distributed over the roof
• The size of the holes may be varying
• The Grasshopper script must run smoothly, it may not take more than 1 second to calculate

Before we start building however, let’s take a look at the intersection modules of Grasshopper.

### Intersection Modules

The intersection options of Grasshopper

The Grasshopper Intersect tab has four categories: mathematical, physical, region and shape. The mathematical modules mainly focus on intersections between curves and planes or surfaces. Physical intersections are mostly 2-Dimensional. Regions include the trim and split tools of Grasshopper. Shape intersections focus on 3-Dimensional geometry, like solids and 3D meshes.

So why is this important? When you will start working with intersections of geometry, it will be hard finding the right method. Sometimes a script may work, but it is very slow and hard to work with. Therefore we advise you to practice with the different tools, watch tutorials and before solving, think about the best method!

Generally speaking, the lower amount of dimensions geometry has, the easier the calculation. For example: a curve and a curve is a faster calculation than a solid with a solid. This is the reason why it was asked to use a surface, and not a solid as roof to work with.

## Creating the Script

Set your Rhino roof to a surface parameter

First, create your roof in Rhino or Grasshopper. This should be a surface. In the picture on the left, you see an example how it can look like. Of course you can also just make a rectangular surface. After that, connect it to a surface parameter in Grasshopper.

• Create a roof in Rhino
• Set the roof to a surface parameter RMB on Surface Parameter » Set one Surface » Click on roof

Projection of the roof on ground plane

Now we want to project the surface on the ground plane. This will be the blueprint where we make the holes for our script.

• Project the surface on the ground Transform » Affine » Project

There are several project functions in Grasshopper. Make sure you use the right one as visible in the image! The project function also asks for a Plane. If we hold our mouse on the Plane input, you see it already has set a World XY Plane, so this is fine.

Populate ground plane with points

Now populate the projection with points using the Populate Geometry module. Please take a look at Random Points on Surface if you are not familiar with this function. Connect a Number Slider to the Count and Seed and check your Rhino viewport.

• Connect a Populate Geometry function to the projection Vector » Grid » Populate Geometry
• Add two number sliders to the Count and Seed Params » Input » Number Slider

As you can see, some of the points are very close to the boundary of the blueprint. This is a problem. When you will create a circle around these points, the holes will cut the boundaries of your roof. This problem will be solved in a later stage. Let’s go back to where we were.

Create circles around the random points

The next step is to create the circles around the points we just made.

• Add a Circle CNR to every point Curve » Primitive » Circle CNR

Generate random numbers for the radius

Now we want to generate the radius of the circles randomly. Add a random node to the radius and connect a construct domain to it as we have done in several earlier tutorials. The Number input of the random node is equal to the count of the Populate Geometry function.

• Connect a random node to the Radius of the circles Sets » Sequence » Random
• Add a construct domain to the range with Number Sliders as input Params » Input » Number Slider
• Connect the Numbers Slider of the Populate Geometry Count to the Number input of the Random node
• If you want, you can add a seed input Params » Input » Number Slider

Deconstruct the projected surface

The next step is to fix the problem that some circles are cutting the edges of the blueprint. There are multiple methods to solve this problem. First, you could remove al the circles that intersect. However, that would mean that the amount of openings is not equal anymore to your preferred input. Second, you can change the boundary. In our case, we will choose for the second option.

Add a deconstruct Brep to the projection. This will divide the original surface in Faces, Edges and Vertices.

• Connect a Deconstruct Brep to the Geometry output of the projection Surface » Analysis » Deconstruct Brep

Join the edges of the projection to one curve

When you connect a panel to the Edges output, you see that the output gives 4 different edges. Of course, if we want to offset them, they need to be joined. So add a join curves node.

• Connect a panel to the Edges output of the Deconstruct Brep Params » Input » Panel
• Connect a join curves to the Edges output of the Deconstruct Brep Curve » Util » Join Curves

Give the joined curves an offset

After joining the curves, the overall edge should get an offset inwards. For this, Offset Curve can be used. Note that the Plane Input already has an XY Plane, so that is fine. You can leave the Corners input as it is.

• Add an Offset Curve to the joined edges Curve » Util » Offset Curve

Connect the Domain End for the random range to the Offset Curve Distance

The question is, how far should the curve be offsetted? Considering that the radius of the circles is based on a domain. We can use the maximum possible value (Domain End) as Distance.

• Connect the Number Slider of the Domain End to the Distance input of the Offset Curve

Create a surface from the Offset Curve

Now the curve should be changed to a surface. This can be done by adding the Boundary Surfaces component

• Connect a Boundary Surface component to the curve output Surface » Freeform » Boundary Surfaces

Replace the Populate Geometry input
Reorded version of the script. Keep it readable!

Now we should replace the Populate Geometry Geometry input with the new surface just created.

• Replace the Populate Geometry Geometry input with the created surface, as can be seen in the left picture
• Reorder you Grasshopper script
• Rename your Number Sliders

Let's check our Rhino viewport. We now have a blueprint with curves. The last step is to project these curves on the roof and make an intersection.

Project the circles back to the roof. Use the correct Project Node!

Project the created blueprint curves on the roof. Use the original surface as input for the Brep. Make sure you use the correct version of the project nodes! As you see, the direction of the project function we use is Z (up), so it can be left empty.

• Project the holes on the roof Curve » Util » Project
• Connect the original surface to the Brep input of the Project node

Flatten the list of curves

Connect a panel to the Curve output. As you see, we have a structure of lists in lists. This is not was we need, flatten the list. Tree editing is a complex but essential aspect of Grasshopper. In this stage in the tutorials, it is still hard to explain. Just remember that flattening will give you one single list with information.

• Flatten the Curve list Sets » Tree » Flatten

Split the roof surface with the curves

The final question is what intersection module to use. Note that we use a surface and curves. Looking at the intersection tab, a Surface Split can be found. Set off the preview of all functions we used before to see the result.

• Add a Surface Split Intersect » Physical » Surface Split
• Set off the preview of previously used nodes

Result of previous steps. All splitted surfaces are visible.

As you see in the Rhino viewport, not only the intersected roof is visible, but also the smaller hole parts. You can fix this by adding a List Item node. Standard, the List Item node takes the first item of the list (index 0). Luckily, the overall surface is already the first item. If not for some reason, just add a Number Slider to the Index of the list item and find the right surface.

• Connect a list item to the Fragments output of the Surface Split Set » List » List Item

Retrieve the roof surface with a list item

By adding an Extrude to you script, you can give your roof thickness.

• Add thickness to your roof with Surface » Freeform » Extrude
• Add a Unit Z to the direction of the extrusion Vector » Vector » Unit Z
• Connect a Number Slider to the Unit Z vector Params » Input » Number Slider

Extrude the surface to give your roof thickness

Your script is now completed! For good practice, add a Geometry Parameter at the end. Don't forget to turn off the preview of nodes that are not important.

• Finish the script by adding Params » Parameter » Geometry at the end of the network.

Final script

## Calculation Speed of Grasshopper

Profiler showing the speed of your script

During your learning process of Grasshopper, you will find out that calculation time is important. As stated in the beginning of this tutorial, it is important to use the right modules, because some of them take more time to calculate than others. If you want to see which functions in your script are the bottleneck, turn on the profiler to see the problem. Display » Canvas Widgets » Profiler