From 3baadaa817ecef5bc2ced863a51bb16aac13127c Mon Sep 17 00:00:00 2001 From: Ekaropolus Date: Sat, 1 Mar 2025 19:40:14 -0600 Subject: [PATCH] Initial commit from local machine --- __init__.py | 0 __pycache__/__init__.cpython-310.pyc | Bin 0 -> 157 bytes __pycache__/admin.cpython-310.pyc | Bin 0 -> 198 bytes __pycache__/apps.cpython-310.pyc | Bin 0 -> 465 bytes __pycache__/models.cpython-310.pyc | Bin 0 -> 195 bytes __pycache__/urls.cpython-310.pyc | Bin 0 -> 422 bytes __pycache__/views.cpython-310.pyc | Bin 0 -> 5139 bytes admin.py | 3 + apps.py | 6 + migrations/__init__.py | 0 .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 168 bytes models.py | 3 + .../city_digital_twin.html | 51 ++++ tests.py | 3 + urls.py | 10 + views.py | 243 ++++++++++++++++++ 16 files changed, 319 insertions(+) create mode 100644 __init__.py create mode 100644 __pycache__/__init__.cpython-310.pyc create mode 100644 __pycache__/admin.cpython-310.pyc create mode 100644 __pycache__/apps.cpython-310.pyc create mode 100644 __pycache__/models.cpython-310.pyc create mode 100644 __pycache__/urls.cpython-310.pyc create mode 100644 __pycache__/views.cpython-310.pyc create mode 100644 admin.py create mode 100644 apps.py create mode 100644 migrations/__init__.py create mode 100644 migrations/__pycache__/__init__.cpython-310.pyc create mode 100644 models.py create mode 100644 templates/pxy_city_digital_twins/city_digital_twin.html create mode 100644 tests.py create mode 100644 urls.py create mode 100644 views.py 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 0000000000000000000000000000000000000000..fe77ea97fe8897c0aa17af4e162698740fc5623c GIT binary patch literal 157 zcmd1j<>g`kf`u)rX(0MBh(HF6K#l_t7qb9~6oz01O-8?!3`HPe1o6v3KO;XkRo^is zH#09iF)uSwzaT#+v$!B9wIZ{mQoo?0GCmo|h)>B(&n!vIi7zS7%q!N9kI&4@EQycT ZE2zB1VUwGmQks)$2Qs;s2}rOo003F8CF%eG literal 0 HcmV?d00001 diff --git a/__pycache__/admin.cpython-310.pyc b/__pycache__/admin.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9554c3c523164c12eac45cb823b7141bd67c64c7 GIT binary patch literal 198 zcmd1j<>g`kf`u)rY4$++F^Gc(44TX@fuanW zjJH@5Q*tx&{4|-O_)@YG^V0M6lJoOQiZYXmKnAR2C}IXuVB(jpenx(7s=gygLwaIf zW}<#Ueokg_K~8E#W=W-fK}BVJGLR9Ul9`@al9&@;Ql6PttPeI{ub}c4hfQvNN@-52 N9V5`hVvy+q3;>@|F+czS literal 0 HcmV?d00001 diff --git a/__pycache__/apps.cpython-310.pyc b/__pycache__/apps.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1d5a11402a085a17d95c5d89e12c56af4380ae51 GIT binary patch literal 465 zcmZuty-ve05VqqKh5jt4LSjH-VaSraK!sY0V5^W|%3_(G6O5e1)QM65TA@IqOc zcm*cTO(i;T(w*<``_6aeXw)Yt@0;`V6W=cv?2C`V6xE)g0RmK$oFIKxfXg?IRcrAT31{kBTu)KzN>wZl{?hd{7mAw&jUxp9XZBTZF6~?6z~gE6)vd-G8GyZ-BWrm~=Z_ MxPw|pI3#2C3z)5W1^@s6 literal 0 HcmV?d00001 diff --git a/__pycache__/models.cpython-310.pyc b/__pycache__/models.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e4cab75ccbe7609bfa241ae061096902ffe72518 GIT binary patch literal 195 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 C>6Hcm literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..23852332c95909647571d566bb09a3c7adbf967b GIT binary patch literal 168 zcmd1j<>g`kf`u)rX(0MBh(HF6K#l_t7qb9~6oz01O-8?!3`HPe1o6vTKO;XkRo^is zH#09iF)uSwzaT#+v$!B9wIZ{mQoo?0GCmo|h)>B(&n!vIi7zS7%q!N<%}g&!EXm9V iGUMYj^D;}~ + + + + 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, + }