Buildings
Overview
The Overture buildings theme captures the compilation of many building attributes from a variety of open data sources including OpenStreetMap, Esri Community Maps, Microsoft, and Google.
Feature types
The buildings theme has two feature types:
building
is a polygon or multipolygon geometry that represents the building's footprint (or roofprint, if traced from imagery).building_part
is a polygon that describes part of a building. These come from the OSM features with the tagbuilding:part=yes
.
Theme concepts
Both building and building_part types may have many shape related properties. These are useful for expressing the physical shape characteristics of the buidling including roof_height
, roof_shape
, roof_material
, facade_material
, etc.
Properties Derived from OpenStreetMap Tags
In OpenStreetMap, an object is defined as a building by the presence of building
tag. Most commonly, the value is simply, building=yes
. However, in cases where there is a more descriptive value, we capture that information along with other building attributes such as height, roof shape, material, etc. and map them to a finite list of values defined in the building schema.
You can see the SQL query logic that transforms OSM tags into Overture properties for each of these attributes below:
How do I interpret these queries?
Each WHEN
line in the CASE
statement is a condition that defines the value of the Overture property. For example:
WHEN lower(trim(element_at(tags, 'building'))) IN ('clinic','hospital') THEN 'medical'
Here, lower(trim(element_at(tags, 'building')))
is accessing the value of the building
tag in OSM (and ensuring it is lowercase). Therefore, when either the building=clinic
or building=hospital
tag is present, the statement returns medical
. In this case, this defines the subtype for a medical building.
- Subtype
- Class
- Facade
- Roof Shape
- Roof Material
CASE
-- Prioritize the `building` tag to determine the subtype
-- Agricultural
WHEN lower(trim(element_at(tags, 'building'))) IN (
'agricultural',
'barn',
'cowshed',
'farm',
'farm_auxiliary',
'glasshouse',
'greenhouse',
'silo',
'stable',
'sty'
) THEN 'agricultural'
-- Civic
WHEN lower(trim(element_at(tags, 'building'))) IN (
'civic',
'fire_station',
'government',
'government_office',
'public'
) THEN 'civic'
-- Commercial
WHEN lower(trim(element_at(tags, 'building'))) IN (
'commercial',
'hotel',
'kiosk',
'marketplace',
'office',
'restaurant',
'retail',
'shop',
'supermarket',
'warehouse'
) THEN 'commercial'
-- Education
WHEN lower(trim(element_at(tags, 'building'))) IN (
'college',
'kindergarten',
'school',
'university'
) THEN 'education'
-- Entertainment
WHEN lower(trim(element_at(tags, 'building'))) IN (
'grandstand',
'pavilion',
'sports_centre',
'sports_hall',
'stadium'
) THEN 'entertainment'
-- Industrial
WHEN lower(trim(element_at(tags, 'building'))) IN (
'factory',
'industrial',
'manufacture'
) THEN 'industrial'
-- Medical
WHEN lower(trim(element_at(tags, 'building'))) IN (
'clinic',
'hospital'
) THEN 'medical'
-- Military
WHEN lower(trim(element_at(tags, 'building'))) IN (
'bunker',
'military'
) THEN 'military'
-- Outbuilding
WHEN lower(trim(element_at(tags, 'building'))) IN (
'allotment_house',
'carport',
'outbuilding',
'shed'
) THEN 'outbuilding'
-- Religious
WHEN lower(trim(element_at(tags, 'building'))) IN (
'cathedral',
'chapel',
'church',
'monastery',
'mosque',
'presbytery',
'religious',
'shrine',
'synagogue',
'temple',
'wayside_shrine'
) THEN 'religious'
-- Residential
WHEN lower(trim(element_at(tags, 'building'))) IN (
'apartments',
'bungalow',
'cabin',
'detached',
'dormitory',
'duplex',
'dwelling_house',
'garage',
'garages',
'ger',
'house',
'houseboat',
'hut',
'residential',
'semi',
'semidetached_house',
'static_caravan',
'stilt_house',
'terrace',
'townhouse',
'trullo'
) THEN 'residential'
-- Service
WHEN lower(trim(element_at(tags, 'building'))) IN (
'beach_hut',
'boathouse',
'digester',
'guardhouse',
'service',
'slurry_tank',
'storage_tank',
'toilets',
'transformer_tower'
) THEN 'service'
-- Transportation
WHEN lower(trim(element_at(tags, 'building'))) IN (
'hangar',
'parking',
'train_station',
'transportation'
) THEN 'transportation'
-- Consider any amenity / tourism tags if no other building tag was present
WHEN lower(trim(element_at(tags, 'amenity'))) IN (
'nursing_home'
) THEN 'residential'
WHEN lower(trim(element_at(tags, 'amenity'))) IN (
'bus_station',
'parking'
) THEN 'transportation'
WHEN lower(trim(element_at(tags, 'amenity'))) IN (
'place_of_worship'
) THEN 'religious'
WHEN lower(trim(element_at(tags, 'amenity'))) IN (
'clinic',
'dentist',
'doctors',
'hospital',
'pharmacy'
) THEN 'medical'
WHEN lower(trim(element_at(tags, 'amenity'))) IN (
'casino',
'conference_centre',
'events_venue',
'cinema',
'theatre',
'arts_centre',
'nightclub'
) THEN 'entertainment'
WHEN lower(trim(element_at(tags, 'tourism'))) IN (
'aquarium',
'attraction',
'gallery',
'museum'
) THEN 'entertainment'
WHEN lower(trim(element_at(tags, 'amenity'))) IN (
'bar',
'cafe',
'fast_food',
'food_court',
'fuel',
'ice_cream',
'pub',
'restaurant'
) THEN 'commercial'
WHEN lower(trim(element_at(tags, 'amenity'))) IN (
'animal_shelter',
'community_centre',
'courthouse',
'fire_station',
'library',
'police',
'post_office',
'public_bath',
'public_building',
'ranger_station',
'shelter',
'social_centre',
'townhall',
'veterinary'
) THEN 'civic'
WHEN lower(trim(element_at(tags, 'amenity'))) IN (
'college',
'driving_school',
'kindergarten',
'music_school',
'school',
'university'
) THEN 'education'
-- buildings that are part of bridge structures
WHEN lower(trim(element_at(tags, 'bridge:support'))) <> 'no'
THEN 'transportation'
WHEN lower(trim(element_at(tags, 'bridge:structure'))) <> 'no'
THEN 'transportation'
ELSE NULL
END
CASE
-- Prioritize these amenity tags when present because they are also used to determine subtype:
WHEN lower(trim(element_at(tags, 'amenity'))) IN (
'library',
'parking',
'post_office'
) THEN lower(trim(element_at(tags, 'amenity')))
-- Certain building tags become the class value to further describe the building subtype
WHEN lower(trim(element_at(tags, 'building'))) IN (
-- Agricultural
'agricultural',
'barn',
'cowshed',
'farm',
'farm_auxiliary',
'glasshouse',
'greenhouse',
'silo',
'stable',
'sty',
-- Civic
'civic',
'fire_station',
'government',
'public',
--Commercial
'commercial',
'hotel',
'kiosk',
'office',
'retail',
'supermarket',
'warehouse',
--Education
'college',
'kindergarten',
'school',
'university',
--Entertainment
'grandstand',
'pavilion',
'sports_centre',
'sports_hall',
'stadium',
--Industrial
'factory',
'industrial',
'manufacture',
--Medical
'hospital',
--Military
'bunker',
'military',
--Outbuilding
'allotment_house',
'carport',
'outbuilding',
'shed',
--Religious
'cathedral',
'chapel',
'church',
'monastery',
'mosque',
'presbytery',
'religious',
'shrine',
'synagogue',
'temple',
'wayside_shrine',
--Residential
'apartments',
'bungalow',
'cabin',
'detached',
'dormitory',
'dwelling_house',
'garage',
'garages',
'ger',
'house',
'houseboat',
'hut',
'residential',
'semi',
'semidetached_house',
'static_caravan',
'stilt_house',
'terrace',
'trullo',
--Service
'beach_hut',
'boathouse',
'digester',
'guardhouse',
'service',
'slurry_tank',
'storage_tank',
'toilets',
'transformer_tower',
-- Transportation
'hangar',
'parking',
'train_station',
'transportation'
) THEN lower(trim(element_at(tags, 'building')))
-- Certain building are part of bridge structures
WHEN lower(trim(element_at(tags, 'bridge:support'))) <> 'no'
THEN 'bridge_structure'
WHEN lower(trim(element_at(tags, 'bridge:structure'))) <> 'no'
THEN 'bridge_structure'
-- No other allowed classes
ELSE NULL
END
CASE
WHEN lower(trim(element_at(tags, 'building:material'))) IN (
'brick',
'slate',
'ladrillos',
'masonry',
'silicate brick',
'bricks',
'unburnt brick',
'silicate_brick',
'brick_block',
'muddy_brick'
) THEN 'brick'
WHEN lower(trim(element_at(tags, 'building:material'))) IN (
'cement_block',
'block',
'cement block',
'cement_blocks',
'cement blocks'
) THEN 'cement_block'
WHEN lower(trim(element_at(tags, 'building:material'))) IN (
'clay',
'mud',
'rammed_earth',
'loam',
'earth',
'grass',
'pressed_soil_blocks'
) THEN 'clay'
WHEN lower(trim(element_at(tags, 'building:material'))) IN (
'concrete',
'concrete masonry unit',
'cement',
'concrete_reinforced',
'reinforced_concrete'
) THEN 'concrete'
WHEN lower(trim(element_at(tags, 'building:material'))) IN (
'glass',
'mirror'
) THEN 'glass'
WHEN lower(trim(element_at(tags, 'building:material'))) IN (
'metal',
'steel',
'metal_plates',
'tin',
'iron_sheet',
'copper',
'metal_sheet',
'ironsheets',
'panel',
'aluminium'
) THEN 'metal'
WHEN lower(trim(element_at(tags, 'building:material'))) IN (
'plaster',
'plastered',
'hard'
) THEN 'plaster'
WHEN lower(trim(element_at(tags, 'building:material'))) IN (
'plastic',
'vinyl',
'plastic_sheeting',
'composite',
'vinyl_siding'
) THEN 'plastic'
WHEN lower(trim(element_at(tags, 'building:material'))) IN (
'stone',
'limestone',
'sandstone',
'granite',
'marble',
'tiles'
) THEN 'stone'
WHEN lower(trim(element_at(tags, 'building:material'))) IN (
'timber_framing',
'traditional'
) THEN 'timber_framing'
WHEN lower(trim(element_at(tags, 'building:material'))) IN (
'wood',
'reed',
'wattle_and_daub',
'timber_planks',
'wood/masonry',
'wood/bamboo',
'bamboo'
) THEN 'wood'
-- when building:material isn't usable then try building:facade:material
WHEN lower(trim(element_at(tags, 'building:facade:material'))) IN (
'brick',
'slate',
'ladrillos',
'masonry',
'silicate brick',
'bricks',
'unburnt brick',
'silicate_brick',
'brick_block',
'muddy_brick'
) THEN 'brick'
WHEN lower(trim(element_at(tags, 'building:facade:material'))) IN (
'cement_block',
'block',
'cement block',
'cement_blocks',
'cement blocks'
) THEN 'cement_block'
WHEN lower(trim(element_at(tags, 'building:facade:material'))) IN (
'clay',
'mud',
'rammed_earth',
'loam',
'earth',
'grass',
'pressed_soil_blocks'
) THEN 'clay'
WHEN lower(trim(element_at(tags, 'building:facade:material'))) IN (
'concrete',
'concrete masonry unit',
'cement',
'concrete_reinforced',
'reinforced_concrete'
) THEN 'concrete'
WHEN lower(trim(element_at(tags, 'building:facade:material'))) IN (
'glass',
'mirror'
) THEN 'glass'
WHEN lower(trim(element_at(tags, 'building:facade:material'))) IN (
'metal',
'steel',
'metal_plates',
'tin',
'iron_sheet',
'copper',
'metal_sheet',
'ironsheets',
'panel',
'aluminium'
) THEN 'metal'
WHEN lower(trim(element_at(tags, 'building:facade:material'))) IN (
'plaster',
'plastered',
'hard'
) THEN 'plaster'
WHEN lower(trim(element_at(tags, 'building:facade:material'))) IN (
'plastic',
'vinyl',
'plastic_sheeting',
'composite',
'vinyl_siding'
) THEN 'plastic'
WHEN lower(trim(element_at(tags, 'building:facade:material'))) IN (
'stone',
'limestone',
'sandstone',
'granite',
'marble',
'tiles'
) THEN 'stone'
WHEN lower(trim(element_at(tags, 'building:facade:material'))) IN (
'timber_framing',
'traditional'
) THEN 'timber_framing'
WHEN lower(trim(element_at(tags, 'building:facade:material'))) IN (
'wood',
'reed',
'wattle_and_daub',
'timber_planks',
'wood/masonry',
'wood/bamboo',
'bamboo'
) THEN 'wood'
ELSE NULL
END
CASE
WHEN lower(trim(element_at(tags, 'roof:shape'))) IN (
'dome'
) THEN 'dome'
WHEN lower(trim(element_at(tags, 'roof:shape'))) IN (
'flat'
) THEN 'flat'
WHEN lower(trim(element_at(tags, 'roof:shape'))) IN (
'gambrel'
) THEN 'gambrel'
WHEN lower(trim(element_at(tags, 'roof:shape'))) IN (
'gabled',
'pitched',
'crosspiched',
'double_pitch',
'gabled_height_moved',
'hip-and-gabled',
'gable',
'gabled_row',
'round_gabled',
'dutch_gabled',
'monopitch',
'2 faces (pitched)',
'2 face (pitched)',
'gabeled',
'gabed',
'gambled',
'double_gabled',
'gabred',
'cross_gabled'
) THEN 'gabled'
WHEN lower(trim(element_at(tags, 'roof:shape'))) IN (
'half-hipped',
'half_hipped'
) THEN 'half_hipped'
WHEN lower(trim(element_at(tags, 'roof:shape'))) IN (
'hipped',
'side_hipped',
'hyped',
'equal_hipped',
'4 faces (hipped)',
'side_half-hipped',
'side_half_hipped'
) THEN 'hipped'
WHEN lower(trim(element_at(tags, 'roof:shape'))) IN (
'mansard'
) THEN 'mansard'
WHEN lower(trim(element_at(tags, 'roof:shape'))) IN (
'onion',
'cone',
'conical'
) THEN 'onion'
WHEN lower(trim(element_at(tags, 'roof:shape'))) IN (
'pyramidal'
) THEN 'pyramidal'
WHEN lower(trim(element_at(tags, 'roof:shape'))) IN (
'round'
) THEN 'round'
WHEN lower(trim(element_at(tags, 'roof:shape'))) IN (
'saltbox',
'double_saltbox',
'quadruple_saltbox'
) THEN 'saltbox'
WHEN lower(trim(element_at(tags, 'roof:shape'))) IN (
'sawtooth'
) THEN 'sawtooth'
WHEN lower(trim(element_at(tags, 'roof:shape'))) IN (
'skillion',
'lean_to',
'triple_skillion'
) THEN 'skillion'
WHEN lower(trim(element_at(tags, 'roof:shape'))) IN (
'spherical'
) THEN 'spherical'
ELSE NULL
END
CASE
WHEN lower(trim(element_at(tags, 'roof:material'))) IN (
'asphalt_shingle',
'asphalt',
'concrete slab',
'concrete',
'rcc'
) THEN 'concrete'
WHEN lower(trim(element_at(tags, 'roof:material'))) IN (
'copper'
) THEN 'copper'
WHEN lower(trim(element_at(tags, 'roof:material'))) IN (
'a/c sheets',
'asbestos',
'eternit'
) THEN 'eternit'
WHEN lower(trim(element_at(tags, 'roof:material'))) IN (
'glass',
'acrylic_glass'
) THEN 'glass'
WHEN lower(trim(element_at(tags, 'roof:material'))) IN (
'grass',
'plants',
'roof_greening'
) THEN 'grass'
WHEN lower(trim(element_at(tags, 'roof:material'))) IN (
'gravel'
) THEN 'gravel'
WHEN lower(trim(element_at(tags, 'roof:material'))) IN (
'corrugated_iron_sheets',
'corrugated_iron',
'corrugated',
'iron_sheet',
'metal_sheet',
'metal:sheet',
'metal',
'tin',
'zinc',
'zink'
) THEN 'metal'
WHEN lower(trim(element_at(tags, 'roof:material'))) IN (
'plastic',
'composite'
) THEN 'plastic'
WHEN lower(trim(element_at(tags, 'roof:material'))) IN (
'roof_tiles',
'tile',
'tiles',
'roof-tiles',
'clay_tiles'
) THEN 'roof_tiles'
WHEN lower(trim(element_at(tags, 'roof:material'))) IN (
'brick',
'marble',
'sandstone',
'slate',
'stone'
) THEN 'slate'
WHEN lower(trim(element_at(tags, 'roof:material'))) IN (
'solar_panels'
) THEN 'solar_panels'
WHEN lower(trim(element_at(tags, 'roof:material'))) IN (
'tar_paper'
) THEN 'tar_paper'
WHEN lower(trim(element_at(tags, 'roof:material'))) IN (
'cadjan_palmyrah_straw',
'thatch'
) THEN 'thatch'
WHEN lower(trim(element_at(tags, 'roof:material'))) IN (
'wood',
'wooden'
) THEN 'wood'
ELSE NULL
END
Building Heights from OpenStreetMap
There are multiple ways to describe the height of an object in OSM. Overture, however, defines height as the number of meters from the ground to the tallest point of the feature. Therefore, we must parse and convert from the OSM string value.
We look for height values in the following OSM tags:
height
- The overall height of a building or building part.est_height
- The estimated height of a building or building part.min_height
- The minimum height of a building part.roof_height
- The height of the roof of a building or building part.
The OSM wiki specifically lists the following height values as valid: 4
, 4 m
, 1.35
, 7'4"
. However, there are many other formats present in the data that should be considered.
Comprehensive list of different height tag formats in OSM
As of June 2024:
Format | Count |
---|---|
X | 16,222,092 |
X m | 615,927 |
X meter | 212 |
X metre | 2 |
X' | 142,366 |
X ft | 721 |
X feet | 7 |
X'Y" | 2,432 |
X" | 6 |
Parsing & Conversion
There are a handful of common formatting issues that we generally allow when parsing height values including leading / trailing white space and incorrectly placed decimal points. We apply the following regular expressions to determine the unit of measurement and then perform the appropriate conversion:
- No Units
- Metric
- Imperial
^\s*\d+(\.\d*)?\s*$
Height strings that contain only a number value with no indicated units are assumed to be meters. These values are not rounded. Examples:
10
=> 1010
=> 1010.0
=> 1010.
=> 1010.6543
=> 10.6543
^\s*\d+(\.\d*)?\s*(m|meter|metre)s?\s*$
Height strings with a number follwed by a metric unit that matches the singular
or plural version form of m
, meter
, and metre
strings after the number are
also treated as meters and the units are stripped. These values are not rounded.
Examples:
10m
=> 1010 meters
=> 1010.0 metre
=> 1010. meter
=> 1010.6543meter
=> 10.6543
^\s*\d+(\.\d*)?\s*(''|ft|feet)\s*$
^\s*\d+(\.\d*)?\s*''\s*\d+(\.\d*)?\s*"\s*$
^\s*\d+(\.\d*)?"\s*$
Height strings with a number followed by an imperial unit are matched and converted to meters. Strings that are recognized as indicating units of feet are '
, ft
, and feet
. Strings that are recognized as indicating units of inches are "
. Inches and feet are matched in combination with each other or alone. When both feet and inches are indicated the '
string must be used to indicate feet and the inches value and "
string must be after the feet value. These values are then converted into meters by multiplying feet by 0.3048
. Inches are multiplied by 0.0254
. The final meters value is then rounded to two decimal places.
Examples:
10'
=> 3.0510.65 ft
=> 3.2510.65 feet
=> 3.2510. '
=> 3.0510.65feet
=> 3.0510' 13"
=> 3.3810' 13"
=> 3.3810'13"
=> 3.3810' 13"
=> 3.3810' 13"
=> 3.3810'13"
=> 3.38