156 lines
5.1 KiB
Python
156 lines
5.1 KiB
Python
import random
|
||
from .network import compute_mst_fiber_paths, compute_network_summary
|
||
|
||
GRID_SIZE = 5
|
||
SPACING = 15 # Distance between objects
|
||
|
||
|
||
def generate_com_con_city_data(lat, long):
|
||
"""
|
||
Generate a digital twin for a real-world city (e.g., Concepción).
|
||
Returns towers, fiber paths, wifi hotspots, and a summary.
|
||
"""
|
||
random.seed(f"{lat},{long}")
|
||
|
||
center_x = lat
|
||
center_z = long
|
||
|
||
towers = generate_towers(center_x, center_z)
|
||
fiber_paths = compute_mst_fiber_paths(towers)
|
||
wifi_hotspots = generate_wifi_hotspots(center_x, center_z)
|
||
summary = compute_network_summary(towers, fiber_paths, wifi_hotspots)
|
||
|
||
return {
|
||
'towers': towers,
|
||
'fiber_paths': fiber_paths,
|
||
'wifi_hotspots': wifi_hotspots,
|
||
'network_summary': summary,
|
||
}
|
||
|
||
def generate_towers(center_x, center_z, mode="streets"):
|
||
"""
|
||
Generate towers either in a 'grid' or at realistic 'streets' (mocked).
|
||
mode: "grid" | "streets"
|
||
"""
|
||
if mode == "streets":
|
||
return generate_street_corner_towers(center_x, center_z)
|
||
else:
|
||
return generate_grid_towers(center_x, center_z)
|
||
|
||
|
||
import osmnx as ox
|
||
|
||
def generate_street_corner_towers(center_x, center_z, min_towers=10):
|
||
"""
|
||
Get real intersections from OSM and convert them to local x/z positions
|
||
relative to center_x / center_z (in meters). Fallbacks to mocked layout if needed.
|
||
"""
|
||
print("📍 Starting generate_street_corner_towers()")
|
||
print(f"→ center_x: {center_x}, center_z: {center_z}")
|
||
|
||
point = (center_x, center_z)
|
||
print(f"→ Using real lat/lon: {point}")
|
||
|
||
try:
|
||
for dist in [100, 200, 500, 1000]:
|
||
print(f"🛰️ Trying OSM download at radius: {dist} meters...")
|
||
G = ox.graph_from_point(point, dist=dist, network_type='all')
|
||
G_undirected = G.to_undirected()
|
||
degrees = dict(G_undirected.degree())
|
||
intersections = [n for n, d in degrees.items() if d >= 3]
|
||
print(f" ✅ Found {len(intersections)} valid intersections.")
|
||
if len(intersections) >= min_towers:
|
||
break
|
||
else:
|
||
raise ValueError("No sufficient intersections found.")
|
||
|
||
nodes, _ = ox.graph_to_gdfs(G)
|
||
origin_lon = nodes.loc[intersections]['x'].mean()
|
||
origin_lat = nodes.loc[intersections]['y'].mean()
|
||
print(f"📌 Using origin_lon: {origin_lon:.6f}, origin_lat: {origin_lat:.6f} for local projection")
|
||
|
||
def latlon_to_sim(lon, lat):
|
||
dx = (lon - origin_lon) * 111320
|
||
dz = (lat - origin_lat) * 110540
|
||
return center_x + dx, center_z + dz
|
||
|
||
towers = []
|
||
for i, node_id in enumerate(intersections):
|
||
row = nodes.loc[node_id]
|
||
x_sim, z_sim = latlon_to_sim(row['x'], row['y'])
|
||
print(f" 🗼 Tower #{i+1} at sim position: x={x_sim:.2f}, z={z_sim:.2f}")
|
||
towers.append(make_tower(x_sim, z_sim, i + 1))
|
||
|
||
print(f"✅ Done. Total towers returned: {len(towers)}\n")
|
||
return towers
|
||
|
||
except Exception as e:
|
||
print(f"❌ OSM tower generation failed: {e}")
|
||
print("⚠️ Falling back to mocked tower layout.")
|
||
|
||
# Return 3x3 fixed grid as fallback
|
||
offsets = [(-30, -30), (-30, 0), (-30, 30),
|
||
(0, -30), (0, 0), (0, 30),
|
||
(30, -30), (30, 0), (30, 30)]
|
||
|
||
towers = []
|
||
for i, (dx, dz) in enumerate(offsets):
|
||
x = center_x + dx
|
||
z = center_z + dz
|
||
towers.append(make_tower(x, z, i + 1))
|
||
|
||
print(f"✅ Fallback returned {len(towers)} towers.\n")
|
||
return towers
|
||
|
||
|
||
def generate_grid_towers(center_x, center_z):
|
||
"""Generates a 5×5 grid of towers around the city center."""
|
||
towers = []
|
||
for i in range(GRID_SIZE):
|
||
for j in range(GRID_SIZE):
|
||
x = center_x + (i - GRID_SIZE // 2) * SPACING
|
||
z = center_z + (j - GRID_SIZE // 2) * SPACING
|
||
towers.append({
|
||
'id': len(towers) + 1,
|
||
'status': 'Active' if random.random() > 0.2 else 'Inactive',
|
||
'position_x': x,
|
||
'position_y': 0,
|
||
'position_z': z,
|
||
'height': random.randint(40, 60),
|
||
'range': random.randint(500, 1000),
|
||
'color': '#ff4500'
|
||
})
|
||
return towers
|
||
|
||
|
||
def generate_wifi_hotspots(center_x, center_z):
|
||
"""Places 10 Wi-Fi hotspots randomly around the city center."""
|
||
hotspots = []
|
||
bound = SPACING * GRID_SIZE / 2
|
||
for i in range(10):
|
||
x = center_x + random.uniform(-bound, bound)
|
||
z = center_z + random.uniform(-bound, bound)
|
||
hotspots.append({
|
||
'id': i + 1,
|
||
'position_x': x,
|
||
'position_y': 1.5,
|
||
'position_z': z,
|
||
'status': 'Online' if random.random() > 0.2 else 'Offline',
|
||
'radius': random.randint(1, 3),
|
||
'color': '#32cd32'
|
||
})
|
||
return hotspots
|
||
|
||
def make_tower(x, z, id):
|
||
return {
|
||
'id': id,
|
||
'status': 'Active',
|
||
'position_x': x,
|
||
'position_y': 0,
|
||
'position_z': z,
|
||
'height': 50,
|
||
'range': 1000,
|
||
'color': '#ff4500'
|
||
}
|
||
|