2525 NetworkError ,
2626 find_incomplete_relations ,
2727 get_osm ,
28+ get_osm_overpass ,
2829 get_overpass_relations ,
2930)
3031from map_machine .osm .osm_reader import OSMData
@@ -141,15 +142,33 @@ def get_extended_bounding_box(self) -> BoundingBox:
141142 float (point_1 [0 ]),
142143 ).round ()
143144
144- def load_osm_data (self , cache_path : Path ) -> OSMData :
145+ def load_osm_data (
146+ self , cache_path : Path , overpass_query : str | None = None
147+ ) -> OSMData :
145148 """Construct map data from extended bounding box.
146149
147150 :param cache_path: directory to store OSM data files
151+ :param overpass_query: custom Overpass query with `{{bbox}}`
152+ placeholder
148153 """
149- cache_file_path : Path = (
150- cache_path / f"{ self .get_extended_bounding_box ().get_format ()} .osm"
154+ bounding_box : BoundingBox = self .get_extended_bounding_box ()
155+ overpass_cache_path : Path = (
156+ cache_path / f"{ bounding_box .get_format ()} _overpass.osm"
151157 )
152- get_osm (self .get_extended_bounding_box (), cache_file_path )
158+
159+ if overpass_cache_path .is_file ():
160+ cache_file_path = overpass_cache_path
161+ else :
162+ cache_file_path = cache_path / f"{ bounding_box .get_format ()} .osm"
163+ try :
164+ get_osm (bounding_box , cache_file_path )
165+ except NetworkError as error :
166+ logger .warning (
167+ "OSM API failed (%s), falling back to Overpass API..." ,
168+ error .message ,
169+ )
170+ cache_file_path = overpass_cache_path
171+ get_osm_overpass (bounding_box , cache_file_path , overpass_query )
153172
154173 osm_data : OSMData = OSMData ()
155174 osm_data .parse_osm_file (cache_file_path )
@@ -178,16 +197,19 @@ def draw(
178197 configuration : MapConfiguration ,
179198 * ,
180199 use_overpass : bool = True ,
200+ overpass_query : str | None = None ,
181201 ) -> None :
182202 """Draw tile to SVG and PNG files.
183203
184204 :param directory_name: output directory for storing tiles
185205 :param cache_path: directory to store SVG and PNG tiles
186206 :param configuration: drawing configuration
187207 :param use_overpass: fetch missing relation data via Overpass API
208+ :param overpass_query: custom Overpass query with `{{bbox}}`
209+ placeholder
188210 """
189211 try :
190- osm_data : OSMData = self .load_osm_data (cache_path )
212+ osm_data : OSMData = self .load_osm_data (cache_path , overpass_query )
191213 except NetworkError as error :
192214 msg = f"Map is not loaded. { error .message } "
193215 raise NetworkError (msg ) from error
@@ -300,12 +322,35 @@ def from_bounding_box(
300322
301323 return cls (tiles , tile_1 , tile_2 , zoom_level , extended_bounding_box )
302324
303- def load_osm_data (self , cache_path : Path ) -> OSMData :
304- """Load OpenStreetMap data."""
305- cache_file_path : Path = (
306- cache_path / f"{ self .bounding_box .get_format ()} .osm"
325+ def load_osm_data (
326+ self , cache_path : Path , overpass_query : str | None = None
327+ ) -> OSMData :
328+ """Load OpenStreetMap data.
329+
330+ :param cache_path: directory for caching OSM data files
331+ :param overpass_query: custom Overpass query with `{{bbox}}` placeholder
332+ """
333+ overpass_cache_path : Path = (
334+ cache_path / f"{ self .bounding_box .get_format ()} _overpass.osm"
307335 )
308- get_osm (self .bounding_box , cache_file_path )
336+
337+ if overpass_cache_path .is_file ():
338+ cache_file_path = overpass_cache_path
339+ else :
340+ cache_file_path = (
341+ cache_path / f"{ self .bounding_box .get_format ()} .osm"
342+ )
343+ try :
344+ get_osm (self .bounding_box , cache_file_path )
345+ except NetworkError as error :
346+ logger .warning (
347+ "OSM API failed (%s), falling back to Overpass API..." ,
348+ error .message ,
349+ )
350+ cache_file_path = overpass_cache_path
351+ get_osm_overpass (
352+ self .bounding_box , cache_file_path , overpass_query
353+ )
309354
310355 osm_data : OSMData = OSMData ()
311356 osm_data .parse_osm_file (cache_file_path )
@@ -517,6 +562,12 @@ def generate_tiles(options: argparse.Namespace) -> None:
517562
518563 use_overpass : bool = not getattr (options , "no_overpass" , False )
519564
565+ overpass_query : str | None = None
566+ overpass_query_path : str | None = getattr (options , "overpass_query" , None )
567+ if overpass_query_path :
568+ with Path (overpass_query_path ).open (encoding = "utf-8" ) as query_file :
569+ overpass_query = query_file .read ()
570+
520571 if options .input_file_name :
521572 osm_data = OSMData ()
522573 osm_data .parse_osm_file (Path (options .input_file_name ))
@@ -548,7 +599,7 @@ def generate_tiles(options: argparse.Namespace) -> None:
548599 np .array (coordinates ), min_zoom_level
549600 )
550601 try :
551- osm_data = min_tile .load_osm_data (cache_path )
602+ osm_data = min_tile .load_osm_data (cache_path , overpass_query )
552603 except NetworkError as error :
553604 message = f"Map is not loaded. { error .message } "
554605 raise NetworkError (message ) from error
@@ -577,6 +628,7 @@ def generate_tiles(options: argparse.Namespace) -> None:
577628 cache_path ,
578629 configuration ,
579630 use_overpass = use_overpass ,
631+ overpass_query = overpass_query ,
580632 )
581633
582634 elif options .bounding_box :
@@ -589,7 +641,7 @@ def generate_tiles(options: argparse.Namespace) -> None:
589641
590642 min_tiles : Tiles = Tiles .from_bounding_box (bounding_box , min_zoom_level )
591643 try :
592- osm_data = min_tiles .load_osm_data (cache_path )
644+ osm_data = min_tiles .load_osm_data (cache_path , overpass_query )
593645 except NetworkError as error :
594646 message = f"Map is not loaded. { error .message } "
595647 raise NetworkError (message ) from error
0 commit comments