Connection Com scene with its own elements

This commit is contained in:
Ekaropolus 2025-03-01 22:20:13 -06:00
commit f12945e689
3 changed files with 273 additions and 35 deletions

Binary file not shown.

View File

@ -1,51 +1,195 @@
{% load static %}
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>LDS City</title>
<script src="https://aframe.io/releases/1.4.0/aframe.min.js"></script>
<script src="https://raw.githack.com/donmccurdy/aframe-extras/v6.0.0/dist/aframe-extras.min.js"></script>
<!-- A-Frame 1.7.0 & environment component -->
<script src="https://aframe.io/releases/1.7.0/aframe.min.js"></script>
<script src="https://unpkg.com/aframe-environment-component/dist/aframe-environment-component.min.js"></script>
<!-- 1) Simple “look-at” component to face the camera -->
<script>
AFRAME.registerComponent('billboard', {
schema: {type: 'selector'},
tick: function () {
if (!this.data) return;
// Make this entity face the camera each frame
this.el.object3D.lookAt(this.data.object3D.position);
}
});
</script>
</head>
<body>
<a-scene>
<!-- Camera and controls -->
<a-entity camera look-controls wasd-controls position="0 2 0"></a-entity>
<a-scene shadow="type: pcfsoft"
environment="preset: forest; dressing: trees; groundColor: #777; skyType: gradient; dressingAmount: 20;">
<!-- Sky -->
{% load static %}
<a-sky id="sky" src="{% static 'textures/sky.jpg' %}" radius="150"></a-sky>
<!-- Camera & Controls (give it an id for look-at) -->
<a-entity id="mainCamera" camera look-controls wasd-controls position="0 2 0"></a-entity>
<!-- Ground plane -->
<a-plane position="0 -0.1 0" rotation="-90 0 0" width="200" height="200" material="src: url(https://cdn.aframe.io/a-painter/images/floor.jpg); repeat: 100 100;"></a-plane>
<!-- Optional: Transparent ground plane (comment out if you want only environment ground) -->
<a-plane position="0 -0.1 0" rotation="-90 0 0"
width="200" height="200"
color="#444" opacity="0.3">
</a-plane>
<!-- Buildings -->
{% for building in city_data.buildings %}
<a-entity id="{{ building.id }}" status="{{ building.status }}">
<a-text value="Status: {{ building.status }}" position="{{ building.position_x }} {{ building.height }} {{ building.position_z }}" scale="2 2 2"></a-text>
<a-box position="{{ building.position_x }} 1 {{ building.position_z }}" width="{{ building.width }}" height="{{ building.height }}" depth="{{ building.depth }}" rotation="0 0 0" color="{{ building.color }}"></a-box>
<!-- Building geometry -->
<a-box position="{{ building.position_x }} 1 {{ building.position_z }}"
width="{{ building.width }}" height="{{ building.height }}" depth="{{ building.depth }}"
color="{{ building.color }}">
</a-box>
<!-- Label entity: plane + text, billboarded to face camera -->
<a-entity position="{{ building.position_x }} 3 {{ building.position_z }}"
billboard="#mainCamera">
<!-- Semi-transparent background plane -->
<a-plane width="4" height="1.2" color="#000" opacity="0.5"></a-plane>
<!-- Text in front of plane -->
<a-text value="Status: {{ building.status }}"
width="4"
align="center"
color="#FFF"
position="0 0 0.01">
</a-text>
</a-entity>
</a-entity>
{% endfor %}
<!-- Lamps -->
{% for lamp in city_data.lamps %}
<a-entity id="{{ lamp.id }}" status="{{ lamp.status }}" position="{{ lamp.position_x }} 1 {{ lamp.position_z }}">
<a-text value="Status: {{ lamp.status }}" position="0 {{ lamp.height }} 0" scale="2 2 2"></a-text>
<a-cone radius-bottom="0.1" radius-top="0.5" height="{{ lamp.height }}" color="{{ lamp.color }}"></a-cone>
<a-sphere radius="0.2" color="#FFFFFF" position="0 {{ lamp.height }} 0"></a-sphere>
<!-- Lamp geometry -->
<a-cone radius-bottom="0.1" radius-top="0.5"
height="{{ lamp.height }}" color="{{ lamp.color }}">
</a-cone>
<a-sphere radius="0.2" color="#FFFFFF"
position="0 {{ lamp.height }} 0">
</a-sphere>
<!-- Label: billboard to camera -->
<a-entity position="0 3 0" billboard="#mainCamera">
<a-plane width="4" height="1.2" color="#000" opacity="0.5"></a-plane>
<a-text value="Status: {{ lamp.status }}"
width="4"
align="center"
color="#FFF"
position="0 0 0.01">
</a-text>
</a-entity>
</a-entity>
{% endfor %}
<!-- Trees -->
{% for tree in city_data.trees %}
<a-entity id="{{ tree.id }}" status="{{ tree.status }}" position="{{ tree.position_x }} 1 {{ tree.position_z }}">
<a-text value="Status: {{ tree.status }}" position="0 {{ tree.height }} 0" scale="2 2 2"></a-text>
<a-cone radius-bottom="{{ tree.radius_bottom }}" radius-top="{{ tree.radius_top }}" height="{{ tree.height }}" color="{{ tree.color_trunk }}"></a-cone>
<a-sphere radius="{{ tree.radius_top }}" color="{{ tree.color_leaves }}" position="0 {{ tree.height }} 0"></a-sphere>
<!-- Tree trunk & leaves -->
<a-cone radius-bottom="{{ tree.radius_bottom }}"
radius-top="{{ tree.radius_top }}"
height="{{ tree.height }}"
color="{{ tree.color_trunk }}">
</a-cone>
<a-sphere radius="{{ tree.radius_top }}"
color="{{ tree.color_leaves }}"
position="0 {{ tree.height }} 0">
</a-sphere>
<!-- Label: billboard to camera -->
<a-entity position="0 3 0" billboard="#mainCamera">
<a-plane width="4" height="1.2" color="#000" opacity="0.5"></a-plane>
<a-text value="Status: {{ tree.status }}"
width="4"
align="center"
color="#FFF"
position="0 0 0.01">
</a-text>
</a-entity>
</a-entity>
{% endfor %}
<!-- Cell Towers -->
{% for tower in city_data.towers %}
<a-entity id="tower{{ tower.id }}"
position="{{ tower.position_x }} {{ tower.position_y }} {{ tower.position_z }}">
<!-- Base tower cylinder -->
<a-cylinder height="{{ tower.height }}" radius="1" color="{{ tower.color }}"></a-cylinder>
<!-- Animated signal ring near top -->
<a-ring color="#FF0000"
radius-inner="2"
radius-outer="2.5"
position="0 {{ tower.height|add:'1' }} 0"
rotation="-90 0 0"
animation="property: scale; to: 1.5 1.5 1.5; dir: alternate; dur: 1000; loop: true">
</a-ring>
<!-- Tower label: billboard to camera -->
<a-entity position="0 -5 0" billboard="#mainCamera">
<a-plane width="4" height="1.2" color="#000" opacity="0.5"></a-plane>
<a-text value="📡 Tower {{ tower.id }} - {{ tower.status }}"
width="4"
align="center"
color="#FFF"
position="0 0 0.01">
</a-text>
</a-entity>
</a-entity>
{% endfor %}
<!-- Fiber Paths (Cylinders) -->
{% for fiber in city_data.fiber_paths %}
<a-entity>
<a-cylinder position="{{ fiber.mid_x }} {{ fiber.mid_y }} {{ fiber.mid_z }}"
height="{{ fiber.length }}"
radius="0.1"
rotation="90 {{ fiber.angle }} 0"
color="{{ fiber.color }}">
</a-cylinder>
<!-- Fiber label: billboard to camera -->
<a-entity position="{{ fiber.start_x }} 3 {{ fiber.start_z }}" billboard="#mainCamera">
<a-plane width="4" height="1.2" color="#000" opacity="0.5"></a-plane>
<a-text value="🔗 Fiber Path {{ fiber.id }} - {{ fiber.status }}"
width="4"
align="center"
color="{{ fiber.color }}"
position="0 0 0.01">
</a-text>
</a-entity>
</a-entity>
{% endfor %}
<!-- Wi-Fi Hotspots -->
{% for wifi in city_data.wifi_hotspots %}
<a-entity id="wifi{{ wifi.id }}"
position="{{ wifi.position_x }} {{ wifi.position_y }} {{ wifi.position_z }}">
<!-- Hotspot sphere (animated) -->
<a-sphere radius="{{ wifi.radius }}" color="{{ wifi.color }}"
animation="property: scale; to: 1.5 1.5 1.5; dir: alternate; dur: 1500; loop: true">
</a-sphere>
<!-- Coverage area (fixed or dynamic) -->
<a-sphere radius="5"
color="#00FFFF"
opacity="0.2"
position="0 {{ wifi.radius }} 0">
</a-sphere>
<!-- Wi-Fi label: billboard to camera -->
<a-entity position="0 3 0" billboard="#mainCamera">
<a-plane width="4" height="1.2" color="#000" opacity="0.5"></a-plane>
<a-text value="📶 WiFi {{ wifi.id }} - {{ wifi.status }}"
width="4"
align="center"
color="#FFF"
position="0 0 0.01">
</a-text>
</a-entity>
</a-entity>
{% endfor %}
</a-scene>
<script src="{% static 'js/lds_city_vr.js' %}"></script>
</body>
</html>

126
views.py
View File

@ -3,17 +3,35 @@ 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:
if city_id == "random_city":
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":
# 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)
@ -21,22 +39,22 @@ def city_digital_twin(request, city_id, innovation_pct=None, technology_pct=None
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()
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)
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.")
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
@ -164,7 +182,6 @@ def triangular_layout(num_elements):
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)
@ -241,3 +258,80 @@ def generate_random_city_data(innovation_pct=100, technology_pct=100, science_pc
'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
}