2. Introduction
• Lead Software Engineer @ HERE
Get in contact
• Twitter @tafkas
• GitHub Tafkas
• Blog blog.tafkas.net
GeoPython 2021 - Mapquadlib
3. What are MapQuads?
• Quadtree data structure in which each
internal node has exactly four
children.
• Partitions a two-dimensional space by
recursively subdividing it into four
quadrants.
GeoPython 2021 - Mapquadlib
4. Why using MapQuads?
• Very convenient way to represent some area on the map
• load tiles individually
• Binning spatial data
• Pre-compute tiles
GeoPython 2021 - Mapquadlib
6. Morton Codes
• Interleaving the binary coordinate
values yields binary z-values
• Connecting the z-values in their
numerical order produces the
recursively Z-shaped curve
• Two-dimensional z-values are also
called quadkey
GeoPython 2021 - Mapquadlib
7. Morton Codes - Example
Example: A Mapquad of zoom level 10 with column x=754 and row y=531
1. Convert X and Y to binary values
x = 1011110010
y = 1000010011
2. Interleave x and y, with
• x on even and
• y on odd positions
morton_key = 1100 0101 0111 0000 1110
= 11 00 01 01 01 11 10 00 00 11 10
=> 3 0 1 1 1 3 2 0 0 3 2
= 30111320032 = quad_key
GeoPython 2021 - Mapquadlib
8. Mapquadlib
A Python library for working with MapQuads
• Uses only Python Standard Library => zero dependencies
• Well tested: over 500 tests, 92% test coverage
• Currently, supports MercatorQuads and HereQuads
• To be open-sourced soon
GeoPython 2021 - Mapquadlib
9. MercatorQuads
• Used at Bing Maps, Mapbox
• Tiling schema with baked in Mercator
projection
•
!
Tile is always a square on the
map surface
•
"
Distortion
•
"
Latitude is limited up to ~85.05
degrees north and ~-85.05 south
GeoPython 2021 - Mapquadlib
10. HereQuads
• Based on raw, non-projected WGS84
lat/lng coordinate values
• non-square tiles when viewed on
Mercator projected 2D map
•
!
Tile size in degrees does not change
when close to the poles
GeoPython 2021 - Mapquadlib
16. Mapquadlib - Descendants
Get a MapQuad's descendants:
descendants = my_quad.descendants(14)
geo_collection = {
"type": "GeometryCollection",
"geometries": [d.bounding_box._geojson()
for d in descendants]
}
GeoPython 2021 - Mapquadlib
17. Mapquadlib - Neighbors
Get a MapQuad's neighbors:
neighbors = my_quad.neighbors()
geo_collection = {
"type": "GeometryCollection",
"geometries": [d.bounding_box._geojson()
for d in neighbors]
}
GeoPython 2021 - Mapquadlib
18. Mapquadlib - Neighbors
Get a MapQuad's neighbors at a different
level:
neighbors = my_quad.neighbors(14)
geo_collection = {
"type": "GeometryCollection",
"geometries": [d.bounding_box._geojson()
for d in neighbors]
}
GeoPython 2021 - Mapquadlib
19. Mapquadlib - Iterators
Get all MapQuads for a given bounding
box
berlin = BoundingBox(west=13.08835,
south=52.33826,
east=13.76116,
north=52.67551)
quads = MapQuadIterator(HereQuad,level=14,
bounding_box=berlin)
geo_collection = {
"type": "GeometryCollection",
"geometries": [q.bounding_box._geojson() for q in quads]
}
GeoPython 2021 - Mapquadlib
20. Mapquadlib - Conversion
Convert from one MapQuad type to
another
iterator = MapQuadIterator(MercatorQuad,
level=14,
bounding_box=berlin)
geojson = {
"type": "GeometryCollection",
"geometries": [q.bounding_box._geojson() for q in iterator]
}
here_quads = set([HereQuad.from_geocoordinate_level(q.bounding_box.center,
level=14) for q in iterator])
geojson = {
"type": "GeometryCollection",
"geometries": [q.bounding_box._geojson() for q in here_quads]
}
GeoPython 2021 - Mapquadlib
21. Mapquadlib - Conversion
Convert from one MapQuad type to
another
iterator = MapQuadIterator(MercatorQuad,
level=14,
bounding_box=berlin)
geojson = {
"type": "GeometryCollection",
"geometries": [q.bounding_box._geojson() for q in iterator]
}
here_quads = set([HereQuad.from_geocoordinate_level(q.bounding_box.center,
level=14) for q in iterator])
geojson = {
"type": "GeometryCollection",
"geometries": [q.bounding_box._geojson() for q in here_quads]
}
GeoPython 2021 - Mapquadlib
22. References
1. Tiled web map
2. Z-order curve
3. Bing Maps Tile System
4. Here Developer Portal
GeoPython 2021 - Mapquadlib