from django.shortcuts import render, get_object_or_404 from django.http import Http404 import random import math from .services.presets import get_environment_preset import networkx as nx from .services.layouts import ( rectangular_layout, circular_layout, diagonal_layout, triangular_layout, ) from .services.random_city import generate_random_city_data from .services.com_con_city import generate_com_con_city_data from .services.osm_city import generate_osm_city_data, generate_osm_road_midpoints_only def city_digital_twin(request, city_id, innovation_pct=None, technology_pct=None, science_pct=None): try: lat = float(request.GET.get('lat', 0)) long = float(request.GET.get('long', 0)) scale = float(request.GET.get('scale', 1.0)) # default to 1.0 (normal scale) if city_id == "osm_city": city_data = generate_osm_city_data(lat, long,scale=scale) elif city_id == "com_con": city_data = generate_com_con_city_data(lat, long) elif city_id == "random_city": city_data = generate_random_city_data() elif city_id == "dream": innovation_pct = innovation_pct or request.GET.get('innovation', 0) technology_pct = technology_pct or request.GET.get('technology', 0) science_pct = science_pct or request.GET.get('science', 0) innovation_pct = int(innovation_pct) technology_pct = int(technology_pct) science_pct = int(science_pct) city_data = generate_random_city_data(innovation_pct, technology_pct, science_pct) else: city_data = get_city_data(city_id) if not city_data: city_data = get_example_data() preset = get_environment_preset(lat, long) context = { 'city_data': city_data, 'environment_preset': preset, 'lat': lat, 'long': long, } return render(request, 'pxy_city_digital_twins/city_digital_twin.html', context) except (ValueError, TypeError): raise Http404("Invalid data provided.") def get_city_data(city_id): # Implement fetching logic here # This is a mock function to demonstrate fetching logic if str(city_id) == "1" or str(city_id) == "123e4567-e89b-12d3-a456-426614174000": return { # Real data retrieval logic goes here } return None def get_example_data(): return { 'buildings': [ { 'id': 1, 'status': 'Occupied', 'position_x': 0, 'height': 10, 'position_z': 0, 'width': 5, 'depth': 5, 'color': '#8a2be2', 'file': '', # No file for a simple box representation }, { 'id': 2, 'status': 'Vacant', 'position_x': 10, 'height': 15, 'position_z': 10, 'width': 7, 'depth': 7, 'color': '#5f9ea0', 'file': '', # No file for a simple box representation } ], 'lamps': [ { 'id': 1, 'status': 'Functional', 'position_x': 3, 'position_z': 3, 'height': 4, 'color': '#ffff00', }, { 'id': 2, 'status': 'Broken', 'position_x': 8, 'position_z': 8, 'height': 4, 'color': '#ff0000', } ], 'trees': [ { 'id': 1, 'status': 'Healthy', 'position_x': 5, 'position_z': 5, 'height': 6, 'radius_bottom': 0.2, 'radius_top': 1, 'color_trunk': '#8b4513', 'color_leaves': '#228b22', }, { 'id': 2, 'status': 'Diseased', 'position_x': 15, 'position_z': 15, 'height': 6, 'radius_bottom': 0.2, 'radius_top': 1, 'color_trunk': '#a0522d', 'color_leaves': '#6b8e23', } ] } def city_augmented_digital_twin(request, city_id): try: lat = float(request.GET.get('lat', 0)) long = float(request.GET.get('long', 0)) scale = float(request.GET.get('scale', 1.0)) # default to 1.0 if city_id == "osm_city": city_data = generate_osm_road_midpoints_only(lat, long, scale=scale) elif city_id == "random_city": city_data = generate_random_city_data() elif city_id == "gauge_ahead": # No city data needed, just render the special AR scene return render(request, 'pxy_city_digital_twins/spawn_gauge_ahead.html') else: raise Http404("Unsupported city_id for AR view") preset = get_environment_preset(lat, long) context = { 'city_data': city_data, 'environment_preset': preset, 'lat': lat, 'long': long, } return render(request, 'pxy_city_digital_twins/city_augmented_digital_twin.html', context) except (ValueError, TypeError): raise Http404("Invalid parameters provided.") from django.shortcuts import render from django.http import Http404 from .services.waste_routes import get_dispatch_data_for import json def waste_route_debug(request, subdivision, vehicle): # 1) load all routes for this subdivision dispatch_data = get_dispatch_data_for(subdivision) if not dispatch_data: return render(request, 'pxy_city_digital_twins/waste_route_default.html', { 'subdivision': subdivision }) # 2) pick your route by the required `vehicle` path-param try: selected = next(r for r in dispatch_data if r['route_id'] == vehicle) except StopIteration: return render(request, 'pxy_city_digital_twins/waste_route_not_found.html', { 'subdivision': subdivision }) # 3) derive a “center” latitude/longitude from that route: coords = selected.get('coords', []) if coords: avg_lon = sum(pt[0] for pt in coords) / len(coords) avg_lat = sum(pt[1] for pt in coords) / len(coords) else: steps = selected.get('steps', []) avg_lon = sum(s['position'][0] for s in steps) / len(steps) avg_lat = sum(s['position'][1] for s in steps) / len(steps) # 4) generate your OSM‐based city around that center city_data = generate_osm_city_data(avg_lat, avg_lon) # 5) sanitize building heights (replace NaN or missing with default 10.0) default_height = 10.0 for b in city_data.get('buildings', []): h = b.get('height') if not isinstance(h, (int, float)) or (isinstance(h, float) and math.isnan(h)): b['height'] = default_height # 6) render the VR template return render(request, 'pxy_city_digital_twins/waste_route_debug.html', { 'subdivision': subdivision, 'vehicle': vehicle, 'selected_route_json': json.dumps(selected), 'city_data': city_data, }) import math import json from django.shortcuts import render from pyproj import Transformer from .services.osm_city import generate_osm_city_data from .services.waste_routes import get_dispatch_data_for def waste_route(request, subdivision, vehicle): """ URL: /waste/// Renders a single vehicle's waste‐collection route in VR, overlaid on an OSM‐generated city around the route center. """ # 1) load all routes for this subdivision dispatch_data = get_dispatch_data_for(subdivision) if not dispatch_data: return render(request, 'pxy_city_digital_twins/waste_route_default.html', { 'subdivision': subdivision }) # 2) pick your route by the required `vehicle` path-param try: selected = next(r for r in dispatch_data if r['route_id'] == vehicle) except StopIteration: return render(request, 'pxy_city_digital_twins/waste_route_not_found.html', { 'subdivision': subdivision }) # 3) derive center lon/lat from coords (or fallback to steps) coords = selected.get('coords', []) if coords: avg_lon = sum(pt[0] for pt in coords) / len(coords) avg_lat = sum(pt[1] for pt in coords) / len(coords) else: steps = selected.get('steps', []) avg_lon = sum(s['position'][0] for s in steps) / len(steps) avg_lat = sum(s['position'][1] for s in steps) / len(steps) # 4) generate your OSM‐based city around that center city_data = generate_osm_city_data(avg_lat, avg_lon) # 5) sanitize building heights (replace NaN or missing with default 10.0) default_height = 10.0 for b in city_data.get('buildings', []): h = b.get('height') if not isinstance(h, (int, float)) or (isinstance(h, float) and math.isnan(h)): b['height'] = default_height # 6) project all coords (and steps) to Web Mercator, recenter them transformer = Transformer.from_crs("EPSG:4326", "EPSG:3857", always_xy=True) # route merc = [transformer.transform(lon, lat) for lon, lat in coords] if not merc: merc = [transformer.transform(*s['position']) for s in selected.get('steps', [])] avg_x = sum(x for x, _ in merc) / len(merc) avg_z = sum(z for _, z in merc) / len(merc) rel_coords = [[x - avg_x, z - avg_z] for x, z in merc] # steps step_positions = [] for step in selected.get('steps', []): lon, lat = step['position'] x, z = transformer.transform(lon, lat) step_positions.append({ 'x': x - avg_x, 'z': z - avg_z, 'step': step }) # 7) render return render(request, 'pxy_city_digital_twins/virtual_waste_route.html', { 'subdivision': subdivision, 'vehicle': vehicle, 'selected_route_json': json.dumps(selected), 'city_data': city_data, 'rel_coords': rel_coords, 'step_positions': step_positions, }) def augmented_waste_route(request, subdivision, vehicle): """ URL: /waste/// Renders a single vehicle's waste‐collection route in VR, overlaid on an OSM‐generated city around the route center. """ # 1) load all routes for this subdivision dispatch_data = get_dispatch_data_for(subdivision) if not dispatch_data: return render(request, 'pxy_city_digital_twins/waste_route_default.html', { 'subdivision': subdivision }) # 2) pick your route by the required `vehicle` path-param try: selected = next(r for r in dispatch_data if r['route_id'] == vehicle) except StopIteration: return render(request, 'pxy_city_digital_twins/waste_route_not_found.html', { 'subdivision': subdivision }) # 3) derive center lon/lat from coords (or fallback to steps) coords = selected.get('coords', []) if coords: avg_lon = sum(pt[0] for pt in coords) / len(coords) avg_lat = sum(pt[1] for pt in coords) / len(coords) else: steps = selected.get('steps', []) avg_lon = sum(s['position'][0] for s in steps) / len(steps) avg_lat = sum(s['position'][1] for s in steps) / len(steps) # 4) generate your OSM‐based city around that center city_data = generate_osm_city_data(avg_lat, avg_lon) # 5) sanitize building heights (replace NaN or missing with default 10.0) default_height = 10.0 for b in city_data.get('buildings', []): h = b.get('height') if not isinstance(h, (int, float)) or (isinstance(h, float) and math.isnan(h)): b['height'] = default_height # 6) project all coords (and steps) to Web Mercator, recenter them transformer = Transformer.from_crs("EPSG:4326", "EPSG:3857", always_xy=True) # route merc = [transformer.transform(lon, lat) for lon, lat in coords] if not merc: merc = [transformer.transform(*s['position']) for s in selected.get('steps', [])] avg_x = sum(x for x, _ in merc) / len(merc) avg_z = sum(z for _, z in merc) / len(merc) rel_coords = [[x - avg_x, z - avg_z] for x, z in merc] # steps step_positions = [] for step in selected.get('steps', []): lon, lat = step['position'] x, z = transformer.transform(lon, lat) step_positions.append({ 'x': x - avg_x, 'z': z - avg_z, 'step': step }) # 7) render return render(request, 'pxy_city_digital_twins/augmented_waste_route.html', { 'subdivision': subdivision, 'vehicle': vehicle, 'selected_route_json': json.dumps(selected), 'city_data': city_data, 'rel_coords': rel_coords, 'step_positions': step_positions, })