Routing added on maps
This commit is contained in:
parent
e737bcab38
commit
9a2e507c24
3 changed files with 55 additions and 11 deletions
|
|
@ -15,7 +15,7 @@ from urllib.request import Request, urlopen
|
|||
from PIL import Image, ImageDraw, ImageFont
|
||||
|
||||
|
||||
VERSION = "2026-05-31-infographic-v5-single-location-footer-fix"
|
||||
VERSION = "2026-07-01-road-route-no-distance"
|
||||
|
||||
MAP_WIDTH = 906
|
||||
MAP_HEIGHT = 510
|
||||
|
|
@ -26,6 +26,7 @@ CLUSTER_RADIUS_KM = 2.0
|
|||
FOOTER_HEIGHT = 118
|
||||
FOOTER_MARGIN = 14
|
||||
USER_AGENT = "gpsmap-infographic-script/1.0"
|
||||
OSRM_ROUTE_URL = "https://router.project-osrm.org/route/v1/driving"
|
||||
|
||||
PHOTO_EXTENSIONS = {
|
||||
".jpg", ".jpeg", ".png", ".heic", ".heif", ".webp", ".tif", ".tiff"
|
||||
|
|
@ -168,6 +169,47 @@ def haversine_km(lat1, lon1, lat2, lon2):
|
|||
return 2 * r * math.atan2(math.sqrt(a), math.sqrt(1 - a))
|
||||
|
||||
|
||||
def fetch_road_route(points):
|
||||
"""Return route geometry as [(lat, lon), ...], falling back to straight points.
|
||||
|
||||
Uses OSRM's public OpenStreetMap-based demo router. The footer intentionally
|
||||
does not show route distance; this is only for drawing a more realistic path.
|
||||
"""
|
||||
if len(points) < 2:
|
||||
return points
|
||||
|
||||
try:
|
||||
coords = ";".join(f"{lon:.6f},{lat:.6f}" for lat, lon in points)
|
||||
params = urlencode({
|
||||
"overview": "full",
|
||||
"geometries": "geojson",
|
||||
"steps": "false",
|
||||
})
|
||||
url = f"{OSRM_ROUTE_URL}/{coords}?{params}"
|
||||
request = Request(url, headers={"User-Agent": USER_AGENT})
|
||||
|
||||
with urlopen(request, timeout=30) as response:
|
||||
data = json.loads(response.read().decode("utf-8"))
|
||||
|
||||
if data.get("code") != "Ok":
|
||||
message = data.get("message") or data.get("code") or "unknown OSRM error"
|
||||
raise RuntimeError(message)
|
||||
|
||||
route = (data.get("routes") or [{}])[0]
|
||||
coordinates = route.get("geometry", {}).get("coordinates") or []
|
||||
road_points = [(float(lat), float(lon)) for lon, lat in coordinates]
|
||||
|
||||
if len(road_points) < 2:
|
||||
raise RuntimeError("empty route geometry")
|
||||
|
||||
print(f"Road route: {len(road_points)} geometry points")
|
||||
return road_points
|
||||
|
||||
except Exception as e:
|
||||
print(f"Road route unavailable; using straight lines: {e}")
|
||||
return points
|
||||
|
||||
|
||||
def collect_media(media_dir):
|
||||
items = []
|
||||
|
||||
|
|
@ -604,19 +646,18 @@ def main():
|
|||
|
||||
clusters = make_clusters(items)
|
||||
points = [(c.lat, c.lon) for c in clusters]
|
||||
route_latlon = fetch_road_route(points)
|
||||
view_points = (route_latlon + points) if len(route_latlon) > 1 else points
|
||||
|
||||
zoom = choose_zoom(points, MAP_WIDTH, MAP_HEIGHT)
|
||||
top_left_x, top_left_y = map_view(points, zoom)
|
||||
zoom = choose_zoom(view_points, MAP_WIDTH, MAP_HEIGHT)
|
||||
top_left_x, top_left_y = map_view(view_points, zoom)
|
||||
|
||||
label = make_map_label(items, clusters)
|
||||
photo_count = sum(1 for i in items if i.kind == "photo")
|
||||
video_count = sum(1 for i in items if i.kind == "video")
|
||||
distance = round(route_distance_km(clusters))
|
||||
stats_parts = [plural(photo_count, "photo")]
|
||||
if video_count:
|
||||
stats_parts.append(plural(video_count, "video"))
|
||||
if len(clusters) > 1 and distance > 0:
|
||||
stats_parts.append(f"{distance} km route")
|
||||
stats = " • ".join(stats_parts)
|
||||
date_text = format_date_range(items)
|
||||
print(f"Map label: {label}")
|
||||
|
|
@ -627,10 +668,11 @@ def main():
|
|||
image = render_tiles(top_left_x, top_left_y, zoom)
|
||||
draw = ImageDraw.Draw(image)
|
||||
|
||||
route_points = [screen_xy(c.lat, c.lon, zoom, top_left_x, top_left_y) for c in clusters]
|
||||
route_points = [screen_xy(lat, lon, zoom, top_left_x, top_left_y) for lat, lon in route_latlon]
|
||||
draw_route(draw, route_points)
|
||||
|
||||
for cluster, (x, y) in zip(clusters, route_points):
|
||||
marker_points = [screen_xy(c.lat, c.lon, zoom, top_left_x, top_left_y) for c in clusters]
|
||||
for cluster, (x, y) in zip(clusters, marker_points):
|
||||
draw_cluster_marker(draw, x, y, cluster)
|
||||
|
||||
draw_bottom_title(draw, label, stats, date_text)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue