OSM Quick 3D

OSM to native QGIS 2D/3D styled layers with flat-roof building massing • v0.20.4

1. Overview

OSM Quick 3D downloads OpenStreetMap data for a user-defined study area and produces native QGIS vector layers styled by function, with optional 3D building extrusion through QGIS's own 3D symbology engine. Unlike its sibling plugin osm_3d_model (which opens a browser-based Three.js viewer), OSM Quick 3D keeps everything inside QGIS as editable vector layers—suited for larger areas, analysis, printing, and manual editing. The plugin provides a dock-based, two-tab control panel with a Build tab for data acquisition and a Theme & Style tab for live retuning.

2. Theoretical Foundations

2.1 OpenStreetMap as Urban Data Infrastructure

Haklay and Weber (2008) established OSM as a viable volunteered geographic information (VGI) platform, demonstrating that user-generated street maps can match or exceed the completeness of authoritative datasets in well-mapped urban areas. Fan et al. (2014) specifically validated OSM building footprint quality, finding that in German urban areas, OSM building data achieved >80% completeness with positional accuracy comparable to cadastral surveys. The plugin leverages this by treating OSM as the primary data source for rapid urban morphology assessment, with the Overpass API serving as a query interface.

2.2 Level of Detail in 3D City Models

Kolbe (2009) formalised the CityGML LOD (Level of Detail) hierarchy for 3D city models: LOD1 comprises prismatic building blocks with flat roofs derived from footprints and height attributes, LOD2 adds roof structures, and LOD3 adds architectural details. OSM Quick 3D produces LOD1 models: flat-roofed extrusions from OSM building footprints with heights derived from OSM tags or typology-based defaults. Biljecki et al. (2017) demonstrated that LOD1 models generated from OSM without elevation data can achieve high accuracy when building height attributes are present, supporting the plugin's three-tier height fallback strategy.

3. Study Area Definition

Boundary Sources and Shapes

Two area sources: Visible map extent (canvas) or Selected features (active layer, dissolved via unaryUnion()). Five boundary shapes: Rectangle (raw bounding box), Rounded rectangle (corners at ~18% of short side via double-buffer technique: buffer(-corner, 12) then buffer(+corner, 12)), Circle (inscribed, radius = min(width, height) / 2, 64 segments), Hexagon (pointy-top orientation, 6 points at 60° intervals starting at −30°, inscribed), and Polygon (user-selected feature, dissolved if multiple).

The area is auto-projected to its local UTM zone via utm_epsg_for(): zone = \(\lfloor(\lambda + 180)/6\rfloor + 1\), clamped 1–60, EPSG = 32600 + zone (north) or 32700 + zone (south). Area is clamped to a configurable maximum in square kilometres (default 6 km2) by shrinking uniformly around the centroid.

4. OSM Data Download

Overpass API Pipeline with Multi-Mirror Fallback

The plugin constructs a single Overpass QL query requesting all features within the WGS84 bounding box: ways and relations with building, highway, waterway (river/stream/canal/drain/ditch/riverbank), leisure (park/garden/playground/pitch/nature_reserve/common/dog_park/golf_course), landuse (forest/grass/meadow/recreation_ground/cemetery/reservoir/basin/village_green/orchard/vineyard/farmland/allotments/greenfield), natural (wood/scrub/water/grassland/heath), amenity (parking/marketplace), and place=square; plus nodes for trees, bus stops (also public_transport=platform), benches, street lamps, and waste baskets. The query uses out body geom; for full geometry, with a 60-second timeout.

Multi-mirror fallback: Three endpoints are tried in order (overpass-api.de, overpass.kumi.systems, overpass.private.coffee) with a 10-second additional HTTP read timeout. HTTP 429 (rate-limited) triggers the next mirror. The first endpoint returning valid, non-empty JSON wins. Feedback messages distinguish first query from mirror fallback.

5. Data Layers

Twelve Layer Types

The plugin creates 12 in-memory vector layers (all Multi* geometry for features potentially split by clipping):

