100 lines
4.4 KiB
Python
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})
|