--- /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()