Add train route distance info
This commit is contained in:
parent
5964899a00
commit
8ef67e0cee
|
@ -1,12 +1,14 @@
|
|||
"""Travel."""
|
||||
|
||||
import json
|
||||
import os
|
||||
import typing
|
||||
|
||||
import flask
|
||||
import yaml
|
||||
from geopy.distance import geodesic
|
||||
|
||||
from .types import Event
|
||||
from .types import Event, StrDict
|
||||
|
||||
Leg = dict[str, str]
|
||||
|
||||
|
@ -63,3 +65,47 @@ def flight_number(flight: Leg) -> str:
|
|||
def all_events(data_dir: str) -> list[Event]:
|
||||
"""Get all flights and rail journeys."""
|
||||
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
|
||||
|
|
|
@ -98,6 +98,8 @@
|
|||
| <a href="https://uk.flightaware.com/live/flight/{{ full_flight_number | replace("U2", "EZY") }}">FlightAware</a>
|
||||
| <a href="{{ radarbox_url }}">radarbox</a>
|
||||
</div>
|
||||
<div class="grid-item">
|
||||
</div>
|
||||
{% endmacro %}
|
||||
|
||||
{% macro train_row(item) %}
|
||||
|
@ -131,4 +133,9 @@
|
|||
{% endif %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
<div class="grid-item text-end">
|
||||
{% if item.distance %}
|
||||
{{ "{:.1f} km / {:.1f} miles".format(item.distance, item.distance / 1.60934) }}
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endmacro %}
|
||||
|
|
|
@ -5,14 +5,14 @@
|
|||
<style>
|
||||
.grid-container {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(8, auto);
|
||||
grid-template-columns: repeat(9, auto);
|
||||
gap: 10px;
|
||||
justify-content: start;
|
||||
}
|
||||
|
||||
.train-grid-container {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(8, auto);
|
||||
grid-template-columns: repeat(9, auto);
|
||||
gap: 10px;
|
||||
justify-content: start;
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
{% set conference_column_count = 7 %}
|
||||
{% set accommodation_column_count = 7 %}
|
||||
{% set travel_column_count = 8 %}
|
||||
{% set travel_column_count = 9 %}
|
||||
<style>
|
||||
.conferences {
|
||||
display: grid;
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
|
||||
{% set conference_column_count = 7 %}
|
||||
{% set accommodation_column_count = 7 %}
|
||||
{% set travel_column_count = 8 %}
|
||||
{% set travel_column_count = 9 %}
|
||||
<style>
|
||||
.conferences {
|
||||
display: grid;
|
||||
|
|
14
web_view.py
14
web_view.py
|
@ -117,6 +117,15 @@ def travel_list() -> str:
|
|||
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)
|
||||
|
||||
|
||||
|
@ -300,7 +309,6 @@ def human_readable_delta(future_date: date) -> str | None:
|
|||
@app.route("/trip/<start>")
|
||||
def trip_page(start: str) -> str:
|
||||
"""Individual trip page."""
|
||||
|
||||
trip_list = [
|
||||
trip
|
||||
for trip in agenda.trip.build_trip_list()
|
||||
|
@ -341,7 +349,9 @@ def trip_page(start: str) -> str:
|
|||
|
||||
for route in routes:
|
||||
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:
|
||||
countries = {c.alpha_2 for c in trip.countries}
|
||||
|
|
Loading…
Reference in a new issue