--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/kml/config.py Mon May 18 08:48:51 2020 +0200
@@ -0,0 +1,246 @@
+import json
+import os
+
+import targets
+from kml import *
+
+
+class Config:
+ class Value:
+ def __init__(self, key, val):
+ self.key = key
+ self.val = val
+ self.chk = True
+ self.keyact = key + '_actual'
+
+ def extract(self, p):
+ if self.key in p:
+ self.val = p[self.key][0]
+ self.chk = True
+
+ class ValueN(Value):
+ def extract(self, p):
+ if self.key in p:
+ try:
+ self.val = float(p[self.key][0])
+ self.chk = True
+ except:
+ self.val = p[self.key][0]
+ self.chk = False
+
+ def __init__(self):
+ # -------------------------------------------------
+ # zadání - vstupní veličiny
+ # -------------------------------------------------
+ self.name = self.Value('NA', 'flyby')
+ self.targname = self.Value('TA', '')
+ self.lat = self.ValueN('LA', targets.Stalin.lat)
+ self.long = self.ValueN('LO', targets.Stalin.long)
+ self.h0 = self.ValueN('H0', 300)
+ self.x0 = self.ValueN('X0', 8000)
+ self.y0 = self.ValueN('Y0', -12000)
+ self.z0 = self.ValueN('Z0', 12000)
+ self.x1 = self.ValueN('X1', 0)
+ self.y1 = self.ValueN('Y1', -150)
+ self.z1 = self.ValueN('Z1', 100)
+ self.exp = self.ValueN('EX', 2)
+ self.steps = self.ValueN('ST', 600)
+ self.speedfact = self.ValueN('SPF', 1)
+ self.slowdown = self.Value('SLD', 'tangential')
+ self.slowdfact = self.ValueN('SLF', 1)
+ self.flyby = self.ValueN('FL', 1)
+ self.influentials = ['name', 'targname', 'lat', 'long', 'h0', 'x0', 'y0', 'z0',
+ 'x1', 'y1', 'z1', 'exp', 'steps', 'speedfact', 'slowdown', 'slowdfact', 'flyby']
+
+ # -------------------------------------------------
+ # počáteční podmínky
+ # -------------------------------------------------
+ self.dXmin = 0.1 # min delta X při numerické konvergenci
+ self.minZ = 60 # minimální přípustná výška nad terénem v metrech
+ self.dHmax = 5 # empirické maximální přípustné otočení pohledu v jednom kroku ve stupních
+ self.durOpt = 23 # empirické optimum: rychlost otáčení pohledu = 23°/sec
+ self.stepsMax = 9999
+
+ # -------------------------------------------------
+ # provozní konstanty
+ # -------------------------------------------------
+ self.configsrv = 'kml'
+ self.dnldsrv = 'flyby'
+ if 'HTTP_HOST' in os.environ:
+ h = os.environ['HTTP_HOST'].split('.')
+ self.srvhost = h[0].lower()
+ self.srvdomain = '.'.join(h[1:])
+ self.dnldqual = '.'.join((self.dnldsrv, self.srvdomain))
+ self.configqual = '.'.join((self.configsrv, self.srvdomain))
+ _reqPath = os.environ['HTTP_HOST'] + os.environ['REQUEST_URI'].split('?')[0]
+ _configKeyWord = 'kml'
+ _dnldKeyWord = 'flyby'
+ self.configReq = _reqPath.lower().find(_configKeyWord) > -1
+ self.dnldReq = _reqPath.lower().find(_dnldKeyWord) > -1
+ _reqUrl = '{scheme}://{host}:{port}{path}'.\
+ format(scheme=os.environ['REQUEST_SCHEME'],
+ host=os.environ['HTTP_HOST'],
+ port=os.environ['SERVER_PORT'],
+ path=os.environ['REQUEST_URI'].split('?')[0])
+ self.dnldUrl = _reqUrl.lower().replace(_configKeyWord, _dnldKeyWord)
+ deb('self.dnldUrl=%s' % self.dnldUrl)
+ self.dnldPath = _reqPath.lower().replace(_configKeyWord, _dnldKeyWord)
+ deb('self.dnldPath=%s' % self.dnldPath)
+ self.defaultlat = 50.1
+ self.defaultlong = 14.3
+ self.parmsdir = 'params'
+ self.targsdir = 'targets'
+ self.kmlfn = 'flyby' # jméno výstupu - neměnné
+ self.zipped = False
+ # zipping se nedá v současnosti používat, protože Google Earth se s ním nechová standardně
+ # - viz .../memo/googleearth
+ self.kmlfile = '{}.{}'.format(self.kmlfn, 'kmz' if self.zipped else 'kml')
+ self.urlfile = 'url.kml'
+ self.msg = ''
+ self.flagged = False
+
+ def adjust(self):
+ self.x0.val = fabs(self.x0.val)
+ if self.x0.val < self.dXmin:
+ self.x0.val = 0
+ self.x1.val = 0
+ if self.z0.val < self.minZ:
+ self.z0.val = self.minZ
+ if self.z1.val < self.minZ:
+ self.z1.val = self.minZ
+ self.steps.val = int(round(self.steps.val))
+ if self.steps.val <= 0:
+ self.steps.val = 20
+ if self.steps.val > self.stepsMax:
+ self.steps.val = self.stepsMax
+ self.exp.val = fabs(self.exp.val)
+ self.flyby.val = int(fabs(self.flyby.val))
+
+ if self.x0.val > 0:
+ self.r0 = degrees(atan(self.y0.val / self.x0.val)) # lokální azimut na startu
+ self.r1 = 90 if self.y1.val < 0 else -90 # lokální azimut v průletu
+ if self.y1.val == 0:
+ if self.y0.val == 0:
+ self.r1 = 90
+ else:
+ self.r1 = 90 * fabs(self.y0.val) / self.y0.val
+ if self.exp.val <= 1:
+ self.r1 = -self.r1
+ self.h1 = can360(self.h0.val + self.r0 + self.r1) # azimut v průletu
+ self.h2 = can360(self.h0.val + 2 * (self.h1 - self.h0.val)) # azimut na konci
+
+ dY = self.y1.val - self.y0.val
+ dZ = self.z1.val - self.z0.val
+ if dY == 0:
+ self.A = pi / 2 if dZ < 0 else -pi / 2
+ else:
+ self.A = atan(dZ / dY) # sklon roviny letu, horiz = 0
+ if dY > 0:
+ self.A = self.A + pi if dZ <= 0 else self.A - pi
+
+ F = sqrt(pow(dY, 2) + pow(dZ, 2)) # maximální funkční hodnota
+ if self.x0.val > 0:
+ self.K = F / pow(self.x0.val, self.exp.val) # koeficient paraboly
+
+ sa = SpeedAdjust(self.speedfact.val, self.slowdfact.val, self.steps.val, self)
+ self.speedAdjust = sa.slowdowns[self.slowdown.val](sa)
+
+ self.lastH = self.h0.val
+ self.lastX, self.lastY, self.lastZ = self.x0.val, self.y0.val, self.z0.val
+ self.dX = -2 * self.x0.val / self.steps.val
+ if fabs(self.dX) < self.dXmin:
+ self.dX = -self.dXmin
+ self.sumSteps, self.sumDur = 0, 0
+ self.rr = []
+
+ def update_influentials(self, p):
+ for n in self.influentials:
+ v = eval('self.{}'.format(n))
+ v.extract(p)
+ self.flagged += (not v.chk)
+
+ v = self.lat
+ if v.chk:
+ v.chk = (v.val >= -90 and v.val <= 90)
+ v = self.long
+ if v.chk:
+ v.chk = v.val >= -180 and v.val <= 180
+ v = self.slowdown
+ v.chk = v.val in SpeedAdjust.keys
+
+ self.flagged = False
+ for n in self.influentials:
+ v = eval('self.{}'.format(n))
+ self.flagged += (not v.chk)
+
+ def parmspath(self):
+ return os.path.join(self.parmsdir, self.name.val)
+
+ def parmsls(self):
+ l = os.listdir(self.parmsdir)
+ l.sort()
+ #deb("l={}".format(l))
+ return l
+
+ def targspath(self, name):
+ return os.path.join(self.targsdir, name)
+
+ def targsls(self):
+ l = os.listdir(self.targsdir)
+ l.sort()
+ return l
+
+ def gettarget(self, name):
+ fn = name if name != '' else 'point'
+ path = self.targspath(fn)
+ long = self.defaultlong
+ lat = self.defaultlat
+ if os.path.exists(path):
+ g = {}
+ for p in open(path).read().split(','):
+ k, v = p.split('=')
+ g[k] = v
+ if self.long.key in g:
+ long = g[self.long.key]
+ if self.lat.key in g:
+ lat = g[self.lat.key]
+ return long, lat
+
+ def storetarget(self, name, long, lat):
+ fn = name if name != '' else 'point'
+ path = self.targspath(fn)
+ open(path, mode='w').write('{}={},{}={}'.format(self.lat.key, lat, self.long.key, long))
+
+ def restoreparms(self):
+ if not os.path.exists(self.parmspath()):
+ return
+ parms = dict(json.load(open(self.parmspath())))
+ # for p in open(self.parmspath()).read().split(','):
+ # k,v = p.split('=')
+ # parms[k] = [v]
+ self.update_influentials(parms)
+
+ def storeparms(self):
+ if not self.name:
+ return
+ # s = []
+ p = {}
+ for n in self.influentials:
+ v = eval('self.{}'.format(n))
+ # s = s + ['='.join((v.key,str(v.val)))]
+ p[v.key] = [str(v.val)]
+ # open(self.parmspath(), mode='w').write(','.join(s))
+ json.dump(p, open(self.parmspath(), mode='w'), ensure_ascii=False)
+
+ def printparms(self):
+ s = []
+ for n in self.influentials:
+ v = eval('self.{}'.format(n))
+ s = s + ['{}={}'.format(v.key, v.val)]
+ return '\n'.join(s)
+
+ def adjustenv(self):
+ p = {}
+ for k in os.environ:
+ p[k] = [os.environ[k]]
+ return p
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/kml/flyby.py Mon May 18 08:48:51 2020 +0200
@@ -0,0 +1,243 @@
+# coding=utf8
+
+import targets
+import config
+from kml import *
+import sys
+import os
+import time
+from math import *
+
+"""
+# -----------------------------------------------------------------------------------------------------------
+# pokusy s KML v Googleearth
+# ● program generuje položky LookAt tak, aby vznikl pohyb kamery jako symetrický průlet kolem cílového bodu,
+# na který kamera po celou dobu letu hledí
+# ● cílový bod leží vždy v počátku lokálních souřadnic letu
+# ● zadávané souřadnice výchozího bodu a průletu jsou lokální souřadnice (v metrech) vzhledem k cílovému bodu
+# ● výchozí bod je X0>=0, Y0, Z0>minZ>0; pro X0=0 se vytváří jen jediný LookAt
+# ● bod průletu je X1=0, Y1, Z1>minZ>0
+# ● křivka průletu je symetrická podle roviny Y,Z a je to buď parabola nebo 2 polopřímky s počátkem v průletu
+# ● pro Z0=Z1 probíhá let ve vodorovné rovině, pro Y0=Y1 ve svislé rovině rovnoběžné s X
+# ● zadávaný exponent paraboly exp>0; pro exp=1 přejde parabola do polopřímek
+# ● zadávané geodetické souřadnice cílového bodu a azimut kamery na startu uchycují lokální soustavu do geodetických souřadnic,
+# výška cílového bodu je vždy 0 nad terénem
+# ● v modulu kml jsou dispozici geo-souřadnice několika konkrétních bodů
+# ● zadává se počet kroků (LookAt), které se generují; propočítávají se body z 1.poloviny letu,
+# body 2.poloviny jsou symetrické (mají symetrický lokální azimut)
+# ● doba přeletu v každém kroku se určuje podle empirických pravidel:
+# 1. podle výšky kamery: rychlost v m/s je číselně rovna střední výšce v m
+# 2. podle úhlu otočení v kroku: rychlost taková, aby otáčení vycházelo cca 20°/s
+# ** volí se nižší hodnota rychlosti z obou pravidel
+# ● průběh rychlosti se může zadat jako nelineární se zpomalením v průletu;
+# - k dispozici je 5 podtříd SpeedAdjust od konstatní po exponenciální
+# - každá třída je parametrizována váhovými koeficienty pro konstatntní a proměnnou složku rychlosti
+# ● Googleearth při změnách azimutu mezi dvěma LookAt většími než empirických dHmax nepohybuje kamerou lineárně,
+# proto funkce compStep hlídá změnu azimutu v kroku (dH) a přizpůsobuje dX tak, aby dH byl těsně menší než dHmax
+# ● pro každý krok se vypočítává lokální azimut "polohy" kamery (Ri), z něhož se určuje geo-azimut "pohledu" kamery
+# (lokální azimut 0 leží na kladné poloose X)
+# ● lokální azimut v průletu je R1=+/-90°, pro Y1=0 (kamera hledí svisle dolů) se pokládá R1=-90° pro exp>1 jinak 90°
+# ● když chci obrátit směr pohybu kamery po dráze, obrátím znaménka Y0 a Y1
+# a výchozí azimut H0 změním na konečný azimut H2; vypočtené hodnoty se vypisují v komentáři na začátku výstupu
+# ● zadáním switche "průlet" se řídí vytvoření celého průletu nebo jen letu do největšího přiblížení (bodu průletu)
+# ● výstup ve tvaru Tour v KML Documentu jde na sys.stdout
+#
+# formáty GEO-souřadnic:
+# 50.1009147N, 14.4057506E mapy.cz
+# 50.765779° 15.050950° google earth
+# 50°02'44.9"N 14°25'52.4"E google maps
+# 50.045796, 14.431211
+# 36°58′41″N 82°34′37″W wikipedia
+# -----------------------------------------------------------------------------------------------------------
+"""
+class Flyby():
+ k = Kml()
+
+ def __init__(self, config):
+ self.c = config
+
+ def pr(self, s):
+ print(s, file=self.k.out)
+
+ def compMove(self):
+ c = self.c
+ xi = c.xi
+ Ri = 0
+ if (c.x0.val > 0 and xi == c.x0.val) or c.x0.val == 0:
+ yi, zi = c.y0.val, c.z0.val
+ heading = c.h0.val
+ elif(xi == 0):
+ yi, zi = c.y1.val, c.z1.val
+ heading = c.h1
+ else:
+ try: f = c.K * pow(xi, c.exp.val)
+ except:
+ deb('ABEND: K={}, xi={}, exp={}'.format(c.K, xi, c.exp.val))
+ sys.stderr.close()
+ os._exit(1)
+ yi = c.y1.val + f * cos(c.A)
+ zi = c.z1.val + f * sin(c.A)
+ Ri = degrees(atan(yi / xi))
+ heading = can360(c.h0.val + c.r0 - Ri)
+
+ dist = sqrt(pow(xi,2) + pow(yi,2) + pow(zi,2))
+ tilt = degrees(acos(zi / dist))
+
+ dX = xi - c.lastX
+ dY = yi - c.lastY
+ dZ = zi - c.lastZ
+ dS = sqrt(pow(dX,2) + pow(dY,2) + pow(dZ,2))
+ tDur = dS / pow((zi + fabs(dZ/2)), 1) # empirické optimum: rychlost letu = výška/sec
+ dH = can180(heading - c.lastH)
+ rDur = fabs(dH) / c.durOpt # empirické optimum: rychlost otáčení
+ rawdur = rDur if rDur > tDur else tDur
+ dur = rawdur * c.speedAdjust.koef() if c.x0.val > 0 else rawdur
+
+ # self.drspeed = dS/rawdur if rawdur > 0 else -0.0 # +++
+ # self.dspeed = dS/dur if dur > 0 else -0.0 # +++
+ # self.dkoef = c.speedAdjust.koef() # +++
+ # self.drdur = rDur # +++
+ # self.dtdur = tDur # +++
+
+ c.yi, c.zi = yi, zi
+
+ s = ('Xi={:.3f}, dX={:.3f}, Yi={:.1f}, dY={:.3f}, Zi={:.1f}, dZ={:.3f}, dS={:.3f}, Ri={:.3f}, dist={:.1f}, tilt={:.1f}, '
+ .format(xi, dX, yi, dY, zi, dZ, dS, Ri, dist, tilt),
+ 'heading={:.3f}, dH={:.3f}, dur={:.3f}'.format(heading, dH, dur))
+
+ return (s, dur, dist, tilt, heading)
+
+ def compStep(self):
+ c = self.c
+ (s, dur, dist, tilt, heading) = self.compMove()
+ dH = can180(heading - c.lastH)
+ bad = fabs(dH) > c.dHmax
+ if(bad and fabs(c.dX) > c.dXmin):
+ ddX = -c.dX/2
+ last = bad
+ found = 0
+ while(fabs(dH) > 0 and fabs(dH) != c.dHmax and fabs(ddX) > c.dXmin):
+ c.dX = c.dX + ddX
+ c.xi = c.lastX + c.dX
+ (s, dur, dist, tilt, heading) = self.compMove()
+ dH = can180(heading - c.lastH)
+ bad = fabs(dH) > c.dHmax
+ if(not bad): found = c.xi
+ ddX = ddX/2 if bad == last else -ddX/2
+ last = bad
+ if(fabs(c.dX) > c.xi): c.dX = -c.xi
+ if(bad and found > 0):
+ c.xi = found
+ s, dur, dist, tilt, heading = self.compMove()
+ dH = can180(heading - c.lastH)
+ # deb('Xi={:.3f}, i={:.3f}, koef = {:.3f}, speed={:.3f}, adj speed={:.3f}, trans dur={:.3f}, rot dur={:.3f}'
+ # .format(c.xi, 1 - c.xi / c.x0.val, self.dkoef, self.drspeed, self.dspeed, self.dtdur, self.drdur)) # +++
+ return s, dur, dist, tilt, heading, dH
+
+ def compTour(self):
+ c = self.c
+
+ c.xi = c.x0.val
+ s, dur, dist, tilt, heading, dH = self.compStep()
+ self.fly(s[0]+s[1], 5, False, dist, tilt, heading)
+ if(c.x0.val == 0): return
+
+ c.xi = c.xi + c.dX
+ while(c.xi > fabs(c.dX)):
+ s, dur, dist, tilt, heading, dH = self.compStep()
+ self.fly(s[0]+s[1], dur, True, dist, tilt, heading)
+ c.xi = c.xi + c.dX
+
+ self.k.comm('>>> střed')
+ c.xi = 0
+ s, dur, dist, tilt, heading, dH = self.compStep()
+ if(fabs(dH) <= c.dHmax): self.fly(s[0]+s[1], dur, True, dist, tilt, heading)
+ while(c.xi > c.dXmin):
+ self.k.comm('>>> dotažení středu')
+ c.xi = 0
+ s, dur, dist, tilt, heading, dH = self.compStep()
+ if(fabs(dH) <= c.dHmax): self.fly(s[0]+s[1], dur, True, dist, tilt, heading)
+ else: break
+ if(fabs(dH) > c.dHmax):
+ self.k.comm('>>> dotočení středu')
+ c.xi = 0
+ s, dur, dist, tilt, heading = self.compMove()
+ d = c.dHmax * dH / fabs(dH)
+ h = c.lastH
+ while(fabs(dH) > c.dHmax):
+ h = can360(h + d)
+ dur = fabs(d)/c.durOpt
+ s_ = s[0] + 'heading={:.3f}, dH={:.3f}, dur={:.3f}'.format(h, d, dur)
+ self.fly(s_, dur, True, dist, tilt, h)
+ dH = can180(heading - h)
+ if(fabs(dH) > 0):
+ dur = fabs(dH)/c.durOpt
+ s_ = s[0] + 'heading={:.3f}, dH={:.3f}, dur={:.3f}'.format(heading, dH, dur)
+ self.fly(s_, dur, True, dist, tilt, heading)
+
+ if(c.flyby):
+ c = self.c
+ del c.rr[0] # středový záznam se škrtá, neopakuje se
+ lastH = c.h1
+ for i in c.rr:
+ nDur, dist, tilt, heading = i
+ heading = can360(2 * c.h1 - heading) # heading je zrcadlový vůči svislé rovině headingu v průletu (H1)
+ dH = can180(heading - lastH)
+ s_ = 'dist={:.1f}, tilt={:.1f}, heading={:.3f}, dH={:.3f}, dur={:.3f}'.format(dist, tilt, heading, dH, dur)
+ self.fly(s_, dur, True, dist, tilt, heading) # duration se bere z předchozího záznamu
+ dur = nDur
+ lastH = heading
+
+ self.k.comm('sum: steps={}, duration={:.2f}'.format(c.sumSteps, c.sumDur))
+
+ def step(self, dur, dist, tilt, heading):
+ c = self.c
+ c.lastH = heading
+ c.lastX, c.lastY, c.lastZ = c.xi, c.yi, c.zi
+ c.rr = [(dur, dist, tilt, heading)] + c.rr
+ c.sumDur = c.sumDur + dur
+ c.sumSteps = c.sumSteps + 1
+
+ def fly(self, s, dur, smooth, dist, tilt, heading):
+ self.step(dur, dist, tilt, heading)
+ self.k.comm(s)
+ self.k.flyto.head(dur, smooth)
+ self.k.lookat.run(self.c.long.val, self.c.lat.val, 0, heading, tilt, dist)
+ # self.k.camera.runL(c.long.val, c.lat.val, 0, heading, tilt, dist, 0)
+ self.k.flyto.tail()
+
+ def headcomms(self):
+ c = self.c
+ self.k.comm(time.asctime())
+ c.confcomm = ('lat={lat}, long={long}, heading={heading}, exp={exp}, ' +
+ 'flyby={flyby}, speedfactor={speedf}, slowdown={slowd}, slowdfactor={slowdf}, steps={steps}')\
+ .format(target=c.targname.val, long=c.long.val, lat=c.lat.val, heading=c.h0.val, exp=c.exp.val,
+ flyby=c.flyby.val, speedf=c.speedfact.val, slowd=c.slowdown.val, slowdf=c.slowdfact.val, steps=c.steps.val)
+
+ if(c.x0.val == 0):
+ c.coorcomm = 'X0,Y0,Z0={},{},{}, H0={}'.format(c.x0.val, c.y0.val, c.z0.val, c.h0.val)
+ else:
+ c.coorcomm = ('X0,Y0,Z0={},{},{}, X1,Y1,Z1={},{},{}, '.format(c.x0.val, c.y0.val, c.z0.val, c.x1.val, c.y1.val, c.z1.val) +
+ 'A={:.3f}, H0={}, H1={:.3f}, H2={:.3f}, R0={:.3f}, R1={:.3f}'
+ .format(degrees(c.A), c.h0.val, c.h1, c.h2, c.r0, c.r1))
+
+ self.k.comm(c.confcomm)
+ self.k.comm(c.coorcomm)
+
+ def tour(self):
+ fkml = '{}.kml'.format(int(time.time())) if self.c.zipped else self.c.kmlfile
+ self.k.out = open(fkml, mode='w', encoding='utf-8')
+ self.k.xml.head()
+ self.k.tourProlog(self.c.name.val)
+ self.headcomms()
+ self.compTour()
+ self.k.tourEpilog()
+ self.k.xml.tail()
+ self.k.out.close()
+ if self.c.zipped:
+ fkmz = '{}.kmz'.format(self.c.kmlfn)
+ if os.path.exists(fkmz):
+ os.remove(fkmz)
+ from subprocess import Popen
+ p = Popen(['zip', fkmz, fkml], stdout=sys.stderr)
+ p.wait()
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/kml/hh_http.py Mon May 18 08:48:51 2020 +0200
@@ -0,0 +1,258 @@
+# coding=utf8
+
+import sys
+import os
+import time
+import cgi
+import cgitb
+import html
+from kml import *
+from kml import deb
+from subprocess import Popen
+
+class Http():
+ titles = {}
+ titles['general'] = """
+● vytvoří KML-stream z elementů LookAt pro GoogleEarth tak, aby vznikl pohyb kamery jako symetrický průlet kolem cílového bodu, na který kamera po celou dobu letu hledí
+● cílový bod leží v počátku lokálních souřadnic letu
+● křivka průletu je parabola y = abs(Y1 + x**exp) s počátkem v bodu průletu a je symetrická podle roviny y,z lokálních souřadnic
+● zadávané souřadnice výchozího bodu a bodu průletu jsou lokální souřadnice (v metrech) vzhledem k cílovému bodu
+● výchozí bod má souřadnice X0>=0, Y0, Z0>{minZ}; pro X0=0 se vytváří jen jediný LookAt (vlastně Placemark)
+● bod průletu má souřadnice X1=0, Y1, Z1>{minZ}
+● zadávaný exponent paraboly je exp>0; pro exp=1 přejde parabola do polopřímek
+● pro Z0=Z1 probíhá let ve vodorovné rovině, pro Y0=Y1 ve svislé rovině rovnoběžné s osou x
+● zadávané geodetické souřadnice cílového bodu (ve stupních) a azimut kamery na startu (sever=0) uchycují lokální soustavu do geodetických souřadnic, výška cílového bodu je vždy 0 nad terénem
+● průběh rychlosti se může zadat jako nelineární se zpomalením v průletu s několika druhy průběhu
+● přepínač "flyby" řídí vytvoření celého průletu nebo jen letu do největšího přiblížení (do bodu průletu)
+● konfigurace letů a geo-souřadnice cílových bodů je možno pojmenovat a uložit ("store conf" resp. "store geo") a později vytáhnout do formuláře ("get conf" resp. "get geo")
+"""
+ titles['name'] = 'jméno pro uložení aktuální konfigurace z obrazovky na server {server}'
+ titles['target'] = 'jméno pro uložení aktuálních geodetických souřadnic cílového bodu z obrazovky na server {server}'
+ titles['submitstored'] = 'vytvořit KML-stream z konfigurace uložené na serveru {server} pod zadaným jménem'
+ titles['submitconf'] = 'vytvořit KML-stream z konfigurace vyplněné ve formuláři na obrazovce'
+ titles['storeconf'] = 'uložit konfiguraci na server {server} pod jménem zadaným v položce name'
+ titles['getconf'] = 'vytáhnout konfiguraci uloženou na serveru {server} pod zadaným jménem'
+ titles['storegeo'] = 'uložit souřadnice cílového bodu na server {server} pod jménem zadaným v položce target'
+ titles['getgeo'] = 'vytáhnout souřadnice cílového bodu uložené na serveru {server} pod jménem zadaným v položce target'
+ titles['azimuth'] = 'geodetický azimut cílového bodu při pohledu z výchozího bodu x0,y0,z0'
+ titles['speedfact'] = 'koeficient konstantní složky rychlosti letu >0'
+ titles['slowfact'] = 'koeficient zpomalení v průletu >0'
+ titles['slowdown'] = 'průběh zpomalení v průletu'
+ titles['exponent'] = 'exponent (>0) průletové paraboly x = abs(Y1 + x**exp); pro exp=1 přejde parabola do polopřímek s počátkem v bodu průletu'
+ titles['flyby'] = 'přepínač průlet/nálet; nálet = let z výchozího bodu do maximálního přiblížení (bodu průletu)'
+ titles['steps'] = 'počet bodů KML-streamu < {stepsMax}'
+ titles['xyz0'] = 'lokální souřadnice X0>=0, Y0, Z0>{minZ} v metrech výchozího (krajního) bodu průletové paraboly x = abs(Y1 + x**exp); počátek lokálních souřadnic je v cílovém bodě'
+ titles['xyz1'] = 'lokální souřadnice X1=0, Y1, Z1>{minZ} bodu průletu kolem cílového bodu po parabole x = abs(Y1 + x**exp); počátek lokálních souřadnic je v cílovém bodě'
+ titles['lat'] = 'geodetická šířka cílového bodu ve stupních -90<š<90; cílový bod je zároveň počátkem lokálních souřadnic letové paraboly'
+ titles['long'] = 'geodetická délka cílového bodu ve stupních -180<d<180; cílový bod je zároveň počátkem lokálních souřadnic letové paraboly'
+
+ def __init__(self, config):
+ self.c = config
+ self.titles['general'] = self.titles['general'].format(minZ=self.c.minZ)
+ self.titles['xyz0'] = self.titles['xyz0'].format(minZ=self.c.minZ)
+ self.titles['xyz1'] = self.titles['xyz1'].format(minZ=self.c.minZ)
+ self.titles['steps'] = self.titles['steps'].format(stepsMax=self.c.stepsMax)
+ self.titles['name'] = self.titles['name'].format(server=self.c.configqual)
+ self.titles['target'] = self.titles['target'].format(server=self.c.configqual)
+ self.titles['submitstored'] = self.titles['submitstored'].format(server=self.c.configqual)
+ self.titles['storeconf'] = self.titles['storeconf'].format(server=self.c.configqual)
+ self.titles['getconf'] = self.titles['getconf'].format(server=self.c.configqual)
+ self.titles['storegeo'] = self.titles['storegeo'].format(server=self.c.configqual)
+ self.titles['getgeo'] = self.titles['getgeo'].format(server=self.c.configqual)
+ # deb(self.titles)
+
+ def parsehttp(self, msg):
+ c = self.c
+ # cgitb.enable()
+ p = cgi.parse()
+ # deb(('parsehttp, p', p))
+
+ c.domainname = '.'.join(os.environ['HTTP_HOST'].split('.')[1:])
+ if c.name.keyact in p: c.name.val = p[c.name.keyact][0]
+ if c.name.key in p: c.name.val = p[c.name.key][0]
+ if c.targname.keyact in p: c.targname.val = p[c.targname.keyact][0]
+ if c.slowdown.keyact in p: c.slowdown.val = p[c.slowdown.keyact][0]
+
+ if 'downlkml' in p:
+ self.sendfile(c.kmlfile)
+ return False
+ if 'downlurl' in p:
+ self.httpheader(c.urlfile)
+ Kml().urlPlacemark(c.dnldUrl, c.dnldPath)
+ sys.stdout.close()
+ # self.sendfile(c.urlfile)
+ return False
+
+ c.restoreparms()
+
+ if 'getparms' in p:
+ return False
+ if 'submitstored' in p:
+ if c.flagged:
+ return False
+ else:
+ c.adjust()
+ return True
+
+ c.update_influentials(p)
+
+ if 'gettarget' in p:
+ c.long.val, c.lat.val = c.gettarget(c.targname.val)
+ return False
+ if 'storetarget' in p and c.lat.chk and c.long.chk:
+ c.storetarget(c.targname.val, c.long.val, c.lat.val)
+ return False
+
+ if c.flagged:
+ return False
+ c.adjust()
+ if 'submit' in p:
+ return True
+ if 'storeparms' in p:
+ c.storeparms()
+ return False
+ return False
+
+ def htmlhead(self):
+ print("Content-type: text/html")
+ print('')
+ print('<!DOCTYPE html><html><head>')
+ print('<meta charset=\"utf-8\"/>')
+ print('<style type="text/css">')
+ print('.box {border: 1px solid; padding: .4em}')
+ print('.round {border:.12em solid; border-radius:50%; width:1.2em; line-height:1.2em; text-align:center;}')
+ print('.flag {background-color: #ffaaaa}')
+ print('.emph {color: #ff00ff; font-weight: bold}')
+ print('</style>')
+ print('</head><body>')
+ print('<div style="display:flex" title="{}">'.format(html.escape(self.titles['general'])))
+ print('<br><span class="box"><b>Google Earth parabolic flyby</b></span>')
+ print(' <div><div class="round"><b>?</b></div></div>')
+ print('</div><br>')
+
+ def htmltrail(self):
+ print('</body></html>')
+
+ def sendform(self, confirm=True):
+ c = self.c
+ # cgitb.enable()
+ # cgi.test()
+ self.htmlhead()
+ if(confirm): self.sendconfirm()
+
+ if(c.flagged):
+ print('<p style="color: red"><b>FLAG</b></p>')
+ print('<form method=POST>')
+ print('<input type=hidden name="{kaname}" value="{actualname}">'
+ .format(kaname=c.name.keyact, actualname=c.name.val))
+ print('<input type=hidden name="{katargname}" value="{actualtargname}">'
+ .format(katargname=c.targname.keyact, actualtargname=c.targname.val))
+ print('<input type=hidden name="{kaslowdown}" value="{actualsldn}">'
+ .format(kaslowdown=c.slowdown.keyact, actualsldn=c.slowdown.val))
+
+ print('<table><tr><td><label><b>name</b> [{name}]<br><input type="text" name="{kname}" list="names" title="{tname}">'
+ .format(kname=c.name.key, name=c.name.val, tname=self.titles['name']))
+ print('<datalist id="names">')
+ for i in c.parmsls():
+ print('<option value="{}"/>'.format(i))
+ print('</datalist></input></label></td></tr></table>')
+ print('<input type=submit name="getparms" value="get stored conf" title="{}">'
+ .format(self.titles['getconf']))
+ print('<input type=submit name="storeparms" value="store conf" title="{}">'
+ .format(self.titles['storeconf']))
+ print('<input type=submit name="submitstored" value="submit stored conf" title="{}">'
+ .format(html.escape(self.titles['submitstored'])))
+ print('<br><br>')
+
+ print('<table><tr><td><label><b>target</b> [{targname}]<br><input type="text" name="{ktargname}" list="targets" title="{ttarget}">'
+ .format(ktargname=c.targname.key, targname=c.targname.val, ttarget=self.titles['target']))
+ print('<datalist id="targets">')
+ for i in c.targsls():
+ print('<option value="{}"/>'.format(i))
+ print('</datalist></input></label></td>')
+ print('<td><label><b>latitude<br><input type="text" name="{kla}" value="{vla}" title="{lat}" class="{flag}"></td>'
+ .format(kla=c.lat.key, vla=c.lat.val, lat=self.titles['lat'], flag='' if c.lat.chk else 'flag'))
+ print('<td><label><b>longitude<br><input type="text" name="{klo}" value="{vlo}" title="{long}" class="{flag}"></td>'
+ .format(klo=c.long.key, vlo=c.long.val, long=self.titles['long'], flag='' if c.long.chk else 'flag'))
+ print('</tr></table>')
+ print('<input type=submit name="gettarget" value="get stored geo" title="{}">'
+ .format(self.titles['getgeo']))
+ print('<input type=submit name="storetarget" value="store geo" title="{}">'
+ .format(self.titles['storegeo']))
+ print('<br><br>')
+
+ print('<table><tr>')
+ print('<td><label><b>X0<br><input type="text" name="{kx0}" value="{vx0}" title="{xyz0}" class="{flag}"></label></td>'
+ .format(kx0=c.x0.key, vx0=c.x0.val, xyz0=self.titles['xyz0'], flag='' if c.x0.chk else 'flag'))
+ print('<td><label><b>Y0<br><input type="text" name="{ky0}" value="{vy0}" title="{xyz0}" class="{flag}"></label></td>'
+ .format(ky0=c.y0.key, vy0=c.y0.val, xyz0=self.titles['xyz0'], flag='' if c.y0.chk else 'flag'))
+ print('<td><label><b>Z0<br><input type="text" name="{kz0}" value="{vz0}" title="{xyz0}" class="{flag}"></label></td>'
+ .format(kz0=c.z0.key, vz0=c.z0.val, xyz0=self.titles['xyz0'], flag='' if c.z0.chk else 'flag'))
+ print('</tr>')
+ print('<tr>')
+ print('<td><label><b>azimuth<br><input type="text" name="{kh0}" value="{vh0}" title="{azimuth}" class="{flag}"></label></td>'
+ .format(kh0=c.h0.key, vh0=c.h0.val, azimuth=self.titles['azimuth'], flag='' if c.h0.chk else 'flag'))
+ print('<td><label><b>Y1<br><input type="text" name="{ky1}" value="{vy1}" title="{xyz1}" class="{flag}"></label></td>'
+ .format(ky1=c.y1.key, vy1=c.y1.val, xyz1=self.titles['xyz1'], flag='' if c.y1.chk else 'flag'))
+ print('<td><label><b>Z1<br><input type="text" name="{kz1}" value="{vz1}" title="{xyz1}" class="{flag}"></label></td>'
+ .format(kz1=c.z1.key, vz1=c.z1.val, xyz1=self.titles['xyz1'], flag='' if c.z1.chk else 'flag'))
+ print('<tr/>')
+ print('<tr>')
+ print('<td><label><b>speed factor<br><input type="text" name="{kspeedfact}" value="{speedfact}" title="{tspeedfact}" class="{flag}"></label></td>'
+ .format(kspeedfact=c.speedfact.key, speedfact=c.speedfact.val, tspeedfact=self.titles['speedfact'], flag='' if c.speedfact.chk else 'flag'))
+ print('<td><label><b>slowdown</b> [{slowdown}]<br><input type="text" name="{kslowdown}" list="slowdowns" title="{tslowdown}" class="{flag}"></label></td>'
+ .format(kslowdown=c.slowdown.key, slowdown='' if not c.slowdown.chk else SpeedAdjust.abrv[c.slowdown.val],
+ tslowdown=self.titles['slowdown'], flag='' if c.slowdown.chk else 'flag'))
+ print('<td><label><b>slowdown factor<br><input type="text" name="{kslowdfact}" value="{slowdfact}" title="{tslowfact}" class="{flag}"></label></td>'
+ .format(kslowdfact=c.slowdfact.key, slowdfact=c.slowdfact.val, tslowfact=self.titles['slowfact'], flag='' if c.slowdfact.chk else 'flag'))
+ print('</tr>')
+ print('<tr>')
+ print('<td><label><b>exponent<br><input type="text" name="{kex}" value="{vex}" title="{exponent}" class="{flag}"></label></td>'
+ .format(kex=c.exp.key, vex=c.exp.val, exponent=self.titles['exponent'], flag='' if c.exp.chk else 'flag'))
+ print('<td><label><b>flyby<br><input type="text" name="{kfl}" value="{vfl}" title="{flyby}"></label></td>'
+ .format(kfl=c.flyby.key, vfl=(1 if c.flyby.val else 0), flyby=self.titles['flyby']))
+ print('<td><label><b># of steps<br><input type="text" name="{kst}" value="{vst}" title="{steps}" class="{flag}"></label></td>'
+ .format(kst=c.steps.key, vst=c.steps.val, steps=self.titles['steps'], flag='' if c.steps.chk else 'flag'))
+ print('</tr>')
+ print('</table>')
+
+ print('<input type=submit name="submit" value="submit conf" title="{submitconf}">'
+ .format(submitconf=self.titles['submitconf']))
+ print('<input type=submit name="storeparms" value="store conf" title="{storeconf}">'
+ .format(storeconf=self.titles['storeconf']))
+ print('<datalist id="slowdowns">')
+ for i in SpeedAdjust.keys:
+ print('<option value="{}"/>'.format(i))
+ print('</datalist></form>')
+ self.htmltrail()
+
+ def sendconfirm(self):
+ print("""
+ <b>{}</b><br><br>
+ <div style="font-size: smaller;">
+ Flyby KML is <span class="emph">ready</span> to be opened on Google Earth (GE):<br>
+ <ul>
+ <li>for both <b>standalone-</b> and <b>web-GE</b> download KML and open file on GE</li>
+ or<br>
+ <li>on standalone-GE open KML directly via html-ref placemark http://{}/<br>
+ <span style="font-style: italic;">(download URL-placemark and place it (via open) in GE's placemarks for subsequent direct openings)</span>.</li>
+ </ul></div>
+ <form method=POST>
+ <input type="submit" name="downlkml" value="download flyby KML">
+ <input type="submit" name="downlurl" value="download URL placemark">
+ </form>
+ <div style="font-size: 66%;"><br>{conf}<br>{coor}<br></div>
+ <hr><br>
+ """.format(time.asctime(), self.c.dnldqual, conf=self.c.confcomm, coor=self.c.coorcomm))
+
+ def httpheader(self, fn):
+ print('Content-Type: application/vnd.google-earth.kml+xml')
+ print('Content-Disposition: attachment; filename="{}"'.format(fn))
+ print()
+
+ def sendfile(self, fn):
+ self.httpheader(fn)
+ sys.stdout.flush()
+ p = Popen(('cat', fn))
+ p.wait()
+ sys.stdout.close()
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/kml/kml.py Mon May 18 08:48:51 2020 +0200
@@ -0,0 +1,263 @@
+import sys
+import xml.sax.saxutils
+from math import *
+
+class Kml():
+ def __init__(self):
+ self.out = sys.stdout
+ self.placemark = Placemark(self)
+ self.tour = Tour(self)
+ self.playlist = Playlist(self)
+ self.flyto = FlyTo(self)
+ self.lookat = LookAt(self)
+ self.camera = Camera(self)
+ self.document = Document(self)
+ self.folder = Folder(self)
+ self.xml = Xml(self)
+
+ def documentProlog(self, fn):
+ self.xml.head()
+ self.document.head(fn)
+
+ def documentEpilog(self):
+ self.document.tail()
+ self.xml.tail()
+
+ def folderProlog(self, fn):
+ self.folder.head(fn)
+
+ def folderEpilog(self):
+ self.folder.tail()
+
+ def tourProlog(self, fn):
+ self.tour.head(fn)
+ self.playlist.head()
+
+ def tourEpilog(self):
+ self.playlist.tail()
+ self.tour.tail()
+
+ def placemarkProlog(self, fn):
+ self.xml.head()
+ self.placemark.head(fn)
+
+ def placemarkEpilog(self):
+ self.placemark.tail()
+ self.xml.tail()
+
+ def urlPlacemark(self, url, path):
+ # ref = '<a href="http://{}/index.py">{}</a>'.format(qualname, qualname)
+ ref = '<a href="{}">{}</a>'.format(url, path)
+ p = self.pr
+ p('<Placemark>')
+ p('<name>{ref}</name>'.format(ref = xml.sax.saxutils.escape(ref)))
+ p('</Placemark>')
+
+ def wait(self, dur):
+ self.pr('\n<gx:Wait><gx:duration>{}</gx:duration></gx:Wait>'.format(dur))
+
+ def comm(self, c):
+ self.pr('\n<!-- {} -->'.format(c))
+
+ def pr(self, s):
+ print(s, file=self.out)
+
+class Xml():
+ def __init__(self, kml):
+ self.kml = kml
+
+ def head(self):
+ self.kml.pr('<?xml version="1.0" encoding="UTF-8"?>')
+ self.kml.pr('<kml')
+ self.kml.pr('xmlns="http://www.opengis.net/kml/2.2"')
+ self.kml.pr('xmlns:gx="http://www.google.com/kml/ext/2.2"')
+ self.kml.pr('>')
+
+ def tail(self):
+ self.kml.pr('\n</kml>')
+
+class Document():
+ def __init__(self, kml):
+ self.kml = kml
+
+ def head(self, fn):
+ self.kml.pr('<Document>')
+ self.kml.pr('<name>{}</name>'.format(fn))
+ self.kml.pr('<open>1</open>')
+
+ def tail(self):
+ self.kml.pr('\n</Document>')
+
+
+class Folder():
+ def __init__(self, kml):
+ self.kml = kml
+
+ def head(self, fn):
+ self.kml.pr('<Folder>')
+ self.kml.pr('<name>{}</name>'.format(fn))
+ self.kml.pr('<open>1</open>')
+
+ def tail(self):
+ self.kml.pr('\n</Folder>')
+
+class Tour():
+ def __init__(self, kml):
+ self.kml = kml
+
+ def head(self, fn):
+ self.kml.pr('\n<gx:Tour>')
+ self.kml.pr('<name>{}</name>'.format(fn))
+
+ def tail(self):
+ self.kml.pr('\n</gx:Tour>')
+
+class Playlist():
+ def __init__(self, kml):
+ self.kml = kml
+
+ def head(self):
+ self.kml.pr('\n<gx:Playlist>')
+
+ def tail(self):
+ self.kml.wait(1)
+ self.kml.pr('\n</gx:Playlist>')
+
+class FlyTo():
+ def __init__(self, kml):
+ self.kml = kml
+
+ def head(self, dur, smooth):
+ self.kml.pr('<gx:FlyTo>')
+ self.kml.pr('<gx:duration>{}</gx:duration>'.format(dur))
+ self.kml.pr('<gx:flyToMode>{}</gx:flyToMode>'.format('smooth' if smooth else 'bounce'))
+
+ def tail(self):
+ self.kml.pr('\n</gx:FlyTo>')
+
+class LookAt():
+ def __init__(self, kml):
+ self.kml = kml
+
+ def run(self, long,lat,alt,head,tilt,range):
+ self.kml.pr('\n<LookAt>')
+ self.kml.pr('<latitude>{}</latitude>'.format(lat))
+ self.kml.pr('<longitude>{}</longitude>'.format(long))
+ self.kml.pr('<altitude>{}</altitude>'.format(alt))
+ self.kml.pr('<heading>{}</heading>'.format(head))
+ self.kml.pr('<tilt>{}</tilt>'.format(tilt))
+ self.kml.pr('<range>{}</range>'.format(range))
+ self.kml.pr('<altitudeMode>relativeToGround</altitudeMode>')
+ self.kml.pr('</LookAt>')
+
+class Camera():
+ def __init__(self, kml):
+ self.kml = kml
+
+ def run(self,long,lat,alt,head,tilt,roll):
+ self.kml.pr('<Camera>')
+ self.kml.pr('<latitude>{}</latitude>'.format(lat))
+ self.kml.pr('<longitude>{}</longitude>'.format(long))
+ self.kml.pr('<altitude>{}</altitude>'.format(alt))
+ self.kml.pr('<heading>{}</heading>'.format(head))
+ self.kml.pr('<tilt>{}</tilt>'.format(tilt))
+ self.kml.pr('<roll>{}</roll>'.format(roll))
+ self.kml.pr('<altitudeMode>relativeToSeaFloor</altitudeMode>')
+ self.kml.pr('</Camera>')
+
+ def runL(self, long, lat, alt, head, tilt, range, roll):
+ # dostává parametry LookAt, které konvertuje na parametry Camera tak, aby pohled byl stejný
+ dLO, dLA, Z = l2c(lat, head, tilt, range)
+ self.run(long + dLO, lat + dLA, Z, head, tilt, roll)
+
+class Placemark():
+ def __init__(self, kml):
+ self.kml = kml
+
+ def head(self, fn):
+ self.kml.pr('<Placemark>')
+ self.kml.pr('<name>{}</name>'.format(fn))
+ self.kml.pr('<visibility>0</visibility>')
+ self.kml.pr('<styleUrl>#PIN_YELLOW</styleUrl>')
+
+ def tail(self):
+ self.kml.pr('\n</Placemark>')
+
+class SpeedAdjust():
+ keys = ['none', 'linear', 'parabolic', 'tangential', 'exponential']
+ abrv = {'none':'none', 'linear':'lin', 'parabolic':'par', 'tangential':'tang', 'exponential':'exp'}
+
+ def __init__(self, const, koef, steps, config):
+ self.slowdowns = {'none':self.Const, 'linear':self.Linear, 'parabolic':self.Parabolic, 'tangential':self.Tangent, 'exponential':self.Exponential}
+ self.const = const
+ self.koef = koef
+ self.steps = steps
+ self.c = config
+
+ def phase(self):
+ return 1 - self.c.xi / self.c.x0.val
+
+ class Const():
+ p = 1 # empirická konstanta
+ def __init__(self, sa):
+ self.sa = sa
+ def koef(self):
+ return self.p / self.sa.const
+
+ class Linear():
+ p = 2 # empirická konstanta
+ def __init__(self, sa):
+ self.sa = sa
+ def koef(self):
+ return self.p * self.sa.koef * self.sa.phase() / self.sa.const
+
+ class Parabolic():
+ p = 2 # empirická konstanta
+ def __init__(self, sa):
+ self.sa = sa
+ def koef(self):
+ return self.p * pow(self.sa.koef * self.sa.phase(), 2) / self.sa.const
+
+ class Tangent():
+ p = 1 # empirická konstanta
+ def __init__(self, sa):
+ self.sa = sa
+ def koef(self):
+ margin = atan(self.sa.koef) # < pi/2
+ return (1 + self.p * tan(self.sa.phase() * margin)) / self.sa.const
+
+ class Exponential():
+ p = 1 # empirická konstanta
+ def __init__(self, sa):
+ self.sa = sa
+ def koef(self):
+ return pow(e, self.p * self.sa.koef * self.sa.phase()) / self.sa.const
+
+def canonGeodetic(a):
+ if(a > 360 or a < -360): a = a % 360
+ if(a > 180): a = a - 360
+ if(a < -180): a = a + 360
+ return a
+
+def can360(a360):
+ if(a360 < 0): a360 = a360 + 360
+ elif(a360 > 360): a360 = a360 - 360
+ return a360
+
+def can180(a180):
+ if(a180 < -180): a180 = a180 + 360
+ elif(a180 > 180): a180 = a180 - 360
+ return a180
+
+def l2c(lat, head, tilt, range):
+ RZ = 6378000
+ RL = RZ * cos(radians(lat))
+ Hc = can360(head + 180)
+ Z = range * cos(radians(tilt))
+ d = sqrt(pow(range,2) - pow(Z,2))
+ dLA = degrees(atan(d * cos(radians(Hc)) / RZ))
+ dLO = degrees(atan(d * sin(radians(Hc)) / RL))
+ return dLO, dLA, Z
+
+def deb(s):
+ print('+++ {}'.format(s), file=sys.stderr)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/kml/kmlcgi.py Mon May 18 08:48:51 2020 +0200
@@ -0,0 +1,30 @@
+#!/usr/bin/python3
+# coding=utf8
+
+import sys
+import os
+import time
+import config
+import hh_http
+import flyby
+from kml import deb
+
+# for s in ('PYTHONIOENCODING', 'LC_ALL'):
+# if s in os.environ:
+# deb(os.environ[s])
+# for s in os.environ:
+# deb('ENV[{}]={}'.format(s, os.environ[s]))
+
+if(not 'HTTP_HOST' in os.environ):
+ sys.exit(1)
+c = config.Config()
+h = hh_http.Http(c)
+fl = flyby.Flyby(c)
+if c.configReq: # on config request (...kml...) configure tour
+ if h.parsehttp(''): # syntax OK
+ fl.tour() # generate Google Earth tour
+ h.sendform(confirm=True)
+ else:
+ h.sendform(confirm=False)
+elif c.dnldReq: # on download request (...flyby...) send KML-file
+ h.sendfile(c.kmlfile)
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/kml/targets.py Mon May 18 08:48:51 2020 +0200
@@ -0,0 +1,20 @@
+class Hradčany():
+ name = 'Hradčany'
+ lat = 50.0908833
+ long = 14.4005364
+
+class Onekotan():
+ name = 'Onekotan'
+ lat = 49.351015
+ long = 154.708890
+
+class Memento():
+ name = 'memento mori'
+ lat = 50.0947447
+ long = 14.4159806
+
+class Target():
+ def __init__(self,name,lat,long):
+ self.name = name
+ self.lat = float(lat)
+ self.long = float(long)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/loxodroma.py Mon May 18 08:48:51 2020 +0200
@@ -0,0 +1,66 @@
+#!/usr/bin/python3
+# coding=utf8
+
+import sys, math
+from kml import *
+
+fn = "loxodroma"
+
+long = 0 # výchozí geodetická délka - stupně
+longStep = 5
+maxSteps = 9999
+lat = 87 # výchozí geodetická šířka - stupně
+minPoleDiff = 1 # minimální vzdálenost od pólu - stupně
+R = 6378 * 1000 # zemský poloměr v metrech
+azim = 105
+tilt = 60
+range = 4800 * 1000 # metry
+speed = 1000 * 1000 # m/s rychlost přesunu pohledu
+durMin = 0.1 # secs minimální doba kroku
+durMax = 1 # secs maximální doba kroku
+
+def loxClong():
+ azimR = math.radians(azim)
+ latR = math.radians(lat)
+ longStepR = math.radians(longStep)
+ latNR = math.asin(math.tanh(longStepR / math.tan(azimR) + math.atanh(math.sin(latR))))
+ latN = math.degrees(latNR)
+ longN = canonGeodetic(long + longStep)
+ move = R * math.fabs(latNR - latR) / math.cos(azimR) # délka posunu na povrchu koule v metrech
+ dur = math.fabs(move) / speed # doba přeletu
+ if(dur < durMin): dur = durMin
+ elif(dur > durMax): dur = durMax
+ return (longN, latN, dur, move)
+
+def list():
+ global long, lat
+ k = 0
+ while((90 - math.fabs(lat)) >= minPoleDiff and k < maxSteps):
+ (longN, latN, dur, move) = loxClong()
+ print('{}\t{}\t{}\t{}'.format(k,longN,latN, move))
+ long = longN
+ lat = latN
+ k = k + 1
+
+def run():
+ global long, lat
+ k = 0
+
+ FlyTo.head(5, False)
+ LookAt.run(long, lat, 0, azim, tilt, range)
+ FlyTo.tail()
+
+ while((90 - math.fabs(lat)) >= minPoleDiff and k < maxSteps):
+ (longN, latN, dur, move) = loxClong()
+ FlyTo.head(dur, True)
+ comm('k={}, long={}, lat={}, longN={}, latN={}, move={}'.format(str(k), str(long), str(lat), str(longN), str(latN), str(move)))
+ k = k + 1
+ LookAt.run(longN, latN, 0, azim, tilt, range)
+ FlyTo.tail()
+ long = longN
+ lat = latN
+
+# list()
+tourProlog(fn)
+run()
+tourEpilog()