Add OSM Track Harvesting Policy and demo database initialization script

- Updated documentation to include OSM Track Harvesting Policy with details on railway types, service filters, usage filters, and geometry guardrails.
- Introduced a new script `init_demo_db.py` to automate the database setup process, including environment checks, running migrations, and loading OSM fixtures for demo data.
This commit is contained in:
2025-10-11 21:37:25 +02:00
parent 0b84ee953e
commit 25ca7ab196
9 changed files with 537737 additions and 18 deletions

View File

@@ -8,11 +8,15 @@ import math
import sys
from dataclasses import asdict
from pathlib import Path
from typing import Any, Iterable
from typing import Any, Iterable, Mapping
from urllib.parse import quote_plus
from backend.app.core.osm_config import (
DEFAULT_REGIONS,
TRACK_ALLOWED_RAILWAY_TYPES,
TRACK_EXCLUDED_SERVICE_TAGS,
TRACK_EXCLUDED_USAGE_TAGS,
TRACK_MIN_LENGTH_METERS,
TRACK_TAG_FILTERS,
compile_overpass_filters,
)
@@ -104,13 +108,15 @@ def normalize_track_elements(elements: Iterable[dict[str, Any]]) -> list[dict[st
continue
tags: dict[str, Any] = element.get("tags", {})
length_meters = _polyline_length(coordinates)
if not _should_include_track(tags, length_meters):
continue
name = tags.get("name")
maxspeed = _parse_maxspeed(tags.get("maxspeed"))
status = _derive_status(tags.get("railway"))
is_bidirectional = not _is_oneway(tags.get("oneway"))
length_meters = _polyline_length(coordinates)
tracks.append(
{
"osmId": str(element.get("id")),
@@ -156,6 +162,25 @@ def _derive_status(value: Any) -> str:
return "operational"
def _should_include_track(tags: Mapping[str, Any], length_meters: float) -> bool:
railway = str(tags.get("railway", "")).lower()
if railway not in TRACK_ALLOWED_RAILWAY_TYPES:
return False
if length_meters < TRACK_MIN_LENGTH_METERS:
return False
service = str(tags.get("service", "")).lower()
if service and service in TRACK_EXCLUDED_SERVICE_TAGS:
return False
usage = str(tags.get("usage", "")).lower()
if usage and usage in TRACK_EXCLUDED_USAGE_TAGS:
return False
return True
def _is_oneway(value: Any) -> bool:
if value is None:
return False