diff --git a/VERSION b/VERSION index e90170d..1c49fec 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1242 \ No newline at end of file +1243 \ No newline at end of file diff --git a/backend/main.py b/backend/main.py index 5cbb96b..b473156 100644 --- a/backend/main.py +++ b/backend/main.py @@ -371,6 +371,7 @@ app.mount("/css", StaticFiles(directory=f"{STATIC_DIR}/css"), name="css") app.mount("/js", StaticFiles(directory=f"{STATIC_DIR}/js"), name="js") app.mount("/icons", StaticFiles(directory=f"{STATIC_DIR}/icons"), name="icons") app.mount("/img", StaticFiles(directory=f"{STATIC_DIR}/img"), name="img") +app.mount("/sounds", StaticFiles(directory=f"{STATIC_DIR}/sounds"), name="sounds") # Yaro-Navi-Sounds # Selbst-gehostete Vektor-Tiles (.pmtiles) — liegen im data-Volume, NICHT im Image. # WICHTIG: Starlettes StaticFiles/FileResponse liefert hinter unserer BaseHTTPMiddleware diff --git a/backend/routes/routen.py b/backend/routes/routen.py index db57d55..ee3bac7 100644 --- a/backend/routes/routen.py +++ b/backend/routes/routen.py @@ -73,6 +73,31 @@ def _simplify_track(track: list, max_pts: int = 40) -> list: return [track[round(i * step)] for i in range(max_pts)] +def _decode_polyline3d(encoded: str) -> list: + """ORS-Polyline MIT Elevation: Tripel (lat, lon, ele), Präzision 1e5/1e5/1e2. + Das polyline-Paket kann nur 2D — es würde die Höhen-Deltas als nächste + Koordinate fehlinterpretieren und Müll liefern.""" + coords, idx, lat, lon, ele = [], 0, 0, 0, 0 + n = len(encoded) + while idx < n: + deltas = [] + for _ in range(3): + result, shift = 0, 0 + while True: + b = ord(encoded[idx]) - 63 + idx += 1 + result |= (b & 0x1F) << shift + shift += 5 + if b < 0x20: + break + deltas.append(~(result >> 1) if result & 1 else result >> 1) + lat += deltas[0] + lon += deltas[1] + ele += deltas[2] + coords.append((lat / 1e5, lon / 1e5, ele / 1e2)) + return coords + + def _parse(row) -> dict: d = dict(row) if isinstance(d.get('gps_track'), str): @@ -249,6 +274,7 @@ async def suggest_route(data: SuggestRequest, user=Depends(get_current_user)): }, "units": "m", "geometry": True, + "elevation": True, # Anstieg/Abstieg für ehrliche Schwierigkeit (René 2026-06-06) "instructions": False, } @@ -282,16 +308,20 @@ async def suggest_route(data: SuggestRequest, user=Depends(get_current_user)): except (KeyError, IndexError) as exc: raise HTTPException(502, f"Unerwartete ORS-Antwort: {exc}") - # encoded polyline → [[lat, lon], ...] - points = _polyline.decode(geometry) - gps_track = [{"lat": p[0], "lon": p[1]} for p in points] + # encoded polyline → Track. ACHTUNG: mit elevation=True codiert ORS 3D + # (lat, lon, ele) — der Standard-2D-Decoder würde Müll liefern. + points = _decode_polyline3d(geometry) + gps_track = [{"lat": p[0], "lon": p[1], "alt": round(p[2])} for p in points] distanz_km = round(distanz_m / 1000, 2) dauer_min = max(1, round(dauer_s / 60)) + ascent_m = round(summary.get("ascent", 0)) - if distanz_km < 3: + # Schwierigkeit aus Distanz UND Höhenmetern (René 2026-06-06) — vorher nur km: + # eine flache 6-km-Runde ist nicht „anspruchsvoll", 3 km steil bergauf nicht „leicht". + if distanz_km < 4 and ascent_m < 50: schwierigkeit = "leicht" - elif distanz_km <= 5: + elif distanz_km <= 7 and ascent_m < 150: schwierigkeit = "mittel" else: schwierigkeit = "anspruchsvoll" @@ -319,6 +349,7 @@ async def suggest_route(data: SuggestRequest, user=Depends(get_current_user)): "gps_track": gps_track, "distanz_km": distanz_km, "dauer_min": dauer_min, + "hoehenmeter": ascent_m, "schwierigkeit": schwierigkeit, "weekly_remaining": weekly_remaining, } diff --git a/backend/static/index.html b/backend/static/index.html index 88c1392..bc12e79 100644 --- a/backend/static/index.html +++ b/backend/static/index.html @@ -86,14 +86,14 @@