mirror of
https://forge.chapril.org/tykayn/parking-land
synced 2025-06-20 01:44:42 +02:00
generate map with folium
This commit is contained in:
parent
2399302e4e
commit
8cb321a9c8
23 changed files with 115808 additions and 80 deletions
335
simple_map.py
Normal file
335
simple_map.py
Normal file
|
@ -0,0 +1,335 @@
|
|||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
Script très simplifié pour générer une carte d'une ville à partir de son ID OpenStreetMap.
|
||||
Utilise directement l'API Overpass et Folium pour créer une carte HTML.
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import argparse
|
||||
import requests
|
||||
import folium
|
||||
import json
|
||||
from datetime import datetime
|
||||
|
||||
def get_osm_data(osm_id, element_type="relation"):
|
||||
"""
|
||||
Récupère les données OpenStreetMap pour un élément donné.
|
||||
|
||||
Args:
|
||||
osm_id (int): L'identifiant OpenStreetMap
|
||||
element_type (str): Le type d'élément ('relation', 'way', 'node')
|
||||
|
||||
Returns:
|
||||
dict: Les données récupérées ou None en cas d'erreur
|
||||
"""
|
||||
print(f"Récupération des données pour {element_type}/{osm_id}...")
|
||||
|
||||
# Construire la requête Overpass
|
||||
if element_type == "relation":
|
||||
query = f"""
|
||||
[out:json];
|
||||
relation({osm_id});
|
||||
out body;
|
||||
>;
|
||||
out skel qt;
|
||||
"""
|
||||
elif element_type == "way":
|
||||
query = f"""
|
||||
[out:json];
|
||||
way({osm_id});
|
||||
out body;
|
||||
>;
|
||||
out skel qt;
|
||||
"""
|
||||
elif element_type == "node":
|
||||
query = f"""
|
||||
[out:json];
|
||||
node({osm_id});
|
||||
out body;
|
||||
"""
|
||||
else:
|
||||
print(f"Type d'élément non reconnu: {element_type}")
|
||||
return None
|
||||
|
||||
# Envoyer la requête à l'API Overpass
|
||||
try:
|
||||
overpass_url = "https://overpass-api.de/api/interpreter"
|
||||
response = requests.post(overpass_url, data={"data": query})
|
||||
|
||||
if response.status_code != 200:
|
||||
print(f"Erreur lors de la requête Overpass: {response.status_code}")
|
||||
return None
|
||||
|
||||
data = response.json()
|
||||
|
||||
if not data.get('elements'):
|
||||
print(f"Aucune donnée trouvée pour {element_type}/{osm_id}")
|
||||
return None
|
||||
|
||||
return data
|
||||
|
||||
except Exception as e:
|
||||
print(f"Erreur lors de la récupération des données: {str(e)}")
|
||||
return None
|
||||
|
||||
def get_bbox_from_data(data):
|
||||
"""
|
||||
Calcule la boîte englobante à partir des données OSM.
|
||||
|
||||
Args:
|
||||
data (dict): Les données OSM
|
||||
|
||||
Returns:
|
||||
tuple: (min_lat, min_lon, max_lat, max_lon) ou None
|
||||
"""
|
||||
try:
|
||||
nodes = [e for e in data['elements'] if e.get('type') == 'node']
|
||||
if not nodes:
|
||||
print("Aucun nœud trouvé dans les données")
|
||||
return None
|
||||
|
||||
lats = [n.get('lat', 0) for n in nodes if 'lat' in n]
|
||||
lons = [n.get('lon', 0) for n in nodes if 'lon' in n]
|
||||
|
||||
if not lats or not lons:
|
||||
print("Coordonnées manquantes dans les données")
|
||||
return None
|
||||
|
||||
min_lat, max_lat = min(lats), max(lats)
|
||||
min_lon, max_lon = min(lons), max(lons)
|
||||
|
||||
return (min_lat, min_lon, max_lat, max_lon)
|
||||
|
||||
except Exception as e:
|
||||
print(f"Erreur lors du calcul de la boîte englobante: {str(e)}")
|
||||
return None
|
||||
|
||||
def get_elements_in_bbox(bbox):
|
||||
"""
|
||||
Récupère les routes, bâtiments et parkings dans une boîte englobante.
|
||||
|
||||
Args:
|
||||
bbox (tuple): (min_lat, min_lon, max_lat, max_lon)
|
||||
|
||||
Returns:
|
||||
dict: Les données récupérées ou None en cas d'erreur
|
||||
"""
|
||||
print(f"Récupération des éléments dans la zone...")
|
||||
|
||||
# Construire la requête Overpass
|
||||
query = f"""
|
||||
[out:json];
|
||||
(
|
||||
way[highway]({bbox[0]},{bbox[1]},{bbox[2]},{bbox[3]});
|
||||
way[building]({bbox[0]},{bbox[1]},{bbox[2]},{bbox[3]});
|
||||
way[amenity=parking]({bbox[0]},{bbox[1]},{bbox[2]},{bbox[3]});
|
||||
);
|
||||
out body;
|
||||
>;
|
||||
out skel qt;
|
||||
"""
|
||||
|
||||
# Envoyer la requête à l'API Overpass
|
||||
try:
|
||||
overpass_url = "https://overpass-api.de/api/interpreter"
|
||||
response = requests.post(overpass_url, data={"data": query})
|
||||
|
||||
if response.status_code != 200:
|
||||
print(f"Erreur lors de la requête Overpass: {response.status_code}")
|
||||
return None
|
||||
|
||||
data = response.json()
|
||||
|
||||
if not data.get('elements'):
|
||||
print("Aucun élément trouvé dans la zone")
|
||||
return None
|
||||
|
||||
return data
|
||||
|
||||
except Exception as e:
|
||||
print(f"Erreur lors de la récupération des éléments: {str(e)}")
|
||||
return None
|
||||
|
||||
def create_map(osm_id, output_path=None):
|
||||
"""
|
||||
Crée une carte pour un élément OpenStreetMap.
|
||||
|
||||
Args:
|
||||
osm_id (int): L'identifiant OpenStreetMap
|
||||
output_path (str): Chemin où sauvegarder la carte HTML
|
||||
|
||||
Returns:
|
||||
str: Chemin vers le fichier HTML généré ou None en cas d'erreur
|
||||
"""
|
||||
# Essayer d'abord en tant que relation
|
||||
data = get_osm_data(osm_id, "relation")
|
||||
element_type = "relation"
|
||||
|
||||
# Si ça ne fonctionne pas, essayer en tant que way
|
||||
if not data:
|
||||
print("Essai en tant que chemin (way)...")
|
||||
data = get_osm_data(osm_id, "way")
|
||||
element_type = "way"
|
||||
|
||||
# Si ça ne fonctionne toujours pas, essayer en tant que node
|
||||
if not data:
|
||||
print("Essai en tant que nœud (node)...")
|
||||
data = get_osm_data(osm_id, "node")
|
||||
element_type = "node"
|
||||
|
||||
# Si aucune méthode ne fonctionne
|
||||
if not data:
|
||||
print(f"Impossible de récupérer les données pour l'ID OSM: {osm_id}")
|
||||
return None
|
||||
|
||||
# Extraire les informations de base
|
||||
element_info = next((e for e in data['elements'] if e.get('id') == osm_id), None)
|
||||
if not element_info:
|
||||
print(f"Élément non trouvé dans les données")
|
||||
return None
|
||||
|
||||
# Récupérer le nom
|
||||
name = element_info.get('tags', {}).get('name', f"Lieu_{osm_id}")
|
||||
print(f"Lieu identifié: {name}")
|
||||
|
||||
# Calculer la boîte englobante
|
||||
bbox = get_bbox_from_data(data)
|
||||
if not bbox:
|
||||
print("Impossible de calculer la boîte englobante")
|
||||
return None
|
||||
|
||||
# Récupérer les éléments dans la zone
|
||||
elements_data = get_elements_in_bbox(bbox)
|
||||
if not elements_data:
|
||||
print("Impossible de récupérer les éléments dans la zone")
|
||||
return None
|
||||
|
||||
# Calculer le centre de la carte
|
||||
center_lat = (bbox[0] + bbox[2]) / 2
|
||||
center_lon = (bbox[1] + bbox[3]) / 2
|
||||
center = (center_lat, center_lon)
|
||||
|
||||
# Créer la carte
|
||||
print("Création de la carte...")
|
||||
m = folium.Map(location=center, zoom_start=14, tiles='OpenStreetMap')
|
||||
|
||||
# Ajouter un titre
|
||||
title_html = f'''
|
||||
<h3 align="center" style="font-size:16px"><b>Carte de {name}</b></h3>
|
||||
<p align="center" style="font-size:12px">ID OpenStreetMap: {osm_id} (Type: {element_type})</p>
|
||||
'''
|
||||
m.get_root().html.add_child(folium.Element(title_html))
|
||||
|
||||
# Ajouter un marqueur pour le centre
|
||||
folium.Marker(
|
||||
location=center,
|
||||
popup=f"Centre de {name}",
|
||||
icon=folium.Icon(color='red', icon='info-sign')
|
||||
).add_to(m)
|
||||
|
||||
# Extraire les nœuds pour construire les géométries
|
||||
nodes = {n['id']: (n['lat'], n['lon']) for n in elements_data['elements'] if n['type'] == 'node'}
|
||||
|
||||
# Compter les éléments pour les statistiques
|
||||
highways_count = 0
|
||||
buildings_count = 0
|
||||
parkings_count = 0
|
||||
|
||||
# Traiter les routes, bâtiments et parkings
|
||||
for element in elements_data['elements']:
|
||||
if element['type'] == 'way' and 'tags' in element:
|
||||
# Récupérer les coordonnées des nœuds
|
||||
coords = []
|
||||
for node_id in element['nodes']:
|
||||
if node_id in nodes:
|
||||
coords.append(nodes[node_id])
|
||||
|
||||
if not coords:
|
||||
continue
|
||||
|
||||
# Déterminer le type d'élément
|
||||
if 'highway' in element['tags']:
|
||||
# C'est une route
|
||||
highways_count += 1
|
||||
folium.PolyLine(
|
||||
coords,
|
||||
color='#555555',
|
||||
weight=2,
|
||||
opacity=0.7,
|
||||
tooltip=element['tags'].get('name', 'Route')
|
||||
).add_to(m)
|
||||
|
||||
elif 'building' in element['tags']:
|
||||
# C'est un bâtiment
|
||||
buildings_count += 1
|
||||
folium.Polygon(
|
||||
coords,
|
||||
color='#777777',
|
||||
fill=True,
|
||||
fill_color='#777777',
|
||||
fill_opacity=0.7,
|
||||
tooltip=element['tags'].get('name', 'Bâtiment')
|
||||
).add_to(m)
|
||||
|
||||
elif element['tags'].get('amenity') == 'parking':
|
||||
# C'est un parking
|
||||
parkings_count += 1
|
||||
folium.Polygon(
|
||||
coords,
|
||||
color='#999999',
|
||||
fill=True,
|
||||
fill_color='#999999',
|
||||
fill_opacity=0.7,
|
||||
tooltip=element['tags'].get('name', 'Parking')
|
||||
).add_to(m)
|
||||
|
||||
# Ajouter une légende avec les statistiques
|
||||
legend_html = f'''
|
||||
<div style="position: fixed;
|
||||
bottom: 50px; right: 50px; width: 200px; height: 130px;
|
||||
border:2px solid grey; z-index:9999; font-size:12px;
|
||||
background-color: white; padding: 10px;
|
||||
border-radius: 5px;">
|
||||
<p><b>Statistiques</b></p>
|
||||
<p>Routes: {highways_count}</p>
|
||||
<p>Bâtiments: {buildings_count}</p>
|
||||
<p>Parkings: {parkings_count}</p>
|
||||
</div>
|
||||
'''
|
||||
m.get_root().html.add_child(folium.Element(legend_html))
|
||||
|
||||
# Définir le chemin de sortie
|
||||
if not output_path:
|
||||
output_path = f"{name.replace(' ', '_')}_map.html"
|
||||
elif not output_path.lower().endswith('.html'):
|
||||
output_path = f"{os.path.splitext(output_path)[0]}.html"
|
||||
|
||||
# Sauvegarder la carte
|
||||
print(f"Sauvegarde de la carte dans: {output_path}")
|
||||
m.save(output_path)
|
||||
|
||||
print(f"Carte générée avec succès: {output_path}")
|
||||
print(f"Pour visualiser la carte, ouvrez le fichier HTML dans un navigateur web:")
|
||||
print(f" file://{os.path.abspath(output_path)}")
|
||||
|
||||
return output_path
|
||||
|
||||
def main():
|
||||
"""
|
||||
Fonction principale qui traite les arguments de ligne de commande
|
||||
et génère la carte.
|
||||
"""
|
||||
parser = argparse.ArgumentParser(description='Génère une carte pour un élément OpenStreetMap.')
|
||||
parser.add_argument('osm_id', type=int, help='ID OpenStreetMap')
|
||||
parser.add_argument('-o', '--output', type=str, help='Chemin où sauvegarder la carte HTML')
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
# Créer la carte
|
||||
create_map(args.osm_id, args.output)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
Loading…
Add table
Add a link
Reference in a new issue