LayerGeometryKey Attributes
OSM BuildingsMultiPolygonosm_id, building, building_levels, height, footprint_m2, gfa_m2, name
OSM RoadsMultiLineStringosm_id, highway, width, name
OSM Bike lanesMultiLineStringosm_id, highway, width, name
OSM GreensMultiPolygonosm_id, leisure, landuse, natural, amenity, highway, place, name
OSM WaterlinesMultiLineStringosm_id, waterway, width, name
OSM Water areasMultiPolygonosm_id, natural, waterway, landuse, name
OSM TreesPointosm_id, natural, height
OSM Bus stopsPointosm_id, highway, name
OSM BenchesPointosm_id, amenity
OSM Street lightsPointosm_id, highway
OSM Trash binsPointosm_id, amenity
OSM Base (optional)PolygonGround plinth extruded from -2 m below terrain to -0.15 m

Each layer is clipped against the valid study boundary (geom.makeValid() if needed, then intersection(clip_boundary)). Multipolygon assembly handles OSM relations with outer/inner ring roles for buildings with courtyards. Geometry classification follows a priority order: tree nodes → water areas → parking lots → paved squares → buildings → roads (with cycleway deduplication) → waterways → greens.

6. Building Height Logic

Three-Tier Fallback with 57 Type-Specific Defaults

Height is derived per-building by _building_levels():

  1. Parse building:levels or levels tag, rounded to integer, clamped to ≥1. Handles semicolons ("3;4") and unit suffixes ("m", "ft", etc.).
  2. If no floor count: parse height tag in metres, divide by 3.0, round, clamp to ≥1.
  3. Function-based default from a 57-entry dictionary keyed by OSM building type: apartments=4, residential=4, detached=2, house=2, bungalow=1, office=5, commercial=3, school=3, university=4, hospital=5, church/mosque/temple/synagogue/chapel=1 (cathedral=2), warehouse=1, garage=1, shed=1, unknown=3.
  4. Add roof:levels if present. Final: max(1, base + roof_levels).

For the 3D extrusion expression: coalesce(to_real("height"), to_int("building_levels") × 3, 9). The nine-metre default (3 floors at 3 m/floor) serves as the ultimate fallback when neither OSM height tag nor building:levels tag is present and the building type is unrecognised.

7. Building Colour Modes (8)

Function-Based and Height-Based Schemes

Mode2D RendererDescription
By function (OSM use)QgsCategorizedSymbolRenderer6 categories: residential, commercial, industrial, civic, worship, other. Static palette per theme.
Graduated by heightData-defined fill colour3 classification methods: Continuous (10-step color_rgb(scale_linear(...))), Discrete (5 equal-interval classes), Quantile (5 classes at 20/40/60/80th percentiles).
Soft tinted grayData-defined fillRamp: #e8e9e8 → #6e746f
Soft tinted warmData-defined fillRamp: #ede2d4 → #8a7460
Soft tealData-defined fillRamp: #dbeae7 → #3c7c77
Soft salmonData-defined fillRamp: #f1ded7 → #b9776a
Soft purpleData-defined fillRamp: #e4dded → #6f5c86
Soft sandData-defined fillRamp: #ece6d6 → #9a8a63

The height expression reads actual layer values: coalesce(to_real("height"), to_int("building_levels") × 3, 9.0). Break values and 5 interpolated colours are cached per layer ID for performance.

8. Map Themes (12)

Coordinated Colour Palettes

ThemeBackgroundCharacter
Muted Planning#ffffffProfessional muted european tones; default
Tokyo Cyber#0a0b10Dark, neon purples/oranges/cyans on near-black
Editorial Paper#fdfbf7Warm ivory paper with sepia-brown accents
Nordic Frost#f5f7faCool minimal blues on clean white
Monochrome Noir#1e1e1eHigh-contrast grayscale from near-white to near-black
Civic Atlas#f7f8f2Clean survey tones: muted greens, blues, greys
Mediterranean Survey#fbf4e6Warm sun/sea palette: terracotta, olive, turquoise
Night Print#11161aDark cartographic: gold roads, dark greens, light buildings
Anime Cel#dff3ffBright cartoon pastels: candy pink, lime, sky blue
Desert Dunes#f6e7c8Warm arid: sand beige, rust orange, olive green
Pastel Candy#fff5fbSoft kawaii: lavender pinks, mint greens, baby blues
Vaporwave#2a1a4aNeon retro: deep purple base + hot pink/cyan/mint

