Ekaropolus fe8eb7a214
All checks were successful
continuous-integration/drone/push Build is passing
Dashboard for Stadum
2025-09-04 19:04:03 -06:00

100 lines
4.4 KiB
Python

# pxy_building_digital_twins/views.py
from django.shortcuts import render
from django.http import JsonResponse
from django.views.decorators.clickjacking import xframe_options_sameorigin
import random, math
# ---------- page views (allow same-origin iframe) ----------
@xframe_options_sameorigin
def viewer(request):
resp = render(request, "pxy_building_digital_twins/viewer.html")
resp["Content-Security-Policy"] = "frame-ancestors 'self'"
return resp
@xframe_options_sameorigin
def wire_viewer(request):
resp = render(request, "pxy_building_digital_twins/wire.html")
resp["Content-Security-Policy"] = "frame-ancestors 'self'"
return resp
@xframe_options_sameorigin
def wire_babylon(request):
resp = render(request, "pxy_building_digital_twins/wire_babylon.html")
resp["Content-Security-Policy"] = "frame-ancestors 'self'"
return resp
# ---------- geometry helpers ----------
def rect_poly(cx, cy, w, h):
x1, x2 = cx - w/2, cx + w/2
y1, y2 = cy - h/2, cy + h/2
return {"type": "Polygon", "coordinates": [[[x1,y1],[x2,y1],[x2,y2],[x1,y2],[x1,y1]]]}
def ept(cx, cy, rx, ry, a):
return [cx + rx*math.cos(a), cy + ry*math.sin(a)]
def ellipse_ring(cx, cy, rx_out, ry_out, rx_in, ry_in, segments=128):
outer = [ept(cx, cy, rx_out, ry_out, i/segments*2*math.pi) for i in range(segments)]
inner = [ept(cx, cy, rx_in, ry_in, i/segments*2*math.pi) for i in range(segments-1, -1, -1)]
return {"type":"Polygon","coordinates":[outer, inner]}
def bins_on_ellipse(cx, cy, rx, ry, count, start_rad=0.0, jitter_r=0.0):
feats=[]
kinds = ["recyclable","organic","landfill","special"]
for i in range(count):
a = start_rad + (i/count)*2*math.pi + random.uniform(-0.03, 0.03)
rxf = rx + random.uniform(-jitter_r, jitter_r)
ryf = ry + random.uniform(-jitter_r, jitter_r)
x,y = ept(cx, cy, rxf, ryf, a)
kind = kinds[i % len(kinds)]
cap = random.choice([40,60,80])
feats.append({
"type":"Feature",
"geometry":{"type":"Point","coordinates":[x,y]},
"properties":{"id":f"BIN_{i+1}","kind":kind,"capacity_l":cap}
})
return feats
# ---------- API ----------
def api_random_stadium(request):
seed = request.GET.get("seed")
if seed is not None:
try:
random.seed(int(seed))
except ValueError:
random.seed(seed)
concourse_bins = int(request.GET.get("concourse_bins", random.randint(42,66)))
dry_toilets = int(request.GET.get("dry_toilets", random.randint(4,8)))
FIELD_W = random.uniform(100, 110)
FIELD_H = random.uniform(64, 72)
CONC_RX_IN = random.uniform(62, 68); CONC_RY_IN = random.uniform(56, 64)
CONC_RX_OUT = CONC_RX_IN + random.uniform(6,10); CONC_RY_OUT = CONC_RY_IN + random.uniform(6,10)
STANDS_RX_IN = CONC_RX_OUT + random.uniform(3,5); STANDS_RY_IN = CONC_RY_OUT + random.uniform(3,5)
STANDS_RX_OUT = STANDS_RX_IN + random.uniform(18,26); STANDS_RY_OUT = STANDS_RY_IN + random.uniform(18,26)
spaces = {"type":"FeatureCollection","features":[]}
spaces["features"].append({"type":"Feature","geometry": rect_poly(0,0, FIELD_W, FIELD_H),
"properties": {"type":"field","name":"Field"}})
spaces["features"].append({"type":"Feature","geometry": ellipse_ring(0,0, CONC_RX_OUT, CONC_RY_OUT, CONC_RX_IN, CONC_RY_IN, 128),
"properties": {"type":"concourse","name":"Main Concourse"}})
spaces["features"].append({"type":"Feature","geometry": ellipse_ring(0,0, STANDS_RX_OUT, STANDS_RY_OUT, STANDS_RX_IN, STANDS_RY_IN, 160),
"properties": {"type":"stands","name":"Stands"}})
RX_MID = (CONC_RX_IN + CONC_RX_OUT)/2
RY_MID = (CONC_RY_IN + CONC_RY_OUT)/2
bins = {"type":"FeatureCollection","features":[]}
bins["features"].extend(bins_on_ellipse(0,0, RX_MID, RY_MID, concourse_bins, random.uniform(0, math.pi/3), jitter_r=1.5))
OUT_RX = STANDS_RX_OUT + random.uniform(10,16)
OUT_RY = STANDS_RY_OUT + random.uniform(10,16)
for i in range(dry_toilets):
a = (i/dry_toilets)*2*math.pi + random.uniform(-0.05,0.05)
x,y = ept(0,0, OUT_RX, OUT_RY, a)
bins["features"].append({"type":"Feature","geometry":{"type":"Point","coordinates":[x,y]},
"properties":{"id":f"DT_{i+1}","kind":"dry_toilet","capacity_l":0}})
return JsonResponse({"spaces": spaces, "bins": bins})