diff -r 000000000000 -r bb616224c02a kml/flyby.py --- /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()