From 8e62e2b44003c4198b8597f4399eafa90f290229 Mon Sep 17 00:00:00 2001 From: Alex Date: Thu, 24 Sep 2026 23:41:24 +0200 Subject: [PATCH] =?UTF-8?q?Compteur=20=C3=A0=200=20si=20la=20trace=20ne=20?= =?UTF-8?q?bouge=20pas?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- gpx_video.py | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 77daf49..1796ea2 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ ## Fonctionnalités - Lecture GPX 1.0 / 1.1 (points `trkpt` horodatés). -- Vitesse issue de l'extension `gpxtpx:speed` (m/s, ex. GeoRide) si présente, sinon calculée à partir des distances et des temps ; lissage léger. +- Vitesse issue de l'extension `gpxtpx:speed` (m/s, ex. GeoRide) si présente, sinon calculée à partir des distances et des temps ; lissage léger. Aux arrêts (trace immobile, moins de 3 km/h en moyenne entre deux points), le compteur retombe à 0, même si le GPS n'a enregistré aucun point pendant la pause. - Vidéo accélérée à durée fixe (60 s par défaut) : le trajet complet est parcouru du début à la fin. - Compteur analogique 0-200 km/h (paramétrable), aiguille et vitesse numérique, placé automatiquement dans le coin le moins encombré par la trace ; l'aiguille part de 0 et y revient sur la première et la dernière seconde. - Villes traversées obtenues par géocodage inverse [Nominatim](https://nominatim.org/) (OpenStreetMap), affichées sur la carte dès le début, avec placement des étiquettes qui évite chevauchements et trace. diff --git a/gpx_video.py b/gpx_video.py index fd306d8..fb881a0 100644 --- a/gpx_video.py +++ b/gpx_video.py @@ -43,6 +43,8 @@ CLES_VILLE = ("city", "town", "village", "municipality", "hamlet") LARGEUR_ZOOM = TAILLE // 2 # largeur du nom de ville zoomé HAUTEUR_ZOOM_MAX = TAILLE // 4 # limite pour les noms très courts FONDU_ZOOM = 0.3 # durée des fondus d'apparition/disparition (s de vidéo) +SEUIL_ARRET_KMH = 3 # sous cette vitesse moyenne, un segment est un arrêt +TRANSITION_ARRET = 1.0 # durée (s de trajet) du retour de l'aiguille à 0 BLANC = (255, 255, 255) GRIS = (170, 170, 170) @@ -115,6 +117,36 @@ def calculer_vitesses(lat, lon, t, v_gpx): return np.clip(lisse, 0, None) +def annuler_arrets(lat, lon, t, v): + """Met la vitesse à 0 pendant les arrêts (trace immobile). + + Un segment est immobile si sa vitesse moyenne (distance/durée) est sous + SEUIL_ARRET_KMH. Le GPS enregistre souvent peu ou pas de points à + l'arrêt : sans correction, l'aiguille resterait figée sur la vitesse des + points encadrant la pause. Des points à vitesse nulle sont donc insérés + au début et à la fin de chaque segment immobile long. + """ + d = distances_haversine(lat, lon) + dt = np.diff(t) + immobile = d < SEUIL_ARRET_KMH / 3.6 * dt + v = v.copy() + # Point entouré de segments immobiles (ou en bout de trace) : à l'arrêt. + avant = np.concatenate([[True], immobile]) + apres = np.concatenate([immobile, [True]]) + v[avant & apres] = 0.0 + + longs = np.flatnonzero(immobile & (dt > 2 * TRANSITION_ARRET)) + if len(longs) == 0: + return lat, lon, t, v + t_ajout = np.concatenate([t[longs] + TRANSITION_ARRET, t[longs + 1] - TRANSITION_ARRET]) + t2 = np.concatenate([t, t_ajout]) + lat2 = np.concatenate([lat, np.interp(t_ajout, t, lat)]) + lon2 = np.concatenate([lon, np.interp(t_ajout, t, lon)]) + v2 = np.concatenate([v, np.zeros(len(t_ajout))]) + ordre = np.argsort(t2, kind="stable") + return lat2[ordre], lon2[ordre], t2[ordre], v2[ordre] + + # -------------------------------------------------------------------------- # Villes (Nominatim) # -------------------------------------------------------------------------- @@ -373,6 +405,7 @@ def extraire_morceau(lat, lon, t, vitesse, t0, t1): def generer_video(args): lat, lon, t, v_gpx = charger_gpx(args.gpx) vitesse = calculer_vitesses(lat, lon, t, v_gpx) + lat, lon, t, vitesse = annuler_arrets(lat, lon, t, vitesse) print(f"{len(lat)} points, durée {t[-1] / 60:.1f} min, vitesse max {vitesse.max():.0f} km/h") villes = [] if args.sans_villes else trouver_villes(args.gpx, lat, lon)