Ekaropolus 96fed7c45e
Some checks reported errors
continuous-integration/drone/push Build was killed
Waste management dashboar
2025-05-18 02:25:46 -06:00

121 lines
4.1 KiB
Python

import osmnx as ox
import shapely
import random
import uuid
import networkx as nx
from matplotlib import cm
def generate_osm_city_data(lat, lon, dist=400, scale=1.0):
print(f"🏙️ Fetching OSM buildings and network at ({lat}, {lon})")
scale_factor = scale
status_options = ["OK", "Warning", "Critical", "Offline"]
# ————— STREET NETWORK —————
G = ox.graph_from_point((lat, lon), dist=dist, network_type='drive').to_undirected()
degree = dict(G.degree())
max_degree = max(degree.values()) if degree else 1
color_map = cm.get_cmap("plasma")
# ————— BUILDINGS —————
tags = {"building": True}
gdf = ox.features_from_point((lat, lon), tags=tags, dist=dist)
gdf = gdf[gdf.geometry.type.isin(["Polygon", "MultiPolygon"])].to_crs(epsg=3857)
gdf["centroid"] = gdf.geometry.centroid
raw_buildings = []
for i, row in gdf.iterrows():
centroid = row["centroid"]
polygon = row["geometry"]
building_id = f"BLD-{uuid.uuid4().hex[:6].upper()}"
status = random.choice(status_options)
try:
height = float(row.get("height", None))
except:
height = float(row.get("building:levels", 3)) * 3.2 if row.get("building:levels") else 10.0
try:
node = ox.distance.nearest_nodes(G, X=centroid.x, Y=centroid.y)
node_degree = degree.get(node, 0)
except:
node_degree = 0
norm_value = node_degree / max_degree
rgba = color_map(norm_value)
hex_color = '#%02x%02x%02x' % tuple(int(c * 255) for c in rgba[:3])
raw_buildings.append({
"id": building_id,
"raw_x": centroid.x,
"raw_z": centroid.y,
"width": polygon.bounds[2] - polygon.bounds[0],
"depth": polygon.bounds[3] - polygon.bounds[1],
"height": height,
"color": hex_color,
"status": status,
})
# ————— CENTER AND SCALE —————
if raw_buildings:
avg_x = sum(b['raw_x'] for b in raw_buildings) / len(raw_buildings)
avg_z = sum(b['raw_z'] for b in raw_buildings) / len(raw_buildings)
buildings = [{
"id": b['id'],
"position_x": (b['raw_x'] - avg_x) * scale_factor,
"position_z": (b['raw_z'] - avg_z) * scale_factor,
"width": b['width'] * scale_factor,
"depth": b['depth'] * scale_factor,
"height": b['height'] * scale_factor,
"color": b['color'],
"status": b['status'],
} for b in raw_buildings]
else:
buildings = []
return {"buildings": buildings}
def generate_osm_road_midpoints_only(lat, lon, dist=400, scale=1.0):
import osmnx as ox
import networkx as nx
from shapely.geometry import LineString
import geopandas as gpd
import random
print(f"🛣️ Fetching road midpoints only at ({lat}, {lon})")
# Obtener grafo y convertir a GeoDataFrame con geometría
G = ox.graph_from_point((lat, lon), dist=dist, network_type='drive').to_undirected()
edge_gdf = ox.graph_to_gdfs(G, nodes=False, edges=True)
# Proyectar a metros (3857)
edge_gdf = edge_gdf.to_crs(epsg=3857)
midpoints_raw = []
for _, row in edge_gdf.iterrows():
geom = row.get('geometry', None)
if isinstance(geom, LineString) and geom.length > 0:
midpoint = geom.interpolate(0.5, normalized=True)
midpoints_raw.append((midpoint.x, midpoint.y))
if not midpoints_raw:
return {"roads": []}
avg_x = sum(x for x, _ in midpoints_raw) / len(midpoints_raw)
avg_z = sum(z for _, z in midpoints_raw) / len(midpoints_raw)
midpoints = [{
"id": f"RD-{i}",
"position_x": (x - avg_x) * scale,
"position_z": (z - avg_z) * scale,
"status": random.choice(["OK", "Warning", "Critical", "Offline"])
} for i, (x, z) in enumerate(midpoints_raw)]
# DEBUG
for i in range(min(5, len(midpoints))):
print(f"🧭 Road {i}: x={midpoints[i]['position_x']:.2f}, z={midpoints[i]['position_z']:.2f}")
return {"roads": midpoints}