parking-land/compute.py
2025-03-16 16:26:58 +01:00

389 lines
No EOL
17 KiB
Python
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import os
import requests
import json
import math
from shapely.geometry import Polygon
import argparse
import matplotlib.pyplot as plt
# Configuration
OVERPASS_API = "https://overpass-api.de/api/interpreter"
# Configuration des arguments de ligne de commande
parser = argparse.ArgumentParser(description="Calculer les parkings et la surface d'une ville.")
parser.add_argument("--city", type=str, default="Limours", help="Nom de la ville (défaut: Limours)")
parser.add_argument("--osm-id", type=str, default="3601176343", help="Identifiant OpenStreetMap de la ville (défaut: 3601176343 pour Limours)")
args = parser.parse_args()
CITY_NAME = args.city
# limours: 3601176343
# briis-sous-forges: 3601209165
city_overpass_id = args.osm_id
COUNTRY_NAME = "France"
# estimations des tailles de parking en m carré selon le placement
PARKING_SIZE_ESTIMATE = {
"bike":2,
"surface": 20,
"multilevel": 25,
"underground": 30,
"pmr": 40
}
DEGREES_TO_METERS = 111312
def estimate_road_length_and_surface(city_name):
# Vérifier si le fichier JSON existe
if not os.path.exists('overpass_data.json'):
print("Le fichier overpass_data.json n'existe pas. Veuillez d'abord exécuter fetch.py.")
return None
# Charger les données depuis le fichier JSON
with open('overpass_data.json', 'r') as file:
data = json.load(file)
parking_area = 0
bicycle_parking_area = 0
bicycle_parking_capacity_provided = 0
car_parking_capacity_provided = 0
charging_stations = 0
charging_points = 0
parking_with_capacity_count = 0 # Compteur pour les parkings avec capacité renseignée
road_length = 0
roundabout_count = 0
mini_roundabout_count = 0
road_cycleway_length = 0
road_surface = 0
cycleway_count = 0
building_count = 0
building_area = 0
building_sizes = [0, 10, 50, 100, 200, 500, float('inf')]
building_size_counts = [0, 0, 0, 0, 0, 0, 0]
charging_stations_with_capacity_count = 0
charging_stations_capacity_provided = 0
for element in data["elements"]:
if "tags" in element and "building" in element["tags"]:
if "geometry" in element:
polygon = Polygon([(point['lon'], point['lat']) for point in element["geometry"]])
area = polygon.area
for i, size in enumerate(building_sizes):
if area < size:
building_size_counts[i] += 1
break
print("Bâtiments de moins de 10 m²:", building_size_counts[0])
print("Bâtiments de 10 à 50 m²:", building_size_counts[1])
print("Bâtiments de 50 à 100 m²:", building_size_counts[2])
print("Bâtiments de 100 à 200 m²:", building_size_counts[3])
print("Bâtiments de 200 à 500 m²:", building_size_counts[4])
print("Bâtiments de plus de 500 m²:", building_size_counts[5])
print('éléments:', len(data["elements"]))
for element in data["elements"]:
two_points_distance = 0
element_road_length = 0
if "geometry" in element:
geometry = element["geometry"]
coordinates = geometry
if len(coordinates) > 1:
for i in range(len(coordinates) - 1):
# print(coordinates)
lon1 = coordinates[i]['lon']
lat1 = coordinates[i]['lat']
lon2 = coordinates[i + 1]['lon']
lat2 = coordinates[i + 1]['lat']
# print(lon1, lat1, lon2, lat2)
# Convertir les degrés de lat/lon en mètres
lon1_m, lat1_m = int(lon1 * DEGREES_TO_METERS), int(lat1 * DEGREES_TO_METERS)
lon2_m, lat2_m = int(lon2 * DEGREES_TO_METERS), int(lat2 * DEGREES_TO_METERS)
two_points_distance = math.sqrt((lon2_m - lon1_m)**2 + (lat2_m - lat1_m)**2)
# print(lon1_m, lat1_m, lon2_m, lat2_m)
# print('two_points_distance ', two_points_distance)
# break
element_road_length += two_points_distance
# Estimation de la surface des bâtiments
if "tags" in element and "building" in element["tags"]:
building_count += 1
if "geometry" in element:
polygon = Polygon([(point['lon'], point['lat']) for point in element["geometry"]])
building_area += polygon.area
if "tags" in element and "highway" in element["tags"] and element["tags"]["highway"] == "cycleway":
cycleway_count += 1
road_cycleway_length += two_points_distance
if "tags" in element and "highway" in element["tags"]:
if "lanes" in element["tags"]:
lane_width = 3.5 # Assuming 3.5m width per lane
road_width = int(element["tags"]["lanes"]) * lane_width * 2 # Double voie
else:
road_width = 7 # Default width for single lane roads
if element["tags"]["highway"] in ["motorway", "trunk", "primary", "secondary", "tertiary", "unclassified", "residential", "service"] and "length" in element:
road_length += element["length"]
road_surface += element["length"] * road_width
elif element["tags"]["highway"] == "roundabout":
roundabout_count += 1
road_length += math.pi * element["tags"]["circumference"]
road_surface += math.pi * element["tags"]["circumference"] * road_width
elif element["tags"]["highway"] == "mini_roundabout":
mini_roundabout_count += 1
if "tags" in element and "amenity" in element["tags"]:
if element["tags"]["amenity"] == "parking":
if "capacity" in element["tags"]:
parking_with_capacity_count += 1
# print('car parking capacity:', element["tags"]["capacity"])
car_parking_capacity_provided += int(element["tags"]["capacity"])
# Estimer la surface du parking à partir de la capacité
parking_area += PARKING_SIZE_ESTIMATE["surface"] * int(element["tags"]["capacity"])
elif "geometry" in element:
# Calculer la surface selon la forme du polygone
polygon = Polygon([(point['lon'], point['lat']) for point in element["geometry"]])
parking_area += polygon.area / 1_000_000 # Conversion en km²
elif element["tags"]["amenity"] == "bicycle_parking":
if "capacity" in element["tags"]:
parking_with_capacity_count += 1
bicycle_parking_capacity_provided += int(element["tags"]["capacity"])
bicycle_parking_area += PARKING_SIZE_ESTIMATE["bike"]
# stations de recharge
elif element["tags"]["amenity"] == "charging_station":
charging_stations += 1
if "capacity" in element["tags"]:
charging_stations_with_capacity_count += 1
charging_stations_capacity_provided += int(element["tags"]["capacity"])
elif "tags" in element and "man_made" in element["tags"] and element["tags"]["man_made"] == "charge_point":
charging_points += 1
# points de charge
road_length += element_road_length
road_length_km = road_length / 1000
road_surface_km2 = 3.5*2*road_length / 1000000 # Conversion de mètres carrés en kilomètres carrés
# road_surface = 3.5*2*road_length / 1000
# compter la surface des buildings
# comparer la surface des buildings par rapport à la surface totale de la ville
# -----------------
# estimer la surface prise par les parkings voiture, compter selon les capacity renseignées, et selon les surfaces des polygones geojson
# compter les places de parking par habitant
# -----------------
# infos vélo:
# estimer les km de piste cyclable
# estimer la surface prise par les parkings vélo
# compter les places de parking vélo, amenity=bicycle_parking
# compter les parking vélo par habitant
return {
"longueur_route_km": road_length_km,
"road_cycleway_km": road_cycleway_length/1000,
"compte_highways": len(data["elements"]),
"surface_route_km2": road_surface_km2,
"building_count" : building_count,
"building_area" : building_area/1000,
"building_sizes" : building_sizes,
"building_size_counts" : building_size_counts,
"compte_piste_cyclable": cycleway_count,
"car_parking_capacity_provided" : car_parking_capacity_provided,
"roundabout_count":roundabout_count,
"mini_roundabout_count":mini_roundabout_count,
"surface_parking_km2": parking_area, # Surface totale des parkings en km²
"surface_bicycle_parking_km2": bicycle_parking_area / 1_000_000, # Conversion en km²
"parking_with_capacity_count": parking_with_capacity_count, # Nombre de parkings avec capacité renseignée
"capacity_bicycle_parking_provided": bicycle_parking_capacity_provided,
"bicycle_parking_surface_from_capacity_provided_in_m2" : bicycle_parking_capacity_provided * 2,
"charging_stations" : charging_stations,
"charging_stations_with_capacity_count" : charging_stations_with_capacity_count,
"charging_stations_capacity_provided" : charging_stations_capacity_provided,
"charging_points" : charging_points,
}
def get_osm_relation_id(city_name, country_name):
# Configuration pour Nominatim
NOMINATIM_API = "https://nominatim.openstreetmap.org/search"
NOMINATIM_QUERY = f"{city_name}, {country_name}"
# Requête HTTP pour trouver l'identifiant OSM de la ville
response = requests.get(NOMINATIM_API, params={
"format": "json",
"addressdetails": 1,
"q": NOMINATIM_QUERY
}, headers={"User-Agent": "MonApplication/1.0"}) # Ajout du User-Agent
# Vérification de la réponse
if response.status_code == 200:
data = response.json()
print('résultat de recherche nominatim', len(data))
# Trouver l'identifiant OSM de la relation correspondant à la ville
for result in data:
if "osm_id" in result:
return result["osm_id"]
else:
print(f"Échec de la recherche sur Nominatim. Code d'erreur: {response.status_code}")
return None
def get_city_boundary(city_name, country_name):
# Requête Overpass pour obtenir les limites de la ville
overpass_query__city_bounds = f"""[out:json][timeout:25];relation["name"="{city_name}"]["admin_level"="8"];(._;>;);out geom;
"""
response = requests.post(OVERPASS_API, data={"data": overpass_query__city_bounds}, headers={"X-Requested-With": "overpass-turbo"})
print(response.status_code)
if response.status_code == 200:
data = response.json()
# print("data response: ", data)
if data["elements"]:
for element in data["elements"]:
if "bounds" in element:
# print('bounds: ', element['bounds'])
return element['bounds']
else:
return None
else:
return None
def get_parking_areas(city_bounds):
overpass_query__parkings = '[out:json][timeout:25];area(id:3601176343)->.searchArea;nwr["amenity"="parking"](area.searchArea);out center;'
print('reqête pour les parkings: ', overpass_query__parkings)
response = requests.post(OVERPASS_API, data={"data": overpass_query__parkings})
if response.status_code != 200:
print(f"Échec de la requête Overpass. Code d'erreur: {response.status_code}")
return []
data = response.json()
with open(f'parkings_results_{CITY_NAME}.json', 'w') as file:
json.dump(data, file, ensure_ascii=False, indent=4)
return data["elements"]
def estimate_parking_surface(parking_areas):
total_surface = 0
parking_count = 0
# print('parkings: ', len(parking_areas))
for area in parking_areas:
if "tags" in area and "amenity" in area["tags"] and area["tags"]["amenity"] == "parking":
if "capacity" in area["tags"]:
# print('capacité du parking: ', area["tags"]["capacity"])
parking_count += int(area["tags"]["capacity"])
else:
parking_count += 1
if "parking" in area["tags"] and area["tags"]["parking"] in PARKING_SIZE_ESTIMATE:
total_surface += PARKING_SIZE_ESTIMATE[area["tags"]["parking"]]
else:
# Utilisation d'une valeur par défaut si le type de parking n'est pas spécifié
total_surface += PARKING_SIZE_ESTIMATE["surface"]
return total_surface, parking_count
def calculate_city_surface(city_bounds):
# Conversion des coordonnées en mètres carrés sans bibliothèque
lat_diff = city_bounds["maxlat"] - city_bounds["minlat"]
lon_diff = city_bounds["maxlon"] - city_bounds["minlon"]
# Approximation de la distance en mètres
meters_per_latitude = 111_000 # 1 degré de latitude ≈ 111 km
meters_per_longitude = 111_000 * math.cos(math.radians((city_bounds["maxlat"] + city_bounds["minlat"]) / 2)) # Ajustement pour la longitude
# Calcul de la largeur et de la hauteur en mètres
width = lon_diff * meters_per_longitude
height = lat_diff * meters_per_latitude
# Calcul de la surface en mètres carrés
city_surface_m2 = width * height
print("city_surface_m2", city_surface_m2)
return city_surface_m2 # Retourne l'aire en mètres carrés
def get_population():
wiki_api_url = f"https://fr.wikipedia.org/w/api.php?action=parse&page={CITY_NAME}&format=json"
response = requests.get(wiki_api_url)
data = response.json()
nombre_habitants = None
for line in data["parse"]["text"]["*"].splitlines():
if "Habitants" in line or "Population" in line:
nombre_habitants = int(line.split(":")[1].strip().replace(" ", ""))
break
return nombre_habitants
def draw_city_map(city_name, road_surface_km2, city_surface_km2):
# Dimensions de la carte
fig, ax = plt.subplots(figsize=(8, 8))
# Calcul de la longueur du côté du carré représentant la surface des routes
road_side_length = (road_surface_km2 * 1_000_000) ** 0.5 # Conversion de km² à m²
city_side_length = (city_surface_km2) ** 0.5 # La surface de la ville est déjà en m²
# Création d'un carré représentant la surface des routes
road_square = plt.Rectangle((0, 0), road_side_length, road_side_length, color='blue', alpha=0.5, label='Surface des routes')
# Création d'un carré représentant la surface de la ville
city_square = plt.Rectangle((road_side_length, 0), city_side_length, city_side_length, color='green', alpha=0.5, label='Surface de la ville')
# Ajout des carrés à la carte
ax.add_patch(road_square)
ax.add_patch(city_square)
# Configuration de la carte
ax.set_xlim(0, max(road_side_length, city_side_length) * 1.1) # Laisser un peu d'espace
ax.set_ylim(0, max(road_side_length, city_side_length) * 1.1)
ax.set_title(f"Comparaison de la surface de {city_name} - Routes vs Ville")
ax.set_xlabel("Longitude (m)")
ax.set_ylabel("Latitude (m)")
ax.legend()
# Sauvegarde de la carte en JPG
plt.savefig(f"{city_name}_city_map_comparison.jpg", format='jpg')
# plt.show()
def draw_bar_chart(city_name, road_surface_km2, city_surface_km2):
# Données pour le diagramme
labels = ['Surface des routes (km²)', 'Surface de la ville (km²)']
values = [road_surface_km2, city_surface_km2]
# Création du diagramme en barres
fig, ax = plt.subplots()
ax.bar(labels, values, color=['blue', 'green'], alpha=0.7)
# Configuration du diagramme
ax.set_title(f"Comparaison des surfaces à {city_name}")
ax.set_ylabel("Surface (km²)")
ax.set_ylim(0, max(values) * 1.1) # Ajuster l'axe y pour laisser un peu d'espace
# Sauvegarde du diagramme en JPG
plt.savefig(f"{city_name}_surface_comparison_bar_chart.jpg", format='jpg')
# plt.show()
def main():
# city_bounds = get_city_boundary(CITY_NAME, COUNTRY_NAME)
# city_surface_km2 = calculate_city_surface(city_bounds) / 1_000_000 # Conversion de m² à km²
city_surface_km2 = 10.86
resultats = estimate_road_length_and_surface(CITY_NAME)
print('résultats:', resultats)
# Sauvegarder les résultats dans summary_results.json
with open('summary_results.json', 'w') as summary_file:
json.dump(resultats, summary_file, ensure_ascii=False, indent=2)
road_surface_km2 = resultats["surface_route_km2"]
# draw_city_map(CITY_NAME, road_surface_km2, city_surface_km2)
draw_bar_chart(CITY_NAME, road_surface_km2, city_surface_km2) # Appel de la fonction pour le diagramme en barres
print(f"**Résultats pour {CITY_NAME}, {COUNTRY_NAME}**")
if __name__ == "__main__":
main()