Add train route distance info
This commit is contained in:
		
							parent
							
								
									5964899a00
								
							
						
					
					
						commit
						8ef67e0cee
					
				| 
						 | 
					@ -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
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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 %}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										14
									
								
								web_view.py
									
									
									
									
									
								
							
							
						
						
									
										14
									
								
								web_view.py
									
									
									
									
									
								
							| 
						 | 
					@ -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}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue