from django.shortcuts import render, get_object_or_404 from django.http import Http404 import random import math def get_environment_preset(lat, long): """ Determines the A-Frame environment preset based on latitude and longitude. You can adjust the logic to suit your needs. """ # Example logic: adjust these thresholds as needed if lat >= 60 or lat <= -60: return 'snow' # Polar regions: snow environment elif lat >= 30 or lat <= -30: return 'forest' # Mid-latitudes: forest environment elif long >= 100: return 'goldmine' # Arbitrary example: for far east longitudes, a 'goldmine' preset else: return 'desert' # Default to desert for lower latitudes and moderate longitudes 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)) if 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 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 get_environment_by_lat(lat): if lat > 60 or lat < -60: return 'yeti' elif 30 < lat < 60 or -30 > lat > -60: return 'forest' else: return 'desert' import random def generate_com_con_city_data(lat, long): random.seed(f"{lat},{long}") center_x = lat % 100 center_z = long % 100 grid_size = 5 spacing = 15 # Distance between objects # Towers in a grid 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' }) # Fiber paths connect neighboring towers fiber_paths = [] for i in range(len(towers) - 1): fiber_paths.append({ 'id': i + 1, 'start_x': towers[i]['position_x'], 'start_z': towers[i]['position_z'], 'end_x': towers[i + 1]['position_x'], 'end_z': towers[i + 1]['position_z'], 'mid_x': (towers[i]['position_x'] + towers[i + 1]['position_x']) / 2, 'mid_y': 0.1, 'mid_z': (towers[i]['position_z'] + towers[i + 1]['position_z']) / 2, 'length': ((towers[i + 1]['position_x'] - towers[i]['position_x'])**2 + (towers[i + 1]['position_z'] - towers[i]['position_z'])**2)**0.5, 'angle': random.uniform(0, 360), 'status': 'Connected' if random.random() > 0.1 else 'Broken', 'color': '#4682b4' }) # Wi-Fi Hotspots scattered nearby but within grid bounds wifi_hotspots = [] for i in range(10): x = center_x + random.uniform(-spacing * grid_size / 2, spacing * grid_size / 2) z = center_z + random.uniform(-spacing * grid_size / 2, spacing * grid_size / 2) wifi_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 { 'towers': towers, 'fiber_paths': fiber_paths, 'wifi_hotspots': wifi_hotspots }