From eaf0a6273ab5924dd1de9460e739d68559b92c5d Mon Sep 17 00:00:00 2001 From: Ekaropolus Date: Sun, 2 Mar 2025 01:28:05 -0600 Subject: [PATCH] Add Graph Based Lines --- __pycache__/urls.cpython-310.pyc | Bin 422 -> 397 bytes __pycache__/views.cpython-310.pyc | Bin 7231 -> 8840 bytes .../city_digital_twin.html | 43 ++++++++- urls.py | 1 + views.py | 88 ++++++++++++++---- 5 files changed, 114 insertions(+), 18 deletions(-) diff --git a/__pycache__/urls.cpython-310.pyc b/__pycache__/urls.cpython-310.pyc index dca75e533332cfdefe92319a80f7206f3c33ced5..4227ce172b88834abe3d20ceb3ed0a33753556c0 100644 GIT binary patch delta 32 mcmZ3++{?_H&&$ij00im34yUJVdF>hHZ1gkob5r#lQ*tx&(i8JC6ZH%7b25tya#AZY LODZP^GTHzDsvr?H diff --git a/__pycache__/views.cpython-310.pyc b/__pycache__/views.cpython-310.pyc index 7f83fd04de30b45eb2d2f57b526e34e9dc029ad1..8d7cdb4caefdf8ecbfc879d056c08a9333554d4c 100644 GIT binary patch delta 2947 zcmZuzO>o=B6~+P}2>zO;Y>KiJ6?PK4Oln24JFVSGW7m$Oq=}U{QvQ%+XqpR3utktw zfR(C(Wo&s`yQ!0^=qaP=Sd$*wW5>5ne=a%q(wQD`>bcWX+)Sr4{rlcRqAg8<*|%@s z?mj%c_r16Khf}vN6g!1NR>8B9{%mpM|i*jn;!;S3e=s8X0T znlx@j-za=~QW~!cvLZGb-LB(t{0muZXLi2i+gZ_BsV_U;Vz4AGMWy1)Z0Y`c#VM7! z(TAnJ@fzv76czVZ*&ETZ{a=iI3xc)uWKF66E{YV z9es(Gn#odHC8|W;C31zx5|LK)#}UhrF1mdG?;}T9?%O1OnaC?-@BLE;&oOHSdd4-Q|rneYVuD1d+G{Rh%U)TDDgbNG2x~T(}W6@u$ zlkE8@GgfEsM1LDQcW4d9h#4YNL@pEgDo9O_UOe=~Al~OW!AeJ5tNXonyCJ??%Si9U zy6-q#qCij#VhzDg96Q?Vw7b2)ski;0-g2)vqTX!;OTOsQy5a0zy+uL35&J-Fv*~yN z_N|^AvTI_VrWc5OkH{sEm|cz8YRuL|NTNQG?^6V_6|iLnKffM5ICOkqmUJ!8j^Ndq z!BqK{Sr&cvpZTn+B@*Lbg7)nSnhrqCy}CkY-|hUBG^BHkumkJVrX?S!rJ)d9#_lKI1G5|?)3 zwDbK}$X^CFm-G^=FmW4f6SCn$dk>&#XgELlfmom7e+L2esz@yvFg{5a~&$7JMBiIj-k09k+&{Ig)p zl&MykiF#YcdxWX~$)m{kKNkwMo zp}BZZIfRG{C5JtP5So)eU(Shx95o41-?Oo+nQ!)yjXqMo^Yv a6*r?V#*eb6qKS#ac~dpNZZc3afBb(+Rio_y delta 1283 zcmZ`&O=uHA6yDk0?$%@zYZ9Bp#H4AZx@c>J9$E!0{%c$RYPGZ#O*2VM)g+yy{;{=! z3LY&Zo{F@1X~m1=q$q+OJ?U{p^d^W$6;u@8n~ho#XUI42z3+W*=51!K?|9PbEqXjI z3CF8vx%#$gZw&CRVrl)6dD-jQE!AC;+@_elCNI%w##IUR~shd2T^$lla*4j*1_U7_AmR?wiW1$ zdP_2y%_fs<3o42TWdxDDSTXLK*R~K&Lc-fqb`hSbe=f@Laf7c5Y=E1Ai3 zB}I_!Mn+{NSlBoM1F-dpLOxq$Xa2L{f`4`EUKG|lLe#Jj!U#edA&-#bpZ!gm_;#sk zG|)=iJs9pq=&SZEA0SN^z)s5mzXo=O|0s4;?v?q|#)nfmY0_PhE2^bkAyf-VSIBnh z7@O2B_pD;+R0~R$X6a#xE(`y%e2#_OpLoryasR|Y9h7KYM56v$JtuQYYys)uItfVs zUD_!Y0=Zut;h(KQ>#$HE;Fl`WtVUgQ`J4 + + - + + + {% endfor %} + + + + + + + + + + + + + + + + + + + + + diff --git a/urls.py b/urls.py index a594400..85d593d 100644 --- a/urls.py +++ b/urls.py @@ -7,4 +7,5 @@ urlpatterns = [ # 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 index f1f1edc..ed589a8 100644 --- a/views.py +++ b/views.py @@ -298,22 +298,8 @@ def generate_com_con_city_data(lat, long): }) # 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' - }) + # Compute optimized fiber paths using MST + fiber_paths = compute_mst_fiber_paths(towers) # Wi-Fi Hotspots scattered nearby but within grid bounds wifi_hotspots = [] @@ -330,8 +316,76 @@ def generate_com_con_city_data(lat, long): 'color': '#32cd32' }) + network_summary = compute_network_summary(towers, fiber_paths, wifi_hotspots) + return { 'towers': towers, '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), + } \ No newline at end of file