Each theme sets: background colour, 6 building function colours, building height ramp (low→high), major road colour (motorway/primary/secondary/tertiary), minor road colour (residential/service/foot/other), greens colour (park/forest/pitch/cemetery/water category), water colour, and tree colour. Theme changes are live: they update the canvas background, recolour all layers, and refresh the 3D view without re-downloading data.

9. Native QGIS 3D Extrusion

Rule-Based 3D Renderer with Phong Materials

Building 3D extrusion uses QgsRuleBased3DRenderer with per-function or per-height-class child rules:

Ground base plinth: QgsPolygon3DSymbol extruded from -2.0 m below terrain to -0.15 m (prevents Z-fighting with terrain mesh). Theme-harmonised colour. Data-defined properties for height, extrusion depth, and offset.

Tree canopies: QgsPoint3DSymbol with Sphere shape (2.5 m radius). Transformed with QMatrix4x4().translate(0, 0, 2.5) so spheres rest on the surface. Phong material with theme tree colour.

Managed 3D canvas: Reuses a named Qgs3DMapCanvas ("OSM Quick 3D Scene") via iface.createNewMapCanvas3D(). Flat terrain with configurable tile resolution. Camera: distance = max(width, height, 100) × 1.35, pitch = 45°, zero bearing. Basemap clipping via QgsMapClippingRegion in ClipPainterOnly mode.

10. Tree Scattering Algorithm

Deterministic Procedural Tree Placement

Procedural trees are placed inside wooded green polygons (forest, wood, park, garden, etc.) using a deterministic seeded RNG:

Green TypeSpacing (m2/tree)Height Range (m)
Forest / Wood757–13
Orchard1104–7
Park1705–9
Garden2104–7
Nature Reserve1805–10
Village Green2204–8
Recreation Ground2304–8
Cemetery2605–9
Scrub2802.5–4.5
Allotments3203–5
Grass4003–6
Meadow4403–6

RNG: A Knuth MMIX linear congruential generator seeded from the polygon's bounding box coordinates, area, and green type code: seed = (bbox_minX × 73856093) XOR (bbox_minY × 19349663) XOR (area × 83492791) XOR (kind_code × 2654435761), masked to 32 bits. This ensures that re-running the same area produces identical tree placement every time.

Global cap: 500 total trees; per-polygon cap: 130. Target per polygon: min(130, remaining_cap, floor(polygon_area / spacing)). Rejection sampling: random points within the bounding box, accepted if geom_utm.contains(pt), up to 8× target attempts.

11. Expression-Based Styling

QGIS Expressions for Data-Driven Rendering

The plugin uses QGIS expression strings extensively, avoiding per-feature Python loops:

All colour and width properties are applied as data-defined overrides (QgsProperty.fromExpression()) rather than fixed renderer values, enabling live retuning without rebuilding the renderer.

12. Theme & Style Tab

Post-Build Live Retuning

The Theme & Style tab operates on an existing OSM Quick 3D layer group. Controls: group selector, theme combo with preview swatches, six colour pickers (major roads, minor roads, greens, water, trees, scene background), building colour mode, classification method (continuous/discrete/quantile), height exaggeration (0.5–5.0x), building opacity (0–100%), tree canopy size, tree colour, 3D view controls (Open/Refresh/Focus/Close), per-layer 3D visibility checkboxes, scene resolution selector, and basemap clip region management.

The key design pattern: _apply_changes() freezes the canvas, applies all current state in one batch, unfreezes, and refreshes—avoiding intermediate redraws. The 3D view is refreshed via _refresh_3d_view() with delayed retry timers (600 ms, 1500 ms, 3000 ms). A scene info panel shows real-time stats: 3D canvas open/closed, visible layer count, basemap clip status, and resolution.

