Connection Com scene with its own elements
This commit is contained in:
commit
f12945e689
Binary file not shown.
@ -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
126
views.py
@ -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
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user