Using Rhino, Grasshopper and a Delaunay Mesh to automate the tedious task of outlining rooms.
Why, What and How: Back to the Dark Ages of DWGs
In a world of BIM, why should we go back to DWGs to automate the process of outlining rooms? While we may have BIM models for new buildings, owners and facility managers of existing buildings are stuck with the original drawings done in AutoCAD. To do any analysis of room sizes, or breakdowns of departmental sizes, we have to spend a day or two outlining each room so that we can get the square footages. The process is both a tedious task, and occupies a great deal of time that could be spent more productively.
For those who like a good puzzle, it is also a chance to put your Grasshopper skills to the test.
The question remains, in a DWG full of separate lines, how do we figure out the room boundary? We know that rooms are bounded by three building elements: walls, doors and windows. We need to create a process or algorithm for identifying those elements based on the geometric relationships between the lines in the drawing. We also know that rooms are large empty spaces in between the walls, doors and windows.
With that information, we now need to find a logical sequence that will help us interpret the relationships between all of the lines in the drawing. Since lines are made up of two points, at a more foundational level, we need to interpret the relationships between all of the points in the drawing.
To analyze the relationship between all of the points, we’ll use a Delaunay mesh. We’ll use this method for a few reasons. First, the input to the algorithm is a collection of points (which we have in the drawing). Second, it generates a set of triangles between adjacent points. By looking at the areas of the triangles, we can identify empty space (rooms) and the dense collections of points that make up the walls, doors and windows.
Now lets see how it’s done
The Walk Through: Diving in to Grasshopper
For this walkthrough, we are going to use a line drawing of a single loaded hallway with hospital rooms and attached bathrooms. Our goal is to created polylines around the hallway, each hospital room, and each bathroom.
Create the Delaunay/Analysis Mesh
To start, we first need to create the Delaunay mesh, and translate the resulting triangles into a form that we can analyze.
We have a curve showing the walls of hospital patient rooms and bathrooms along a single loaded corridor. For the example, I’ve combined all of the lines in the drawing into a polyline to simplify the script (scroll down to see why). We then pass that curve into an Explode component to get all of the vertices or points along the line.
Next comes the Delaunay mesh. With all of the vertices extracted from the polyline, we can pass the points into the Delaunay Mesh component in Grasshopper. Pass the resulting mesh into a face boundary component to see all of the mesh edges.
Finally, let’s compare the triangles with the shapes we are trying to identify. We are trying to identify the walls, doors and windows that make up the boundaries of each room. Since these are all rectangular shapes and not triangular like the mesh faces from in the Delaunay mesh, we need a way to bring the mesh face shape closer to the shapes we are trying to identify. To do this, we’ll add a Quadrangulate component to the script. This will take adjacent triangles with parallel sides, and join them into one rectangular shape, which will help us in the next step of identifying and filtering out these faces.
Small note here: Since this is an example, we are starting with a polyline instead of individual lines to simplify the script. If we started with unjoined lines, we’d get both the start and end points of each line in the drawing, and we’d need some extra error correcting code to simplify the start of one line, and the end of another line into a single point. By exploding the polyline, we only get one point for each of the vertices along the line.
Filter Room Boundaries
Now we need to identify the mesh faces that make up the walls, doors and windows. To do this, we’ll combine two different approaches: an area threshold and a process to identify rectangular faces (leveraging the quadrangulation of the mesh we did earlier in the script).
Area Threshold
The philosophy behind this approach is simple. Walls, doors and windows all have small areas relative to the room size. By creating a threshold with a number slider, users can set the threshold based on the unique characteristics of the floor plan they are analyzing.
To create this filter in Grasshopper, we will first use the Area component to get the areas of the mesh faces. Next, use a number slider and the Smaller component to generate a true/false list of mesh faces that are smaller than the area we set in the slider.
Now look at the results using a panel. You’ll see that this threshold picks up corners of the rooms that are smaller than the threshold, so we need an additional filter to make sure that these elements are not removed from the room.
Quadrangle Filter
Take a look at the differences between the mesh faces that make up the room boundary elements, and the room corners that were unintentionally picked up by the area threshold. What is the difference?
In the case of the room corners, you see that the mesh faces are triangular, and in the case of room boundary elements, the mesh faces are rectangular (as a result of the quadrangulate component we used earlier in the script). To identify the boundary elements, we can test the number of sides that each mesh face has, and then create an additional filter.
In Grasshopper, we’ll start by exploding the region intersections from the analysis mesh step. Then take the resulting segments and get the number of sides by measuring the length of the list. Due to the way Grasshopper organizes the list lengths, we’ll need to flatten the resulting list. Finally, we’ll use the Equals component to find all of the polygons that are quadrangles.
Cull and Merge Polygons to Get Room Outlines
With the room boundary elements identified we need to remove the boundary elements and combine the remaining mesh faces using a union operation. Once the mesh union is performed we can use the room outlines to get areas (shown below) or created advanced operations that will further our analysis of the floor plan (see Next Steps).
In Grasshopper, use an And component to combine the true/false lists coming from our area threshold and the quadrangle filter. To cull the mesh faces that meet both conditions, we’ll have to invert the boolean value of each list item using the Bool component. Pass the results to the Cull component, along with the list of faces from the Region Intersection component. Once the boundary elements are filtered, we can pass the remaining mesh faces to the Region Union component. With the area threshold slider set correctly, we are left with distinct outlines of each room. If not, change the area slider till it picks up each of the doorways in your floorplan.
Finally, we can pass the output of the Region Union component to the Area component to get the center points of each room, and the square footages of each room. You’ll be left with the floorplan below:
Complete Grasshopper script
Next Steps…
Now that we have identified rooms, there are a world of applications we can start to explore. When we created the script, did you take note that the area component in Grasshopper gave us the center point of rooms?
With the center point, and an interconnected mesh connecting all of the rooms, we can:
- Generate walking paths between rooms
- Analyze walking paths throughout the building
- Study adjacencies, and the productivity impact of different layouts
All this coming soon…