13. Caching System

SHA-256 Disk Cache with 7-Day TTL

Responses are cached as JSON files in %TEMP%/osm_quick_3d_cache/. The cache key is SHA-256 of the full Overpass query string (truncated to 40 hex characters). TTL: 604800 seconds (7 days). On cache miss: fetch from Overpass, write back. On cache hit: validate payload structure; if corrupt, discard and re-fetch. A "Clear cache" button reports files removed and bytes freed. The "Use OSM cache" checkbox allows users to bypass the cache for fresh data.

14. Parameters and Controls

Build Tab

ControlTypeRange/OptionsDefault
Area sourceComboCanvas / SelectionCanvas
Area shapeComboRectangle / Rounded / Circle / Hexagon / PolygonRectangle
Max areaQDoubleSpinBox0.1 – 200 km26 km2
Layer checkboxesQCheckBoxBuildings / Roads / Water / Greens / Trees / Furniture / LabelsAll on
3D extrusionQCheckBoxOn / OffOff
Height exaggerationQDoubleSpinBox0.5–5.0x1.5x
Map themeCombo12 themesMuted Planning
Building coloursCombo8 modesBy function
Height classesComboContinuous / Discrete / QuantileContinuous
Ground baseQCheckBoxOn / OffOff
Save to GeoPackageQCheckBoxOn / OffOff
Use OSM cacheQCheckBoxOn / OffOn

15. Workflow Guide

  1. Open the OSM Quick 3D dock from the toolbar icon.
  2. On the Build tab, optionally click Add OSM basemap for an XYZ reference tile layer (EPSG:3857).
  3. Set area source, shape, and max area limit. The area is clamped to the configured maximum.
  4. Choose which layers to download. Enable 3D extrusion, set theme and building colour mode as desired.
  5. Click Download & build 3D. The plugin fetches data via Overpass, processes geometries, applies 2D styling, and optionally builds 3D extrusion.
  6. Layers appear in a tree group named "OSM Quick 3D -- EPSG:xxxxx". A managed 3D Map View opens if enabled.
  7. Switch to the Theme & Style tab for live retuning of colours, themes, building opacity, tree size, and per-layer 3D visibility without re-downloading data.
  8. Optionally export to GeoPackage (with layer prefix) for persistence across sessions.

16. Technical Notes

17. Literature

  1. Haklay, M. & Weber, P. (2008). OpenStreetMap: User-generated street maps. IEEE Pervasive Computing, 7(4), 12–18. DOI: 10.1109/MPRV.2008.80
  2. Biljecki, F., Ledoux, H., & Stoter, J. (2017). Generating 3D city models without elevation data. Computers, Environment and Urban Systems, 64, 1–18. DOI: 10.1016/j.compenvurbsys.2017.01.001
  3. Kolbe, T. H. (2009). Representing and exchanging 3D city models with CityGML. In J. Lee & S. Zlatanova (Eds.), 3D Geo-Information Sciences (pp. 15–31). Springer. DOI: 10.1007/978-3-540-87395-2_2
  4. Fan, H., Zipf, A., Fu, Q., & Neis, P. (2014). Quality assessment for building footprints data on OpenStreetMap. International Journal of Geographical Information Science, 28(4), 700–719. DOI: 10.1080/13658816.2013.867495
  5. Goetz, M. (2013). Towards generating highly detailed 3D CityGML models from OpenStreetMap. International Journal of Geographical Information Science, 27(5), 845–865. DOI: 10.1080/13658816.2012.721552
  6. Goodchild, M. F. (2007). Citizens as sensors: The world of volunteered geography. GeoJournal, 69(4), 211–221. DOI: 10.1007/s10708-007-9111-y
  7. Mooney, P. & Minghini, M. (2017). A review of OpenStreetMap data. In G. Foody et al. (Eds.), Mapping and the Citizen Sensor (pp. 37–59). Ubiquity Press. DOI: 10.5334/bbf.c