Différences entre les versions de « Analyser un fichier GPX »
Aller à la navigation
Aller à la recherche
(Page créée avec « Cela consiste à analyser un fichier GPX d'un itinéraire pédestre, pour faire la part de ce qui est "motorisé" et de ce qui ne l'est pas, en fonction de la nature de la trace. Voici le code qui fait ça, à l'aide d'un serveur Flask, <pre> from flask import Flask, request, render_template, send_file import gpxpy import requests import folium from geopy.distance import geodesic import os app = Flask(__name__) def extract_coordinates_from_gpx(gpx_file):... ») |
|||
Ligne 149 : | Ligne 149 : | ||
</pre> | </pre> | ||
Avec un fichier index.html dans un sous-dossier template, | |||
<pre> | |||
<!DOCTYPE html> | |||
<html lang="en"> | |||
<head> | |||
<meta charset="UTF-8"> | |||
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |||
<title>GPX Visualizer</title> | |||
</head> | |||
<body> | |||
<h1>GPX Trace Visualizer</h1> | |||
<form action="/" method="POST" enctype="multipart/form-data"> | |||
<label for="file">Upload GPX File:</label> | |||
<input type="file" name="file" id="file" accept=".gpx"> | |||
<button type="submit">Upload and Visualize</button> | |||
</form> | |||
</body> | |||
</html> | |||
</pre> | |||
et un fichier |
Version du 15 janvier 2025 à 18:30
Cela consiste à analyser un fichier GPX d'un itinéraire pédestre, pour faire la part de ce qui est "motorisé" et de ce qui ne l'est pas, en fonction de la nature de la trace.
Voici le code qui fait ça, à l'aide d'un serveur Flask,
from flask import Flask, request, render_template, send_file import gpxpy import requests import folium from geopy.distance import geodesic import os app = Flask(__name__) def extract_coordinates_from_gpx(gpx_file): coordinates = [] with open(gpx_file, 'r') as file: gpx = gpxpy.parse(file) for track in gpx.tracks: for segment in track.segments: for point in segment.points: coordinates.append((point.latitude, point.longitude)) return coordinates def sample_points(coordinates, sample_rate=5): return coordinates[::sample_rate] def get_road_nature(coordinate): overpass_url = "http://overpass-api.de/api/interpreter" overpass_query = f""" [out:json]; (way(around:1,{coordinate[0]},{coordinate[1]});); out body; """ response = requests.get(overpass_url, params={'data': overpass_query}) if response.status_code != 200: return None data = response.json() motorized_highways = ['motorway', 'trunk', 'primary', 'secondary', 'tertiary', 'residential', 'unclassified'] for element in data.get('elements', []): if 'tags' in element and 'highway' in element['tags']: highway_type = element['tags']['highway'] print(f"Highway type : {highway_type} ") if highway_type in motorized_highways: return "motorized" return "foot" def distance_between_points(p1, p2): return geodesic(p1, p2).meters def split_into_homogeneous_segments(coordinates): """ Divise l'itinéraire en segments homogènes tout en calculant leur longueur. :param coordinates: Liste des coordonnées [(lat, lon), ...] :param min_distance: Distance minimale (en mètres) pour considérer un changement de nature :return: Liste des segments homogènes sous forme de tuples (segment, longueur), et les distances totales pour foot et motorized """ segments = [] # Liste des segments, chaque segment est un tuple (points, longueur) current_segment = [coordinates[0]] # Le premier point commence un segment current_length = 0 # Longueur cumulée du segment actuel current_nature = get_road_nature(coordinates[0]) # Nature de la route pour le premier point total_foot = 0 total_motorized = 0 for i in range(1, len(coordinates)): nature = get_road_nature(coordinates[i]) distance = distance_between_points(coordinates[i-1], coordinates[i]) if nature == current_nature: current_segment.append(coordinates[i]) current_length += distance # Ajouter la distance au segment actuel else: # Ajouter le segment terminé avec sa longueur segments.append((current_segment, current_length)) if current_nature == "foot": total_foot += current_length else: total_motorized += current_length # Commencer un nouveau segment current_segment = [coordinates[i]] current_length = distance # Réinitialiser la longueur pour le nouveau segment current_nature = nature # Ajouter le dernier segment if current_segment: segments.append((current_segment, current_length)) if current_nature == "foot": total_foot += current_length else: total_motorized += current_length return segments, total_foot, total_motorized def plot_on_map(gpx_file, sample_rate=5): """ Visualise la trace GPX sur une carte avec des waypoints à chaque changement de section homogène. Affiche également la longueur de chaque segment homogène. """ coordinates = extract_coordinates_from_gpx(gpx_file) sampled_coordinates = sample_points(coordinates, sample_rate) homogeneous_segments, total_foot, total_motorized = split_into_homogeneous_segments(sampled_coordinates) map_center = sampled_coordinates[0] map_ = folium.Map(location=map_center, zoom_start=14) # Ajouter la trace complète folium.PolyLine(coordinates, color="blue", weight=2.5, opacity=1).add_to(map_) # Ajouter des waypoints et afficher les longueurs des segments homogènes for segment, length in homogeneous_segments: start = segment[0] end = segment[-1] nature = get_road_nature(start) folium.Marker(location=start, popup=f"Start: {nature}").add_to(map_) folium.Marker(location=end, popup=f"End: {nature}, Length: {length:.2f}m").add_to(map_) # Ajouter les totaux dans un coin de la carte total_info = f"Total foot: {total_foot:.2f} meters<br>Total motorized: {total_motorized:.2f} meters" folium.Marker( location=map_center, popup=total_info, icon=folium.Icon(color="green", icon="info-sign") ).add_to(map_) return map_ @app.route("/", methods=["GET", "POST"]) def index(): if request.method == "POST": if 'file' not in request.files: return "No file uploaded", 400 file = request.files['file'] if file.filename == '': return "No selected file", 400 if not file.filename.endswith('.gpx'): return "Invalid file type. Please upload a GPX file.", 400 file_path = os.path.join("uploads", file.filename) file.save(file_path) map_ = plot_on_map(file_path) map_file = "templates/map.html" map_.save(map_file) return render_template("map.html") return render_template("index.html") if __name__ == "__main__": os.makedirs("uploads", exist_ok=True) app.run(debug=True)
Avec un fichier index.html dans un sous-dossier template,
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>GPX Visualizer</title> </head> <body> <h1>GPX Trace Visualizer</h1> <form action="/" method="POST" enctype="multipart/form-data"> <label for="file">Upload GPX File:</label> <input type="file" name="file" id="file" accept=".gpx"> <button type="submit">Upload and Visualize</button> </form> </body> </html>
et un fichier