diff options
| author | Daniel Schadt <kingdread@gmx.de> | 2026-09-28 23:09:01 +0200 |
|---|---|---|
| committer | Daniel Schadt <kingdread@gmx.de> | 2026-09-28 23:09:01 +0200 |
| commit | 6258b36bab2044f802cb89f244fca388bad27987 (patch) | |
| tree | 964fbe482d1dc6015412d241bcb2c02e9addf7e4 | |
| parent | 49c1309ebbbd059fec68bfaee74aba50f60ea34b (diff) | |
| download | fietsboek-6258b36bab2044f802cb89f244fca388bad27987.tar.gz fietsboek-6258b36bab2044f802cb89f244fca388bad27987.tar.bz2 fietsboek-6258b36bab2044f802cb89f244fca388bad27987.zip | |
implement climb extraction actionclimbs
| -rw-r--r-- | fietsboek/actions.py | 72 |
1 files changed, 70 insertions, 2 deletions
diff --git a/fietsboek/actions.py b/fietsboek/actions.py index cdddaa2..bcde0e4 100644 --- a/fietsboek/actions.py +++ b/fietsboek/actions.py @@ -7,6 +7,7 @@ the test functions. """ import datetime +import gzip import io import logging import re @@ -17,11 +18,12 @@ from pyramid.request import Request from sqlalchemy import select from sqlalchemy.orm.session import Session -from . import convert, email, models, trackmap +from . import convert, email, models, osm, trackmap from . import transformers as mod_transformers from . import util from .config import TileLayerConfig from .data import DataManager, TrackDataDir +from .geo import Path from .models.track import TrackType, Visibility from .models.user import TokenType from .views.tileproxy import TileRequester @@ -278,4 +280,70 @@ def send_verification_token(request: Request, user: models.User): ) -__all__ = ["add_track", "edit_images", "execute_transformers", "send_verification_token"] +def _categorize_climb(length: float, avg_grade: float) -> int | None: + # https://bicycles.stackexchange.com/questions/1210/how-are-the-categories-for-climbs-decided + score = length * avg_grade * 100 + if score > 80000: + return 0 + if score > 64000: + return 1 + if score > 32000: + return 2 + if score > 16000: + return 3 + if score > 8000: + return 4 + # You call this a climb?... + return None + + +def extract_climbs( + dbsession: Session, + track: models.Track, + tile_requester: TileRequester, + layer: TileLayerConfig, +): + """(Re-)extracts the climbs from the given track. + + If the track already has climbs assigned, they will be deleted. + + :param dbsession: The database session. + :param track: The track for which to extract climbs. + """ + track.climbs = [] + dbsession.add(track) + path = track.path() + climbs = path.climbs() + for climb_start, climb_end in climbs: + subpath = Path(path.points[climb_start:climb_end]) + movement_data = subpath.movement_data() + + preview = trackmap.render(subpath, layer, tile_requester) + imageio = io.BytesIO() + preview.save(imageio, "png") + preview = imageio.getvalue() + + profile = trackmap.height_profile(subpath, (300, 150)) + profile_compressed = gzip.compress(profile.encode("ascii")) + + avg_grade = movement_data.elevation_gain / movement_data.length + + name = osm.find_name(subpath) + + climb = models.Climb( + track=track, + start_index=climb_start, + end_index=climb_end, + image=preview, + profile=profile_compressed, + avg_grade=avg_grade, + length=movement_data.length, + lowest_elevation=movement_data.min_elevation, + highest_elevation=movement_data.max_elevation, + category=_categorize_climb(movement_data.length, avg_grade), + automatic_name=name, + ) + dbsession.add(climb) + + +__all__ = ["add_track", "edit_images", "execute_transformers", "send_verification_token", "extract_climbs"] |
