72 lines
3.6 KiB
Python
72 lines
3.6 KiB
Python
"""Build reproducible examples and the interactive visualization from Python results."""
|
|
|
|
from dataclasses import asdict
|
|
import json
|
|
import math
|
|
from pathlib import Path
|
|
import sys
|
|
|
|
ROOT=Path(__file__).resolve().parents[1]
|
|
sys.path.insert(0,str(ROOT))
|
|
from geometry import Measurement, solve
|
|
|
|
|
|
def measured(stations, target, errors):
|
|
return [Measurement(x,y,(math.degrees(math.atan2(target[1]-y,target[0]-x))+e)%360)
|
|
for (x,y),e in zip(stations,errors)]
|
|
|
|
|
|
def scenarios():
|
|
target=(80,90)
|
|
normal=measured([(-600,-250),(650,-100),(100,700)],target,[.65,-.55,.35])
|
|
h=20*math.sqrt(3)
|
|
triangle=[Measurement(-1000,0,1),Measurement(540,-500*math.sqrt(3),121),
|
|
Measurement(520,h+500*math.sqrt(3),241)]
|
|
return [
|
|
dict(id='normal',name='三点交会',source='synthetic',target=target,measurements=normal),
|
|
dict(id='triangle',name='直径圆反例',source='synthetic',target=(20,h/3),measurements=triangle),
|
|
dict(id='poor',name='近共线检测点',source='synthetic',target=(900,50),
|
|
measurements=measured([(0,0),(100,0),(200,0)],(900,50),[0,0,0])),
|
|
dict(id='empty',name='不相容观测',source='synthetic',target=None,
|
|
measurements=[Measurement(-100,0,180),Measurement(100,0,0)]),
|
|
dict(id='segment',name='零误差退化线段',source='synthetic',target=(40,0),
|
|
measurements=[Measurement(0,0,0,0),Measurement(100,0,180,0)]),
|
|
]
|
|
|
|
|
|
def main():
|
|
cases=scenarios()
|
|
practice=ROOT/'output/q1/practice'
|
|
for path in sorted(practice.glob('*_observations.json')):
|
|
doc=json.loads(path.read_text(encoding='utf-8'))
|
|
cases.append(dict(id='practice-'+doc['case_code'],name='官方演练 '+doc['case_code'],
|
|
source='official_practice',target=None,
|
|
measurements=[Measurement(**m) for m in doc['measurements']]))
|
|
examples=ROOT/'examples/q1'
|
|
results=ROOT/'output/q1'
|
|
examples.mkdir(parents=True,exist_ok=True)
|
|
results.mkdir(parents=True,exist_ok=True)
|
|
dataset=[]
|
|
for case in cases:
|
|
ms=case['measurements']
|
|
frames=[solve(ms[:n]) for n in range(1,len(ms)+1)]
|
|
data={**case,'measurements':[asdict(m) for m in ms],'frames':frames}
|
|
dataset.append(data)
|
|
if case['source']=='synthetic':
|
|
(examples/(case['id']+'.json')).write_text(json.dumps({k:v for k,v in data.items() if k!='frames'},ensure_ascii=False,indent=2),encoding='utf-8')
|
|
(results/(case['id']+'_result.json')).write_text(json.dumps(frames[-1],ensure_ascii=False,indent=2,allow_nan=False),encoding='utf-8')
|
|
(results/'demo_data.json').write_text(json.dumps(dataset,ensure_ascii=False,indent=2,allow_nan=False),encoding='utf-8')
|
|
template=(ROOT/'visualization/q1.template.html').read_text(encoding='utf-8')
|
|
fragment=template.replace('/*__Q1_DATA__*/',json.dumps(dataset,ensure_ascii=False,allow_nan=False))
|
|
(ROOT/'visualization/question1.html').write_text(fragment,encoding='utf-8')
|
|
# A standalone companion uses the same fragment and computation results.
|
|
theme=(ROOT/'visualization/standalone.css').read_text(encoding='utf-8')
|
|
page='<!doctype html><html lang="zh-CN"><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>B题问题一交会定位</title><style>'+theme+'</style><body>'+fragment+'</body></html>'
|
|
(results/'question1.html').write_text(page,encoding='utf-8')
|
|
print(json.dumps({'cases':len(dataset),'fragment_bytes':len(fragment.encode('utf-8')),
|
|
'standalone':str(results/'question1.html')},ensure_ascii=False))
|
|
|
|
|
|
if __name__=='__main__':
|
|
main()
|