I have recently been constructing whole cities in Rhino using the Elk plugin. This parses OpenStreetMap data into Grasshopper geometry, allowing you to visualise any city or area in the world in your Rhino viewport.
One of the most interesting ways of getting your cities to look like cities is getting the buildings right. It is possible to extract building data with Elk, but this isn’t intuitive if you aren’t already familiar with OpenStreetMap data. And even if you are, the output is a collection of points, which requires further work to turn it into actual buildings.
This article will show you how I created buildings by extracting the OSM data and converting them into 3D meshes.
OpenStreetMap: Understanding the data
A crash course into OpenStreetMap data: All (well, nearly all) objects in the map are either saved as points or as lists of points. Points are useful for small objects, such as benches, letterboxes or trees. For larger objects, such as roads and buildings, collections of points are used. For roads, these points join together to form lines along the centre of the road. For buildings, these points define the line around the building’s edge. These ‘point collections’ are essentially polylines.
Every object, whether a point or a polyline, has a list of data associated with it. Each item in this list has a key and a value. It is with these keys and values that we describe the object. The most common key is ‘name’, and we describe the name in the value field. Most objects have many tags. For example, if we go into the OpenStreetMap editor and have a look at a local branch of Costa Coffee:
We have a list of keys and a list of values. The values are the data itself; the keys describe the type of data.
If you want to see this for yourself, go into the editor on OpenStreetMap. I personally prefer the Potlatch2 editor, which you can find in the drop-down next to the ‘edit’ button at the top. To see the tags, select an object on the map, then click ‘advanced’ in the bottom left.
Buildings in OpenStreetMap
Similarly, all buildings contain a collection of tags. The great thing about tags is that they are an open concept – you can use any tags that you like. With buildings, the most common tags include the building name and the building type. For example:
Using Elk to extract buildings
Elk can be used to extract the points that form the building outline. Like polylines in Rhino, the data is saved as a collection of points, and not a line itself, so it will be up to us to stitch the points together to create a building outline.
There is no built-in component that returns directly the building points, but we can use the GenericOSM to filter for data containing the ‘building’ key. The Polyline component joins the points together.
Make your buildings 3D
This is all well and good, but don’t they look a bit flat and boring? Let’s make them look a bit more realistic.
The easiest way to turn your polylines into 3D buildings is to extrude them, and then use patch to create a roof. But I can tell you through my own experience that this is a bad idea. For a few buildings it’s okay, but for the city scale, working with surfaces is very slow and you’ll quickly see your computer grind to a halt. To build our buildings at lightning speed, we have to use meshes.
There isn’t anything natively in Grasshopper that does this for us, but we can quickly write something in C#. Basically, we build up the walls with mesh faces, then use a Rhino command to cap the top for the roof.
This script takes in a list of points that describe the building outline, and a value for its height. (Let’s just send it a value of 10m or so for now.)
private void RunScript(List<Point3d> pts, double ht, ref object A) { var building = new Mesh(); //make walls for (int p = 0; p < pts.Count; p++) { building.Vertices.Add(pts[p]); building.Vertices.Add(new Point3d(pts[p].X, pts[p].Y, pts[p].Z + ht)); } for (int p = 0; p < pts.Count - 1; p++) { int j = p * 2; building.Faces.AddFace(j, j + 1, j + 3, j + 2); } //make roof var roofpts = new List<Point3d>(); for (int p = 0; p < pts.Count; p++) { roofpts.Add(building.Vertices[p * 2 + 1]); } var pline = new Polyline(roofpts); var roof = Mesh.CreateFromClosedPolyline(pline); building.Append(roof); A = building; }
This then gives us:
But not all buildings are 10 metres tall…
It made things a lot easier to assume a height for our buildings. But can we do any better?
Given that we have a height input, we should be able to put something a bit more sensible into it. Some buildings in OSM do come with height data, though most don’t. If they do, this information is under the height key. How can we extract the building’s height information and apply it to our buildings with Elk?
It currently isn’t easy as there isn’t a comprehensive tag filter within Elk. One solution is to use the GenericOSM with k=height. This will return everything with height data; we just have to assume that everything returned is a building (it usually is) and model it as such.
Set up your Grasshopper as below, using the same C# script as above to create the buildings:
For my example of York, barely a single building has any height data. But, very happily, one very patient mapper has recorded the height of all the different elements of York Minster, leading to a very pleasing model.
But I really want heights on ALL my buildings!
Then you’ll likely have to pay up.
At least in the UK, the only near-comprehensive source of building heights is via the Ordnance Survey Topography Layer. Limited amounts of data are available as free academic licences, but otherwise it ain’t cheap.
In the meantime, if you’ve made it this far, you’ve probably realised that there are a lot of gaps in the OSM database. These gaps are best filled by people with local knowledge where you live, so I would encourage you to register and to start mapping! 🙂
I’m trying to get your c# script to work for the heights and I can’t seem to get it to give me any output. Is there possibly some changes with the assemblies called or an issue with more recent updates that make it not work? Any help would be appreciated. Thanks!
Hi Jake,
Is it possible that the buildings you are working with simply don’t have any height data? This is the simplest thing to check before going on further. The proportion of buildings with height data in OSM is unfortunately still minuscule.
If so, does Elk return any geometry when you set k=”height”?
Yes, they do have height data and in fact some even have the “k=building:part”. I’m working in Manhattan for my master’s thesis in architecture and obviously attempting to get some decently accurate site models to use. I’ve managed to do the work-around with the height input being placed into a z-vector for extrusion; however, I some wild inaccuracies for the building parts (I think it might be a data tree issue). That’s why I’d like to use your script, as I hope it will keep everything together a little better. Should I send you the file?
Hmm, height data is very good in Manhattan. I’m happy to take a look. I’ve just installed a comment attachment tool so you can try that to share the file, otherwise I guess you could share a Dropbox link?
Hi James,
Sorry, holiday weekend and all. Here is a Google Drive link to the osm files and the grasshopper definition. I took your example and built it a little different, but hopefully just simplified it for my own sake as I wasn’t completely ready to use it for the animation portions or road building. As I said, I’m hoping to keep the height data consistent with their particular buildings and the building parts. It seems your script will do a better job than the simple extrusion exercise I’m trying currently in grasshopper. Looking forward to hearing back! Thanks so much again!
https://drive.google.com/open?id=0B_HNNgERsWIwNXpSc0pCYVgxY0U
Hi Jake, I am able to get your file working without a problem!
https://www.dropbox.com/home/Public/for%20Jake
So it’s very hard for me to diagnose. The only thing I had to do was to re-add the OSM file to the Path component, and turn on the preview of your ‘cap’ component. I also had to zoom out a lot. (Middle-click on cap and select ‘zoom to preview’.)
The link above contains what I can see, as well as the GHA file I’m using for Elk (dated about a year ago).
If you’re still having problems, it might be worth taking it onto the Elk forum on the Grasshopper site.
http://www.grasshopper3d.com/group/elk
Thank you so much James for sharing this, this is fantastic. Unfortunately the data is behind, but your work is ahead and ready for it! Yay