Add Graph Based Lines
This commit is contained in:
parent
f12945e689
commit
eaf0a6273a
Binary file not shown.
Binary file not shown.
@ -19,13 +19,27 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
<!-- Register a simple component to toggle the chat panel -->
|
||||||
|
<script>
|
||||||
|
AFRAME.registerComponent('toggle-chat', {
|
||||||
|
init: function () {
|
||||||
|
this.el.addEventListener('click', function () {
|
||||||
|
var panel = document.querySelector('#chatPanel');
|
||||||
|
var isVisible = panel.getAttribute('visible');
|
||||||
|
panel.setAttribute('visible', !isVisible);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<a-scene shadow="type: pcfsoft"
|
<a-scene shadow="type: pcfsoft"
|
||||||
environment="preset: forest; dressing: trees; groundColor: #777; skyType: gradient; dressingAmount: 20;">
|
environment="preset: forest; dressing: trees; groundColor: #777; skyType: gradient; dressingAmount: 20;">
|
||||||
|
|
||||||
<!-- Camera & Controls (give it an id for look-at) -->
|
<!-- Camera & Controls (give it an id for look-at) -->
|
||||||
<a-entity id="mainCamera" camera look-controls wasd-controls position="0 2 0"></a-entity>
|
<a-entity id="mainCamera" camera look-controls wasd-controls position="0 2 5">
|
||||||
|
<a-cursor color="#FF0000"></a-cursor>
|
||||||
|
</a-entity>
|
||||||
|
|
||||||
<!-- Optional: Transparent ground plane (comment out if you want only environment ground) -->
|
<!-- Optional: Transparent ground plane (comment out if you want only environment ground) -->
|
||||||
<a-plane position="0 -0.1 0" rotation="-90 0 0"
|
<a-plane position="0 -0.1 0" rotation="-90 0 0"
|
||||||
@ -190,6 +204,33 @@
|
|||||||
</a-entity>
|
</a-entity>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
|
<!-- VR AI Agent -->
|
||||||
|
<a-entity id="aiAgent" position="0 2 -3" toggle-chat class="clickable">
|
||||||
|
<!-- Agent appears as a rotating sphere -->
|
||||||
|
<a-sphere radius="0.5" color="#FF69B4"
|
||||||
|
animation="property: rotation; to: 0 360 0; loop: true; dur: 5000">
|
||||||
|
</a-sphere>
|
||||||
|
<!-- Prompt text above the agent -->
|
||||||
|
<a-text value="Ask me something!" position="0 1 0" align="center" width="2" color="#FFF"></a-text>
|
||||||
|
</a-entity>
|
||||||
|
|
||||||
|
<!-- Chat Panel (initially hidden) -->
|
||||||
|
<a-entity id="chatPanel" visible="false" position="1 2 -3">
|
||||||
|
<!-- Background panel for the chat -->
|
||||||
|
<a-plane width="3" height="2" color="#000" opacity="0.7" shadow="cast: false; receive: false"></a-plane>
|
||||||
|
<!-- Chat text; later this can be dynamic -->
|
||||||
|
<a-text value="Network Summary:
|
||||||
|
Towers: {{ city_data.network_summary.num_towers }}
|
||||||
|
Fiber: {{ city_data.network_summary.total_fiber_length|floatformat:2 }} m
|
||||||
|
Wi-Fi: {{ city_data.network_summary.num_wifi }}"
|
||||||
|
align="center" width="4" color="#FFF"
|
||||||
|
position="0 0 0.01">
|
||||||
|
</a-text>
|
||||||
|
</a-entity>
|
||||||
|
|
||||||
</a-scene>
|
</a-scene>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
1
urls.py
1
urls.py
@ -7,4 +7,5 @@ urlpatterns = [
|
|||||||
|
|
||||||
# Pattern to accept string words
|
# Pattern to accept string words
|
||||||
path('city/digital/twin/<str:city_id>/', views.city_digital_twin, name='city_digital_twin_str'),
|
path('city/digital/twin/<str:city_id>/', views.city_digital_twin, name='city_digital_twin_str'),
|
||||||
|
|
||||||
]
|
]
|
||||||
|
88
views.py
88
views.py
@ -298,22 +298,8 @@ def generate_com_con_city_data(lat, long):
|
|||||||
})
|
})
|
||||||
|
|
||||||
# Fiber paths connect neighboring towers
|
# Fiber paths connect neighboring towers
|
||||||
fiber_paths = []
|
# Compute optimized fiber paths using MST
|
||||||
for i in range(len(towers) - 1):
|
fiber_paths = compute_mst_fiber_paths(towers)
|
||||||
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
|
# Wi-Fi Hotspots scattered nearby but within grid bounds
|
||||||
wifi_hotspots = []
|
wifi_hotspots = []
|
||||||
@ -330,8 +316,76 @@ def generate_com_con_city_data(lat, long):
|
|||||||
'color': '#32cd32'
|
'color': '#32cd32'
|
||||||
})
|
})
|
||||||
|
|
||||||
|
network_summary = compute_network_summary(towers, fiber_paths, wifi_hotspots)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'towers': towers,
|
'towers': towers,
|
||||||
'fiber_paths': fiber_paths,
|
'fiber_paths': fiber_paths,
|
||||||
'wifi_hotspots': wifi_hotspots
|
'wifi_hotspots': wifi_hotspots,
|
||||||
|
'network_summary': network_summary,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
import networkx as nx
|
||||||
|
import math
|
||||||
|
|
||||||
|
def compute_distance(t1, t2):
|
||||||
|
"""
|
||||||
|
Compute Euclidean distance between two towers in the horizontal plane.
|
||||||
|
"""
|
||||||
|
dx = t1['position_x'] - t2['position_x']
|
||||||
|
dz = t1['position_z'] - t2['position_z']
|
||||||
|
return math.sqrt(dx**2 + dz**2)
|
||||||
|
|
||||||
|
def compute_mst_fiber_paths(towers):
|
||||||
|
"""
|
||||||
|
Given a list of tower dictionaries, compute a Minimum Spanning Tree (MST)
|
||||||
|
and return a list of fiber paths connecting the towers.
|
||||||
|
"""
|
||||||
|
G = nx.Graph()
|
||||||
|
# Add towers as nodes
|
||||||
|
for tower in towers:
|
||||||
|
G.add_node(tower['id'], **tower)
|
||||||
|
|
||||||
|
# Add edges: compute pairwise distances
|
||||||
|
n = len(towers)
|
||||||
|
for i in range(n):
|
||||||
|
for j in range(i+1, n):
|
||||||
|
d = compute_distance(towers[i], towers[j])
|
||||||
|
G.add_edge(towers[i]['id'], towers[j]['id'], weight=d)
|
||||||
|
|
||||||
|
# Compute MST
|
||||||
|
mst = nx.minimum_spanning_tree(G)
|
||||||
|
|
||||||
|
fiber_paths = []
|
||||||
|
for edge in mst.edges(data=True):
|
||||||
|
id1, id2, data = edge
|
||||||
|
# Find towers corresponding to these IDs
|
||||||
|
tower1 = next(t for t in towers if t['id'] == id1)
|
||||||
|
tower2 = next(t for t in towers if t['id'] == id2)
|
||||||
|
|
||||||
|
fiber_paths.append({
|
||||||
|
'id': len(fiber_paths) + 1,
|
||||||
|
'start_x': tower1['position_x'],
|
||||||
|
'start_z': tower1['position_z'],
|
||||||
|
'end_x': tower2['position_x'],
|
||||||
|
'end_z': tower2['position_z'],
|
||||||
|
'mid_x': (tower1['position_x'] + tower2['position_x']) / 2,
|
||||||
|
'mid_y': 0.1, # Slightly above the ground
|
||||||
|
'mid_z': (tower1['position_z'] + tower2['position_z']) / 2,
|
||||||
|
'length': data['weight'],
|
||||||
|
# Optionally, compute the angle in degrees if needed:
|
||||||
|
'angle': math.degrees(math.atan2(tower2['position_x'] - tower1['position_x'],
|
||||||
|
tower2['position_z'] - tower1['position_z'])),
|
||||||
|
'status': 'Connected',
|
||||||
|
'color': '#4682b4'
|
||||||
|
})
|
||||||
|
return fiber_paths
|
||||||
|
|
||||||
|
def compute_network_summary(towers, fiber_paths, wifi_hotspots):
|
||||||
|
total_fiber = sum(fiber['length'] for fiber in fiber_paths)
|
||||||
|
return {
|
||||||
|
'num_towers': len(towers),
|
||||||
|
'total_fiber_length': total_fiber,
|
||||||
|
'num_wifi': len(wifi_hotspots),
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user