commit 3baadaa817ecef5bc2ced863a51bb16aac13127c Author: Ekaropolus Date: Sat Mar 1 19:40:14 2025 -0600 Initial commit from local machine diff --git a/__init__.py b/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/__pycache__/__init__.cpython-310.pyc b/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000..fe77ea9 Binary files /dev/null and b/__pycache__/__init__.cpython-310.pyc differ diff --git a/__pycache__/admin.cpython-310.pyc b/__pycache__/admin.cpython-310.pyc new file mode 100644 index 0000000..9554c3c Binary files /dev/null and b/__pycache__/admin.cpython-310.pyc differ diff --git a/__pycache__/apps.cpython-310.pyc b/__pycache__/apps.cpython-310.pyc new file mode 100644 index 0000000..1d5a114 Binary files /dev/null and b/__pycache__/apps.cpython-310.pyc differ diff --git a/__pycache__/models.cpython-310.pyc b/__pycache__/models.cpython-310.pyc new file mode 100644 index 0000000..e4cab75 Binary files /dev/null and b/__pycache__/models.cpython-310.pyc differ diff --git a/__pycache__/urls.cpython-310.pyc b/__pycache__/urls.cpython-310.pyc new file mode 100644 index 0000000..dca75e5 Binary files /dev/null and b/__pycache__/urls.cpython-310.pyc differ diff --git a/__pycache__/views.cpython-310.pyc b/__pycache__/views.cpython-310.pyc new file mode 100644 index 0000000..2c95af9 Binary files /dev/null and b/__pycache__/views.cpython-310.pyc differ diff --git a/admin.py b/admin.py new file mode 100644 index 0000000..8c38f3f --- /dev/null +++ b/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/apps.py b/apps.py new file mode 100644 index 0000000..e3aa222 --- /dev/null +++ b/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class PxyCityDigitalTwinsConfig(AppConfig): + default_auto_field = "django.db.models.BigAutoField" + name = "pxy_city_digital_twins" diff --git a/migrations/__init__.py b/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/migrations/__pycache__/__init__.cpython-310.pyc b/migrations/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000..2385233 Binary files /dev/null and b/migrations/__pycache__/__init__.cpython-310.pyc differ diff --git a/models.py b/models.py new file mode 100644 index 0000000..71a8362 --- /dev/null +++ b/models.py @@ -0,0 +1,3 @@ +from django.db import models + +# Create your models here. diff --git a/templates/pxy_city_digital_twins/city_digital_twin.html b/templates/pxy_city_digital_twins/city_digital_twin.html new file mode 100644 index 0000000..7ef66b1 --- /dev/null +++ b/templates/pxy_city_digital_twins/city_digital_twin.html @@ -0,0 +1,51 @@ + + + + + LDS City + + + + + + + + + + {% load static %} + + + + + + + {% for building in city_data.buildings %} + + + + + {% endfor %} + + + {% for lamp in city_data.lamps %} + + + + + + {% endfor %} + + + {% for tree in city_data.trees %} + + + + + + {% endfor %} + + + + + + diff --git a/tests.py b/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/urls.py b/urls.py new file mode 100644 index 0000000..a594400 --- /dev/null +++ b/urls.py @@ -0,0 +1,10 @@ +from django.urls import path +from . import views + +urlpatterns = [ + # Pattern to accept UUIDs + path('city/digital/twin//', views.city_digital_twin, name='city_digital_twin_uuid'), + + # Pattern to accept string words + path('city/digital/twin//', views.city_digital_twin, name='city_digital_twin_str'), +] diff --git a/views.py b/views.py new file mode 100644 index 0000000..925fbc7 --- /dev/null +++ b/views.py @@ -0,0 +1,243 @@ +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 == "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, + }