Add train route distance info

This commit is contained in:
Edward Betts 2024-04-05 15:58:44 +02:00
parent 5964899a00
commit 8ef67e0cee
6 changed files with 70 additions and 7 deletions

View file

@ -1,12 +1,14 @@
"""Travel.""" """Travel."""
import json
import os import os
import typing import typing
import flask import flask
import yaml import yaml
from geopy.distance import geodesic
from .types import Event from .types import Event, StrDict
Leg = dict[str, str] Leg = dict[str, str]
@ -63,3 +65,47 @@ def flight_number(flight: Leg) -> str:
def all_events(data_dir: str) -> list[Event]: def all_events(data_dir: str) -> list[Event]:
"""Get all flights and rail journeys.""" """Get all flights and rail journeys."""
return get_trains(data_dir) + get_flights(data_dir) return get_trains(data_dir) + get_flights(data_dir)
RouteDistances = dict[tuple[str, str], float]
def train_leg_distance(geojson_data: StrDict) -> float:
"""Calculate the total length of a LineString in kilometers from GeoJSON data."""
# Extract coordinates
first_object = geojson_data["features"][0]["geometry"]
assert first_object["type"] in ("LineString", "MultiLineString")
if first_object["type"] == "LineString":
coord_list = [first_object["coordinates"]]
else:
first_object["type"] == "MultiLineString"
coord_list = first_object["coordinates"]
# pprint(coordinates)
total_length_km = 0.0
for coordinates in coord_list:
total_length_km += sum(
float(geodesic(coordinates[i], coordinates[i + 1]).km)
for i in range(len(coordinates) - 1)
)
return total_length_km
def load_route_distances(data_dir: str) -> RouteDistances:
"""Load cache of route distances."""
route_distances: RouteDistances = {}
with open(os.path.join(data_dir, "route_distances.json")) as f:
for s1, s2, dist in json.load(f):
route_distances[(s1, s2)] = dist
return route_distances
def add_leg_route_distance(leg: StrDict, route_distances: RouteDistances) -> None:
s1, s2 = sorted([leg["from"], leg["to"]])
dist = route_distances.get((s1, s2))
if dist:
leg["distance"] = dist

View file

@ -98,6 +98,8 @@
| <a href="https://uk.flightaware.com/live/flight/{{ full_flight_number | replace("U2", "EZY") }}">FlightAware</a> | <a href="https://uk.flightaware.com/live/flight/{{ full_flight_number | replace("U2", "EZY") }}">FlightAware</a>
| <a href="{{ radarbox_url }}">radarbox</a> | <a href="{{ radarbox_url }}">radarbox</a>
</div> </div>
<div class="grid-item">
</div>
{% endmacro %} {% endmacro %}
{% macro train_row(item) %} {% macro train_row(item) %}
@ -131,4 +133,9 @@
{% endif %} {% endif %}
{% endfor %} {% endfor %}
</div> </div>
<div class="grid-item text-end">
{% if item.distance %}
{{ "{:.1f} km / {:.1f} miles".format(item.distance, item.distance / 1.60934) }}
{% endif %}
</div>
{% endmacro %} {% endmacro %}

View file

@ -5,14 +5,14 @@
<style> <style>
.grid-container { .grid-container {
display: grid; display: grid;
grid-template-columns: repeat(8, auto); grid-template-columns: repeat(9, auto);
gap: 10px; gap: 10px;
justify-content: start; justify-content: start;
} }
.train-grid-container { .train-grid-container {
display: grid; display: grid;
grid-template-columns: repeat(8, auto); grid-template-columns: repeat(9, auto);
gap: 10px; gap: 10px;
justify-content: start; justify-content: start;
} }

View file

@ -10,7 +10,7 @@
{% set conference_column_count = 7 %} {% set conference_column_count = 7 %}
{% set accommodation_column_count = 7 %} {% set accommodation_column_count = 7 %}
{% set travel_column_count = 8 %} {% set travel_column_count = 9 %}
<style> <style>
.conferences { .conferences {
display: grid; display: grid;

View file

@ -25,7 +25,7 @@
{% set conference_column_count = 7 %} {% set conference_column_count = 7 %}
{% set accommodation_column_count = 7 %} {% set accommodation_column_count = 7 %}
{% set travel_column_count = 8 %} {% set travel_column_count = 9 %}
<style> <style>
.conferences { .conferences {
display: grid; display: grid;

View file

@ -117,6 +117,15 @@ def travel_list() -> str:
if isinstance(item["depart"], datetime) if isinstance(item["depart"], datetime)
] ]
route_distances = agenda.travel.load_route_distances(app.config["DATA_DIR"])
for train in trains:
for leg in train["legs"]:
agenda.travel.add_leg_route_distance(leg, route_distances)
if all("distance" in leg for leg in train["legs"]):
train["distance"] = sum(leg["distance"] for leg in train["legs"])
return flask.render_template("travel.html", flights=flights, trains=trains) return flask.render_template("travel.html", flights=flights, trains=trains)
@ -300,7 +309,6 @@ def human_readable_delta(future_date: date) -> str | None:
@app.route("/trip/<start>") @app.route("/trip/<start>")
def trip_page(start: str) -> str: def trip_page(start: str) -> str:
"""Individual trip page.""" """Individual trip page."""
trip_list = [ trip_list = [
trip trip
for trip in agenda.trip.build_trip_list() for trip in agenda.trip.build_trip_list()
@ -341,7 +349,9 @@ def trip_page(start: str) -> str:
for route in routes: for route in routes:
if "geojson_filename" in route: if "geojson_filename" in route:
route["geojson"] = agenda.trip.read_geojson(route.pop("geojson_filename")) route["geojson"] = agenda.trip.read_geojson(
app.config["PERSONAL_DATA"], route.pop("geojson_filename")
)
if trip.end: if trip.end:
countries = {c.alpha_2 for c in trip.countries} countries = {c.alpha_2 for c in trip.countries}