TileMill’s ability to map 3D complex structures continues to improve. This is a quick post sharing new details since Dave previously wrote about using Mapnik’s Building Symbolizer, demonstrating how to render building polygons with a height attribute from within TileMill
The District of Columbia, as part of its open government data program, publishes a building polygons dataset and a 3D Buildings dataset. The main differences between the two datasets are the level of detail and the geometry type. I’m going to be working with the 3D Buildings layer, which contains highly detailed structures and uses ESRI’s Multipatch Geometry Type.
Because the Multipatch geometry type is not as broadly supported in GDAL as are 2 dimensional geometries, we need to include an additional flag -nlt "MULTIPOLYGON25D" in our script to convert the Shapefile to a PostGIS layer using the command line utility ogr2ogr.
By including the -nlt option, we ensure that the new PostGIS table’s geometry column contains latitude, longitude, and altitude for each multipolygon. This allows us to use PostGIS’ 3D Spatial Functions.
As Dave explained in an earlier TileMill 3D blog post, we use CartoCSS to control how TileMill renders the buildings. First, we need to pull out the altitude value from each geometry, and add it to a new column in our table for TileMill. It’s easy to add a height column to the table using the PostGIS ST_ZMax() function. I found the buildings rendered most accurately when I divided the altitude by 2. Here’s the script to create a table ready for loading in TileMill.
DROP TABLE tilemill_buildings;
CREATE TABLE tilemill_buildings
CAST(size_sqm AS INT) as size_sqm,
CAST(ROUND(CAST(ST_ZMax(wkb_geometry)/2 AS NUMERIC),0) AS INT) AS z_xlarge,
CAST(ROUND(CAST(ST_ZMax(wkb_geometry)/2.5 AS NUMERIC),0) AS INT) AS z_large,
CAST(ROUND(CAST(ST_ZMax(wkb_geometry)/3 AS NUMERIC),0) AS INT) AS z_med,
CAST(ROUND(CAST(ST_ZMax(wkb_geometry)/4 AS NUMERIC),0) AS INT) AS z_small,
wkb_geometry AS wkb_geometry
The last ORDER BY part is important, controlling the order in which TileMill renders each building/element. From here, it’s a matter of loading the layer in TileMill, and styling with CartoCSS.
TileMill Building Symbolizer](https://farm9.staticflickr.com/8509/8486512820_78b8f449da_o.png)](http://tiles.mapbox.com/herwig/map/map-onzoztaf#17.00/38.91619/-77.04398)