from django.shortcuts import render, get_object_or_404 from django.http import Http404 import random import math def city_digital_twin(request, city_id, innovation_pct=None, technology_pct=None, science_pct=None): try: if city_id == "random_city": city_data = generate_random_city_data() elif city_id == "com_con": city_data = generate_com_con_city_data() elif city_id == "dream": # Retrieve percentages from GET parameters if not in URL 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) # Convert to integers 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) except ValueError: raise Http404("City data not found.") if not city_data: city_data = get_example_data() context = {'city_data': city_data} return render(request, 'pxy_city_digital_twins/city_digital_twin.html', context) if not city_data: # Fallback to example data if no city data is found city_data = get_example_data() context = {'city_data': city_data} return render(request, 'pxy_city_digital_twins/city_digital_twin.html', context) 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 rectangular_layout(num_elements, max_dimension): grid_size = int(math.sqrt(num_elements)) spacing = max_dimension // grid_size return [ { 'position_x': (i % grid_size) * spacing, 'position_z': (i // grid_size) * spacing } for i in range(num_elements) ] def circular_layout(num_elements, radius): return [ { 'position_x': radius * math.cos(2 * math.pi * i / num_elements), 'position_z': radius * math.sin(2 * math.pi * i / num_elements) } for i in range(num_elements) ] def diagonal_layout(num_elements, max_position): return [ { 'position_x': i * max_position // num_elements, 'position_z': i * max_position // num_elements } for i in range(num_elements) ] def triangular_layout(num_elements): positions = [] row_length = 1 while num_elements > 0: for i in range(row_length): if num_elements <= 0: break positions.append({ 'position_x': i * 10 - (row_length - 1) * 5, # Spread out each row symmetrically 'position_z': row_length * 10 }) num_elements -= 1 row_length += 1 return positions def generate_random_city_data(innovation_pct=100, technology_pct=100, science_pct=100, max_position=100, radius=50): num_buildings = random.randint(5, 35) num_lamps = random.randint(5, 100) num_trees = random.randint(5, 55) # Buildings layout distribution num_rectangular_buildings = int(num_buildings * innovation_pct / 100) num_circular_buildings = (num_buildings - num_rectangular_buildings) // 2 num_triangular_buildings = num_buildings - num_rectangular_buildings - num_circular_buildings building_positions = rectangular_layout(num_rectangular_buildings, max_position) + \ circular_layout(num_circular_buildings, radius) + \ triangular_layout(num_triangular_buildings) # Lamps layout distribution num_triangular_lamps = int(num_lamps * technology_pct / 100) num_circular_lamps = (num_lamps - num_triangular_lamps) // 2 num_diagonal_lamps = num_lamps - num_triangular_lamps - num_circular_lamps lamp_positions = triangular_layout(num_triangular_lamps) + \ circular_layout(num_circular_lamps, radius) + \ diagonal_layout(num_diagonal_lamps, max_position) # Trees layout distribution num_circular_trees = int(num_trees * science_pct / 100) num_triangular_trees = (num_trees - num_circular_trees) // 2 num_diagonal_trees = num_trees - num_circular_trees - num_triangular_trees tree_positions = circular_layout(num_circular_trees, radius) + \ triangular_layout(num_triangular_trees) + \ diagonal_layout(num_diagonal_trees, max_position) buildings = [ { 'id': i + 1, 'status': random.choice(['Occupied', 'Vacant', 'Under Construction']), 'position_x': pos['position_x'], 'position_z': pos['position_z'], 'height': random.randint(10, 50), 'width': random.randint(5, 20), 'depth': random.randint(5, 20), 'color': random.choice(['#8a2be2', '#5f9ea0', '#ff6347', '#4682b4']), 'file': '' } for i, pos in enumerate(building_positions) ] lamps = [ { 'id': i + 1, 'status': random.choice(['Functional', 'Non-functional']), 'position_x': pos['position_x'], 'position_z': pos['position_z'], 'height': random.randint(3, 10), 'color': random.choice(['#ffff00', '#ff0000', '#00ff00']), } for i, pos in enumerate(lamp_positions) ] trees = [ { 'id': i + 1, 'status': random.choice(['Healthy', 'Diseased', 'Wilting']), 'position_x': pos['position_x'], 'position_z': pos['position_z'], 'height': random.randint(5, 30), 'radius_bottom': random.uniform(0.1, 0.5), 'radius_top': random.uniform(0.5, 2.0), 'color_trunk': '#8b4513', 'color_leaves': random.choice(['#228b22', '#90ee90', '#8b4513']), } for i, pos in enumerate(tree_positions) ] return { 'buildings': buildings, 'lamps': lamps, 'trees': trees, } def generate_com_con_city_data(): """ Generates a telecom-focused digital twin for the hackathon. It includes cell towers, fiber paths, and optimized coverage zones. """ num_towers = random.randint(3, 10) num_fiber_paths = random.randint(5, 15) num_wifi_hotspots = random.randint(5, 20) towers = [ { 'id': i + 1, 'status': 'Active' if random.random() > 0.2 else 'Inactive', 'position_x': random.uniform(-50, 50), 'position_z': random.uniform(-50, 50), 'height': random.randint(20, 50), 'range': random.randint(500, 1500), # Coverage range in meters 'color': '#ff4500' # Orange for telecom towers } for i in range(num_towers) ] fiber_paths = [ { 'id': i + 1, 'start_x': random.uniform(-50, 50), 'start_z': random.uniform(-50, 50), 'end_x': random.uniform(-50, 50), 'end_z': random.uniform(-50, 50), 'status': 'Connected' if random.random() > 0.1 else 'Broken', 'color': '#4682b4' # Steel blue for fiber cables } for i in range(num_fiber_paths) ] wifi_hotspots = [ { 'id': i + 1, 'position_x': random.uniform(-50, 50), 'position_z': random.uniform(-50, 50), 'status': 'Online' if random.random() > 0.2 else 'Offline', 'range': random.randint(100, 300), 'color': '#32cd32' # Lime green for Wi-Fi coverage } for i in range(num_wifi_hotspots) ] return { 'towers': towers, 'fiber_paths': fiber_paths, 'wifi_hotspots': wifi_hotspots }