Compare commits
3 Commits
11326bf585
...
f12945e689
Author | SHA1 | Date | |
---|---|---|---|
f12945e689 | |||
20bb021967 | |||
3baadaa817 |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -1,126 +1,195 @@
|
|||||||
{% load static %}
|
{% load static %}
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<title>LDS City</title>
|
<title>LDS City</title>
|
||||||
<script src="https://aframe.io/releases/1.4.0/aframe.min.js"></script>
|
<!-- A-Frame 1.7.0 & environment component -->
|
||||||
<script src="https://raw.githack.com/donmccurdy/aframe-extras/v6.0.0/dist/aframe-extras.min.js"></script>
|
<script src="https://aframe.io/releases/1.7.0/aframe.min.js"></script>
|
||||||
</head>
|
<script src="https://unpkg.com/aframe-environment-component/dist/aframe-environment-component.min.js"></script>
|
||||||
<body>
|
|
||||||
<a-scene>
|
|
||||||
<!-- Preload Assets -->
|
|
||||||
<a-assets>
|
|
||||||
<img id="skyTexture" src="{% static 'textures/sky.jpg' %}" />
|
|
||||||
<img id="floorTexture" src="https://cdn.aframe.io/a-painter/images/floor.jpg" />
|
|
||||||
</a-assets>
|
|
||||||
|
|
||||||
<!-- Lighting -->
|
<!-- 1) Simple “look-at” component to face the camera -->
|
||||||
<a-entity light="type: ambient; color: #BBB"></a-entity>
|
<script>
|
||||||
<a-entity light="type: directional; color: #FFF; intensity: 0.6" position="0 1 0"></a-entity>
|
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 shadow="type: pcfsoft"
|
||||||
|
environment="preset: forest; dressing: trees; groundColor: #777; skyType: gradient; dressingAmount: 20;">
|
||||||
|
|
||||||
<!-- Camera and Controls -->
|
<!-- Camera & Controls (give it an id for look-at) -->
|
||||||
<a-entity camera look-controls wasd-controls position="0 2 0"></a-entity>
|
<a-entity id="mainCamera" camera look-controls wasd-controls position="0 2 0"></a-entity>
|
||||||
|
|
||||||
<!-- Sky -->
|
<!-- Optional: Transparent ground plane (comment out if you want only environment ground) -->
|
||||||
<a-sky id="sky" src="#skyTexture" radius="150"></a-sky>
|
<a-plane position="0 -0.1 0" rotation="-90 0 0"
|
||||||
|
width="200" height="200"
|
||||||
|
color="#444" opacity="0.3">
|
||||||
|
</a-plane>
|
||||||
|
|
||||||
<!-- Ground Plane -->
|
<!-- Buildings -->
|
||||||
<a-plane position="0 -0.1 0" rotation="-90 0 0" width="200" height="200"
|
|
||||||
material="src: #floorTexture; repeat: 100 100;"></a-plane>
|
|
||||||
|
|
||||||
<!-- Buildings Group -->
|
|
||||||
<a-entity id="buildings-group">
|
|
||||||
{% for building in city_data.buildings %}
|
{% for building in city_data.buildings %}
|
||||||
<a-entity id="building{{ building.id }}" status="{{ building.status }}"
|
<a-entity id="{{ building.id }}" status="{{ building.status }}">
|
||||||
position="{{ building.position_x }} 1 {{ building.position_z }}"
|
<!-- Building geometry -->
|
||||||
event-set__mouseenter="_event: mouseenter; scale: 1.1 1.1 1.1"
|
<a-box position="{{ building.position_x }} 1 {{ building.position_z }}"
|
||||||
event-set__mouseleave="_event: mouseleave; scale: 1 1 1">
|
width="{{ building.width }}" height="{{ building.height }}" depth="{{ building.depth }}"
|
||||||
<a-box width="{{ building.width }}" height="{{ building.height }}" depth="{{ building.depth }}"
|
color="{{ building.color }}">
|
||||||
color="{{ building.color }}"></a-box>
|
</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 }}"
|
<a-text value="Status: {{ building.status }}"
|
||||||
position="0 {{ building.height|add:'1' }} 0"
|
width="4"
|
||||||
scale="1.5 1.5 1.5"></a-text>
|
align="center"
|
||||||
|
color="#FFF"
|
||||||
|
position="0 0 0.01">
|
||||||
|
</a-text>
|
||||||
|
</a-entity>
|
||||||
</a-entity>
|
</a-entity>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</a-entity>
|
|
||||||
|
|
||||||
<!-- Lamps Group -->
|
<!-- Lamps -->
|
||||||
<a-entity id="lamps-group">
|
|
||||||
{% for lamp in city_data.lamps %}
|
{% for lamp in city_data.lamps %}
|
||||||
<a-entity id="lamp{{ lamp.id }}" status="{{ lamp.status }}"
|
<a-entity id="{{ lamp.id }}" status="{{ lamp.status }}" position="{{ lamp.position_x }} 1 {{ lamp.position_z }}">
|
||||||
position="{{ lamp.position_x }} 1 {{ lamp.position_z }}"
|
<!-- Lamp geometry -->
|
||||||
event-set__mouseenter="_event: mouseenter; scale: 1.1 1.1 1.1"
|
<a-cone radius-bottom="0.1" radius-top="0.5"
|
||||||
event-set__mouseleave="_event: mouseleave; scale: 1 1 1">
|
height="{{ lamp.height }}" color="{{ lamp.color }}">
|
||||||
<a-cone radius-bottom="0.1" radius-top="0.5" height="{{ lamp.height }}"
|
</a-cone>
|
||||||
color="{{ lamp.color }}"></a-cone>
|
<a-sphere radius="0.2" color="#FFFFFF"
|
||||||
<a-sphere radius="0.2" color="#FFFFFF" position="0 {{ lamp.height }} 0"></a-sphere>
|
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 }}"
|
<a-text value="Status: {{ lamp.status }}"
|
||||||
position="0 {{ lamp.height|add:'1' }} 0"
|
width="4"
|
||||||
scale="1.5 1.5 1.5"></a-text>
|
align="center"
|
||||||
|
color="#FFF"
|
||||||
|
position="0 0 0.01">
|
||||||
|
</a-text>
|
||||||
|
</a-entity>
|
||||||
</a-entity>
|
</a-entity>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</a-entity>
|
|
||||||
|
|
||||||
<!-- Trees Group -->
|
<!-- Trees -->
|
||||||
<a-entity id="trees-group">
|
|
||||||
{% for tree in city_data.trees %}
|
{% for tree in city_data.trees %}
|
||||||
<a-entity id="tree{{ tree.id }}" status="{{ tree.status }}"
|
<a-entity id="{{ tree.id }}" status="{{ tree.status }}" position="{{ tree.position_x }} 1 {{ tree.position_z }}">
|
||||||
position="{{ tree.position_x }} 1 {{ tree.position_z }}"
|
<!-- Tree trunk & leaves -->
|
||||||
event-set__mouseenter="_event: mouseenter; scale: 1.1 1.1 1.1"
|
<a-cone radius-bottom="{{ tree.radius_bottom }}"
|
||||||
event-set__mouseleave="_event: mouseleave; scale: 1 1 1">
|
radius-top="{{ tree.radius_top }}"
|
||||||
<a-cone radius-bottom="{{ tree.radius_bottom }}" radius-top="{{ tree.radius_top }}"
|
height="{{ tree.height }}"
|
||||||
height="{{ tree.height }}" color="{{ tree.color_trunk }}"></a-cone>
|
color="{{ tree.color_trunk }}">
|
||||||
<a-sphere radius="{{ tree.radius_top }}" color="{{ tree.color_leaves }}"
|
</a-cone>
|
||||||
position="0 {{ tree.height }} 0"></a-sphere>
|
<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 }}"
|
<a-text value="Status: {{ tree.status }}"
|
||||||
position="0 {{ tree.height|add:'1' }} 0"
|
width="4"
|
||||||
scale="1.5 1.5 1.5"></a-text>
|
align="center"
|
||||||
|
color="#FFF"
|
||||||
|
position="0 0 0.01">
|
||||||
|
</a-text>
|
||||||
|
</a-entity>
|
||||||
</a-entity>
|
</a-entity>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</a-entity>
|
|
||||||
|
|
||||||
<!-- Cell Towers Group -->
|
<!-- Cell Towers -->
|
||||||
<a-entity id="towers-group">
|
|
||||||
{% for tower in city_data.towers %}
|
{% for tower in city_data.towers %}
|
||||||
<a-entity id="tower{{ tower.id }}" position="{{ tower.position_x }} 0 {{ tower.position_z }}"
|
<a-entity id="tower{{ tower.id }}"
|
||||||
event-set__mouseenter="_event: mouseenter; scale: 1.1 1.1 1.1"
|
position="{{ tower.position_x }} {{ tower.position_y }} {{ tower.position_z }}">
|
||||||
event-set__mouseleave="_event: mouseleave; scale: 1 1 1">
|
<!-- Base tower cylinder -->
|
||||||
<a-cylinder height="{{ tower.height }}" radius="2" color="{{ tower.color }}"></a-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 }}"
|
<a-text value="📡 Tower {{ tower.id }} - {{ tower.status }}"
|
||||||
position="0 {{ tower.height|add:'1' }} 0" scale="1.5 1.5 1.5"></a-text>
|
width="4"
|
||||||
|
align="center"
|
||||||
|
color="#FFF"
|
||||||
|
position="0 0 0.01">
|
||||||
|
</a-text>
|
||||||
|
</a-entity>
|
||||||
</a-entity>
|
</a-entity>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</a-entity>
|
|
||||||
|
|
||||||
<!-- Fiber Paths Group -->
|
<!-- Fiber Paths (Cylinders) -->
|
||||||
<a-entity id="fiber-paths-group">
|
|
||||||
{% for fiber in city_data.fiber_paths %}
|
{% for fiber in city_data.fiber_paths %}
|
||||||
<a-entity id="fiber{{ fiber.id }}">
|
<a-entity>
|
||||||
<a-line start="{{ fiber.start_x }} 0 {{ fiber.start_z }}"
|
<a-cylinder position="{{ fiber.mid_x }} {{ fiber.mid_y }} {{ fiber.mid_z }}"
|
||||||
end="{{ fiber.end_x }} 0 {{ fiber.end_z }}"
|
height="{{ fiber.length }}"
|
||||||
color="{{ fiber.color }}"></a-line>
|
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 }}"
|
<a-text value="🔗 Fiber Path {{ fiber.id }} - {{ fiber.status }}"
|
||||||
position="{{ fiber.start_x }} 1 {{ fiber.start_z }}"
|
width="4"
|
||||||
scale="1.2 1.2 1.2"></a-text>
|
align="center"
|
||||||
|
color="{{ fiber.color }}"
|
||||||
|
position="0 0 0.01">
|
||||||
|
</a-text>
|
||||||
|
</a-entity>
|
||||||
</a-entity>
|
</a-entity>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</a-entity>
|
|
||||||
|
|
||||||
<!-- Wi-Fi Hotspots Group -->
|
<!-- Wi-Fi Hotspots -->
|
||||||
<a-entity id="wifi-group">
|
|
||||||
{% for wifi in city_data.wifi_hotspots %}
|
{% for wifi in city_data.wifi_hotspots %}
|
||||||
<a-entity id="wifi{{ wifi.id }}" position="{{ wifi.position_x }} 0 {{ wifi.position_z }}"
|
<a-entity id="wifi{{ wifi.id }}"
|
||||||
event-set__mouseenter="_event: mouseenter; scale: 1.1 1.1 1.1"
|
position="{{ wifi.position_x }} {{ wifi.position_y }} {{ wifi.position_z }}">
|
||||||
event-set__mouseleave="_event: mouseleave; scale: 1 1 1">
|
<!-- Hotspot sphere (animated) -->
|
||||||
<a-sphere radius="2" color="{{ wifi.color }}"></a-sphere>
|
<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 }}"
|
<a-text value="📶 WiFi {{ wifi.id }} - {{ wifi.status }}"
|
||||||
position="0 3 0" scale="1.2 1.2 1.2"></a-text>
|
width="4"
|
||||||
|
align="center"
|
||||||
|
color="#FFF"
|
||||||
|
position="0 0 0.01">
|
||||||
|
</a-text>
|
||||||
|
</a-entity>
|
||||||
</a-entity>
|
</a-entity>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</a-entity>
|
|
||||||
|
|
||||||
</a-scene>
|
</a-scene>
|
||||||
<script src="{% static 'js/lds_city_vr.js' %}"></script>
|
</body>
|
||||||
</body>
|
|
||||||
</html>
|
</html>
|
||||||
|
145
views.py
145
views.py
@ -3,19 +3,35 @@ from django.http import Http404
|
|||||||
import random
|
import random
|
||||||
import math
|
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):
|
def city_digital_twin(request, city_id, innovation_pct=None, technology_pct=None, science_pct=None):
|
||||||
try:
|
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()
|
city_data = generate_random_city_data()
|
||||||
elif city_id == "com_con":
|
|
||||||
city_data = generate_com_con_city_data()
|
|
||||||
elif city_id == "dream":
|
elif city_id == "dream":
|
||||||
# Retrieve percentages from GET parameters if not in URL
|
|
||||||
innovation_pct = innovation_pct or request.GET.get('innovation', 0)
|
innovation_pct = innovation_pct or request.GET.get('innovation', 0)
|
||||||
technology_pct = technology_pct or request.GET.get('technology', 0)
|
technology_pct = technology_pct or request.GET.get('technology', 0)
|
||||||
science_pct = science_pct or request.GET.get('science', 0)
|
science_pct = science_pct or request.GET.get('science', 0)
|
||||||
|
|
||||||
# Convert to integers
|
|
||||||
innovation_pct = int(innovation_pct)
|
innovation_pct = int(innovation_pct)
|
||||||
technology_pct = int(technology_pct)
|
technology_pct = int(technology_pct)
|
||||||
science_pct = int(science_pct)
|
science_pct = int(science_pct)
|
||||||
@ -23,23 +39,23 @@ 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)
|
city_data = generate_random_city_data(innovation_pct, technology_pct, science_pct)
|
||||||
else:
|
else:
|
||||||
city_data = get_city_data(city_id)
|
city_data = get_city_data(city_id)
|
||||||
except ValueError:
|
|
||||||
raise Http404("City data not found.")
|
|
||||||
|
|
||||||
if not city_data:
|
if not city_data:
|
||||||
city_data = get_example_data()
|
city_data = get_example_data()
|
||||||
|
|
||||||
context = {'city_data': city_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)
|
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):
|
def get_city_data(city_id):
|
||||||
# Implement fetching logic here
|
# Implement fetching logic here
|
||||||
# This is a mock function to demonstrate fetching logic
|
# This is a mock function to demonstrate fetching logic
|
||||||
@ -244,52 +260,75 @@ def generate_random_city_data(innovation_pct=100, technology_pct=100, science_pc
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def generate_com_con_city_data():
|
def get_environment_by_lat(lat):
|
||||||
"""
|
if lat > 60 or lat < -60:
|
||||||
Generates a telecom-focused digital twin for the hackathon.
|
return 'yeti'
|
||||||
It includes cell towers, fiber paths, and optimized coverage zones.
|
elif 30 < lat < 60 or -30 > lat > -60:
|
||||||
"""
|
return 'forest'
|
||||||
num_towers = random.randint(3, 10)
|
else:
|
||||||
num_fiber_paths = random.randint(5, 15)
|
return 'desert'
|
||||||
num_wifi_hotspots = random.randint(5, 20)
|
|
||||||
|
|
||||||
towers = [
|
|
||||||
{
|
import random
|
||||||
'id': i + 1,
|
|
||||||
|
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',
|
'status': 'Active' if random.random() > 0.2 else 'Inactive',
|
||||||
'position_x': random.uniform(-50, 50),
|
'position_x': x,
|
||||||
'position_z': random.uniform(-50, 50),
|
'position_y': 0,
|
||||||
'height': random.randint(20, 50),
|
'position_z': z,
|
||||||
'range': random.randint(500, 1500), # Coverage range in meters
|
'height': random.randint(40, 60),
|
||||||
'color': '#ff4500' # Orange for telecom towers
|
'range': random.randint(500, 1000),
|
||||||
}
|
'color': '#ff4500'
|
||||||
for i in range(num_towers)
|
})
|
||||||
]
|
|
||||||
|
|
||||||
fiber_paths = [
|
# Fiber paths connect neighboring towers
|
||||||
{
|
fiber_paths = []
|
||||||
|
for i in range(len(towers) - 1):
|
||||||
|
fiber_paths.append({
|
||||||
'id': i + 1,
|
'id': i + 1,
|
||||||
'start_x': random.uniform(-50, 50),
|
'start_x': towers[i]['position_x'],
|
||||||
'start_z': random.uniform(-50, 50),
|
'start_z': towers[i]['position_z'],
|
||||||
'end_x': random.uniform(-50, 50),
|
'end_x': towers[i + 1]['position_x'],
|
||||||
'end_z': random.uniform(-50, 50),
|
'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',
|
'status': 'Connected' if random.random() > 0.1 else 'Broken',
|
||||||
'color': '#4682b4' # Steel blue for fiber cables
|
'color': '#4682b4'
|
||||||
}
|
})
|
||||||
for i in range(num_fiber_paths)
|
|
||||||
]
|
|
||||||
|
|
||||||
wifi_hotspots = [
|
# 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,
|
'id': i + 1,
|
||||||
'position_x': random.uniform(-50, 50),
|
'position_x': x,
|
||||||
'position_z': random.uniform(-50, 50),
|
'position_y': 1.5,
|
||||||
|
'position_z': z,
|
||||||
'status': 'Online' if random.random() > 0.2 else 'Offline',
|
'status': 'Online' if random.random() > 0.2 else 'Offline',
|
||||||
'range': random.randint(100, 300),
|
'radius': random.randint(1, 3),
|
||||||
'color': '#32cd32' # Lime green for Wi-Fi coverage
|
'color': '#32cd32'
|
||||||
}
|
})
|
||||||
for i in range(num_wifi_hotspots)
|
|
||||||
]
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'towers': towers,
|
'towers': towers,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user