Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions mapmaker/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,10 @@ def arg_parser():
help='Maximum zoom level (defaults to 10)')
zoom_options.add_argument('--max-raster-zoom', dest='maxRasterZoom', metavar='N', type=int,
help='Maximum zoom level of rasterised tiles (defaults to maximum zoom level)')
zoom_options.add_argument('--path-min-coverage', dest='pathMinCoverage', metavar='R', type=float, default=0.7,
help='Lower coverage factor used to derive path minzoom (defaults to 0.7)')
zoom_options.add_argument('--path-max-coverage', dest='pathMaxCoverage', metavar='R', type=float, default=5.0,
help='Upper coverage factor used to derive path maxzoom (defaults to 5.0)')

misc_options = parser.add_argument_group('Miscellaneous')
misc_options.add_argument('--commit', metavar='GIT_COMMIT',
Expand Down
8 changes: 8 additions & 0 deletions mapmaker/maker.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,14 @@ def __init__(self, options: dict[str, Any], logger_port: Optional[int]=None,
raise ValueError(f'Max raster zoom cannot be greater than max zoom ({max_zoom})')
if initial_zoom < min_zoom or initial_zoom > max_zoom:
raise ValueError(f'Initial zoom cannot be greater than max zoom ({max_zoom})')

path_min_coverage = options.get('pathMinCoverage', 0.7)
path_max_coverage = options.get('pathMaxCoverage', 5.0)
if path_min_coverage <= 0 or path_max_coverage <= 0:
raise ValueError('Path coverage values must be greater than 0')
if path_max_coverage < path_min_coverage:
raise ValueError('Path max coverage cannot be less than path min coverage')

self.__zoom = (min_zoom, max_zoom, initial_zoom)

if options.get('publish'):
Expand Down
49 changes: 49 additions & 0 deletions mapmaker/output/geojson.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,11 @@

#===============================================================================

# Earth circumference (WGS84 equatorial radius for Web Mercator EPSG:3857)
EARTH_CIRCUMFERENCE = 2 * math.pi * 6378137.0 # meters

#===============================================================================

class GeoJSONOutput(object):
def __init__(self, flatmap: FlatMap, layer: MapLayer, output_dir: str):
#======================================================================
Expand Down Expand Up @@ -120,6 +125,10 @@ def __save_features(self, features):
if scale > 6 and 'group' not in properties and 'minzoom' not in properties:
geojson['tippecanoe']['minzoom'] = 4
else:
if (nodes:=self.__flatmap.connectivity()['paths'].get(feature.models)):
zoom_range = self.__get_path_zoom_range(nodes)
geojson['properties']['minzoom'] = zoom_range[0]
geojson['properties']['maxzoom'] = zoom_range[1]
geojson['properties']['scale'] = 10
geojson['properties'].update(properties)

Expand Down Expand Up @@ -158,3 +167,43 @@ def __save_features(self, features):
progress_bar.update(1)

progress_bar.close()

def __get_path_zoom_range(self, nodes):
path_min_coverage = settings.get('pathMinCoverage', 0.7)
path_max_coverage = settings.get('pathMaxCoverage', 5.0)

points = [geom.centroid
for node in nodes.get('nodes', [])
if (f := self.__flatmap.get_feature_by_geojson_id(node)) is not None
and (geom := f.geometry) is not None]

if len(points) > 1:
# extent
xs = [p.x for p in points]
ys = [p.y for p in points]
# World-space extents (meters, EPSG:3857)
x_extent = max(xs) - min(xs)
y_extent = max(ys) - min(ys)
max_dist = 0.0
for i, p1 in enumerate(points):
for p2 in points[i+1:]:
dist = math.hypot(p2.x - p1.x, p2.y - p1.y)
if dist > max_dist:
max_dist = dist
extent = max(x_extent, y_extent, max_dist)
if not math.isfinite(extent) or extent <= 0:
return self.__flatmap.min_zoom, self.__flatmap.max_zoom

# minzoom and maxzoom
z_min = math.ceil(math.log2((path_min_coverage * EARTH_CIRCUMFERENCE) / extent))
z_max = math.floor(math.log2((path_max_coverage * EARTH_CIRCUMFERENCE) / extent))
if z_max < z_min:
z_max = z_min
z_min = max(self.__flatmap.min_zoom, z_min)
z_max = min(self.__flatmap.max_zoom, z_max)
if z_min >= self.__flatmap.max_zoom:
z_min = self.__flatmap.max_zoom - 1
z_max = self.__flatmap.max_zoom
return z_min, z_max

return self.__flatmap.min_zoom, self.__flatmap.max_zoom
Loading