kml/flyby.py
changeset 0 bb616224c02a
equal deleted inserted replaced
-1:000000000000 0:bb616224c02a
       
     1 # coding=utf8
       
     2 
       
     3 import targets
       
     4 import config
       
     5 from kml import *
       
     6 import sys
       
     7 import os
       
     8 import time
       
     9 from math import *
       
    10 
       
    11 """
       
    12 # -----------------------------------------------------------------------------------------------------------
       
    13 # pokusy s KML v Googleearth
       
    14 #   ● program generuje položky LookAt tak, aby vznikl pohyb kamery jako symetrický průlet kolem cílového bodu,
       
    15 #		na který kamera po celou dobu letu hledí
       
    16 #   ● cílový bod leží vždy v počátku lokálních souřadnic letu
       
    17 #   ● zadávané souřadnice výchozího bodu a průletu jsou lokální souřadnice (v metrech) vzhledem k cílovému bodu
       
    18 #   ● výchozí bod je X0>=0, Y0, Z0>minZ>0; pro X0=0 se vytváří jen jediný LookAt
       
    19 #   ● bod průletu je X1=0, Y1, Z1>minZ>0
       
    20 #   ● 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
       
    21 #   ● pro Z0=Z1 probíhá let ve vodorovné rovině, pro Y0=Y1 ve svislé rovině rovnoběžné s X
       
    22 #   ● zadávaný exponent paraboly exp>0; pro exp=1 přejde parabola do polopřímek
       
    23 #   ● zadávané geodetické souřadnice cílového bodu a azimut kamery na startu uchycují lokální soustavu do geodetických souřadnic,
       
    24 #		výška cílového bodu je vždy 0 nad terénem
       
    25 #   ● v modulu kml jsou  dispozici geo-souřadnice několika konkrétních bodů
       
    26 #   ● zadává se počet kroků (LookAt), které se generují; propočítávají se body z 1.poloviny letu,
       
    27 #		body 2.poloviny jsou symetrické (mají symetrický lokální azimut)
       
    28 #   ● doba přeletu v každém kroku se určuje podle empirických pravidel:
       
    29 #		1. podle výšky kamery: rychlost v m/s je číselně rovna střední výšce v m
       
    30 #		2. podle úhlu otočení v kroku: rychlost taková, aby otáčení vycházelo cca 20°/s
       
    31 #		** volí se nižší hodnota rychlosti z obou pravidel
       
    32 #   ● průběh rychlosti se může zadat jako nelineární se zpomalením v průletu;
       
    33 #		- k dispozici je 5 podtříd SpeedAdjust od konstatní po exponenciální
       
    34 #		- každá třída je parametrizována váhovými koeficienty pro konstatntní a proměnnou složku rychlosti
       
    35 #   ● Googleearth při změnách azimutu mezi dvěma LookAt většími než empirických dHmax nepohybuje kamerou lineárně,
       
    36 #		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
       
    37 #   ● pro každý krok se vypočítává lokální azimut "polohy" kamery (Ri), z něhož se určuje geo-azimut "pohledu" kamery
       
    38 #		(lokální azimut 0 leží na kladné poloose X)
       
    39 #   ● 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°
       
    40 #   ● když chci obrátit směr pohybu kamery po dráze, obrátím znaménka Y0 a Y1
       
    41 # 		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
       
    42 #   ● 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)
       
    43 #   ● výstup ve tvaru Tour v KML Documentu jde na sys.stdout
       
    44 #
       
    45 # formáty GEO-souřadnic:
       
    46 # 	50.1009147N, 14.4057506E		mapy.cz
       
    47 # 	50.765779°   15.050950°			google earth
       
    48 # 	50°02'44.9"N 14°25'52.4"E		google maps
       
    49 # 	50.045796, 14.431211
       
    50 # 	36°58′41″N 82°34′37″W			wikipedia
       
    51 # -----------------------------------------------------------------------------------------------------------
       
    52 """
       
    53 class Flyby():
       
    54     k = Kml()
       
    55 
       
    56     def __init__(self, config):
       
    57         self.c = config
       
    58 
       
    59     def pr(self, s):
       
    60         print(s, file=self.k.out)
       
    61 
       
    62     def compMove(self):
       
    63         c = self.c
       
    64         xi = c.xi
       
    65         Ri = 0
       
    66         if (c.x0.val > 0 and xi == c.x0.val) or c.x0.val == 0:
       
    67             yi, zi = c.y0.val, c.z0.val
       
    68             heading = c.h0.val
       
    69         elif(xi == 0):
       
    70             yi, zi = c.y1.val, c.z1.val
       
    71             heading = c.h1
       
    72         else:
       
    73             try: f = c.K * pow(xi, c.exp.val)
       
    74             except:
       
    75                 deb('ABEND: K={}, xi={}, exp={}'.format(c.K, xi, c.exp.val))
       
    76                 sys.stderr.close()
       
    77                 os._exit(1)
       
    78             yi = c.y1.val + f * cos(c.A)
       
    79             zi = c.z1.val + f * sin(c.A)
       
    80             Ri = degrees(atan(yi / xi))
       
    81             heading = can360(c.h0.val + c.r0 - Ri)
       
    82 
       
    83         dist = sqrt(pow(xi,2) + pow(yi,2) + pow(zi,2))
       
    84         tilt = degrees(acos(zi / dist))
       
    85 
       
    86         dX = xi - c.lastX
       
    87         dY = yi - c.lastY
       
    88         dZ = zi - c.lastZ
       
    89         dS = sqrt(pow(dX,2) + pow(dY,2) + pow(dZ,2))
       
    90         tDur = dS / pow((zi + fabs(dZ/2)), 1)					# empirické optimum: rychlost letu = výška/sec
       
    91         dH = can180(heading - c.lastH)
       
    92         rDur = fabs(dH) / c.durOpt								# empirické optimum: rychlost otáčení
       
    93         rawdur = rDur if rDur > tDur else tDur
       
    94         dur = rawdur * c.speedAdjust.koef() if c.x0.val > 0 else rawdur
       
    95 
       
    96         # self.drspeed = dS/rawdur if rawdur > 0 else -0.0		# +++
       
    97         # self.dspeed = dS/dur if dur > 0 else -0.0				# +++
       
    98         # self.dkoef = c.speedAdjust.koef()						# +++
       
    99         # self.drdur = rDur										# +++
       
   100         # self.dtdur = tDur										# +++
       
   101 
       
   102         c.yi, c.zi = yi, zi
       
   103 
       
   104         s = ('Xi={:.3f}, dX={:.3f}, Yi={:.1f}, dY={:.3f}, Zi={:.1f}, dZ={:.3f}, dS={:.3f}, Ri={:.3f}, dist={:.1f}, tilt={:.1f}, '
       
   105              .format(xi, dX, yi, dY, zi, dZ, dS, Ri, dist, tilt),
       
   106             'heading={:.3f}, dH={:.3f}, dur={:.3f}'.format(heading, dH, dur))
       
   107 
       
   108         return (s, dur, dist, tilt, heading)
       
   109 
       
   110     def compStep(self):
       
   111         c = self.c
       
   112         (s, dur, dist, tilt, heading) = self.compMove()
       
   113         dH = can180(heading - c.lastH)
       
   114         bad = fabs(dH) > c.dHmax
       
   115         if(bad and fabs(c.dX) > c.dXmin):
       
   116             ddX = -c.dX/2
       
   117             last = bad
       
   118             found = 0
       
   119             while(fabs(dH) > 0 and fabs(dH) != c.dHmax and fabs(ddX) > c.dXmin):
       
   120                 c.dX = c.dX + ddX
       
   121                 c.xi = c.lastX + c.dX
       
   122                 (s, dur, dist, tilt, heading) = self.compMove()
       
   123                 dH = can180(heading - c.lastH)
       
   124                 bad = fabs(dH) > c.dHmax
       
   125                 if(not bad): found = c.xi
       
   126                 ddX = ddX/2 if bad == last else -ddX/2
       
   127                 last = bad
       
   128             if(fabs(c.dX) > c.xi): c.dX = -c.xi
       
   129             if(bad and found > 0):
       
   130                 c.xi = found
       
   131                 s, dur, dist, tilt, heading = self.compMove()
       
   132                 dH = can180(heading - c.lastH)
       
   133         # deb('Xi={:.3f}, i={:.3f}, koef = {:.3f}, speed={:.3f}, adj speed={:.3f}, trans dur={:.3f}, rot dur={:.3f}'
       
   134         # 	.format(c.xi, 1 - c.xi / c.x0.val, self.dkoef, self.drspeed, self.dspeed, self.dtdur, self.drdur))		# +++
       
   135         return s, dur, dist, tilt, heading, dH
       
   136 
       
   137     def compTour(self):
       
   138         c = self.c
       
   139 
       
   140         c.xi = c.x0.val
       
   141         s, dur, dist, tilt, heading, dH = self.compStep()
       
   142         self.fly(s[0]+s[1], 5, False, dist, tilt, heading)
       
   143         if(c.x0.val == 0): return
       
   144 
       
   145         c.xi = c.xi + c.dX
       
   146         while(c.xi > fabs(c.dX)):
       
   147             s, dur, dist, tilt, heading, dH = self.compStep()
       
   148             self.fly(s[0]+s[1], dur, True, dist, tilt, heading)
       
   149             c.xi = c.xi + c.dX
       
   150 
       
   151         self.k.comm('>>> střed')
       
   152         c.xi = 0
       
   153         s, dur, dist, tilt, heading, dH = self.compStep()
       
   154         if(fabs(dH) <= c.dHmax): self.fly(s[0]+s[1], dur, True, dist, tilt, heading)
       
   155         while(c.xi > c.dXmin):
       
   156             self.k.comm('>>> dotažení středu')
       
   157             c.xi = 0
       
   158             s, dur, dist, tilt, heading, dH = self.compStep()
       
   159             if(fabs(dH) <= c.dHmax): self.fly(s[0]+s[1], dur, True, dist, tilt, heading)
       
   160             else: break
       
   161         if(fabs(dH) > c.dHmax):
       
   162             self.k.comm('>>> dotočení středu')
       
   163             c.xi = 0
       
   164             s, dur, dist, tilt, heading = self.compMove()
       
   165             d = c.dHmax * dH / fabs(dH)
       
   166             h = c.lastH
       
   167             while(fabs(dH) > c.dHmax):
       
   168                 h = can360(h + d)
       
   169                 dur = fabs(d)/c.durOpt
       
   170                 s_ = s[0] + 'heading={:.3f}, dH={:.3f}, dur={:.3f}'.format(h, d, dur)
       
   171                 self.fly(s_, dur, True, dist, tilt, h)
       
   172                 dH = can180(heading - h)
       
   173             if(fabs(dH) > 0):
       
   174                 dur = fabs(dH)/c.durOpt
       
   175                 s_ = s[0] + 'heading={:.3f}, dH={:.3f}, dur={:.3f}'.format(heading, dH, dur)
       
   176                 self.fly(s_, dur, True, dist, tilt, heading)
       
   177 
       
   178         if(c.flyby):
       
   179             c = self.c
       
   180             del c.rr[0]			# středový záznam se škrtá, neopakuje se
       
   181             lastH = c.h1
       
   182             for i in c.rr:
       
   183                 nDur, dist, tilt, heading = i
       
   184                 heading = can360(2 * c.h1 - heading)			# heading je zrcadlový vůči svislé rovině headingu v průletu (H1)
       
   185                 dH = can180(heading - lastH)
       
   186                 s_ = 'dist={:.1f}, tilt={:.1f}, heading={:.3f}, dH={:.3f}, dur={:.3f}'.format(dist, tilt, heading, dH, dur)
       
   187                 self.fly(s_, dur, True, dist, tilt, heading)	# duration se bere z předchozího záznamu
       
   188                 dur = nDur
       
   189                 lastH = heading
       
   190 
       
   191         self.k.comm('sum: steps={}, duration={:.2f}'.format(c.sumSteps, c.sumDur))
       
   192 
       
   193     def step(self, dur, dist, tilt, heading):
       
   194         c = self.c
       
   195         c.lastH = heading
       
   196         c.lastX, c.lastY, c.lastZ = c.xi, c.yi, c.zi
       
   197         c.rr = [(dur, dist, tilt, heading)] + c.rr
       
   198         c.sumDur = c.sumDur + dur
       
   199         c.sumSteps = c.sumSteps + 1
       
   200 
       
   201     def fly(self, s, dur, smooth, dist, tilt, heading):
       
   202         self.step(dur, dist, tilt, heading)
       
   203         self.k.comm(s)
       
   204         self.k.flyto.head(dur, smooth)
       
   205         self.k.lookat.run(self.c.long.val, self.c.lat.val, 0, heading, tilt, dist)
       
   206         # self.k.camera.runL(c.long.val, c.lat.val, 0, heading, tilt, dist, 0)
       
   207         self.k.flyto.tail()
       
   208 
       
   209     def headcomms(self):
       
   210         c = self.c
       
   211         self.k.comm(time.asctime())
       
   212         c.confcomm = ('lat={lat}, long={long}, heading={heading}, exp={exp}, ' +
       
   213                     'flyby={flyby}, speedfactor={speedf}, slowdown={slowd}, slowdfactor={slowdf}, steps={steps}')\
       
   214                 .format(target=c.targname.val, long=c.long.val, lat=c.lat.val, heading=c.h0.val, exp=c.exp.val,
       
   215                     flyby=c.flyby.val, speedf=c.speedfact.val, slowd=c.slowdown.val, slowdf=c.slowdfact.val, steps=c.steps.val)
       
   216 
       
   217         if(c.x0.val == 0):
       
   218             c.coorcomm = 'X0,Y0,Z0={},{},{}, H0={}'.format(c.x0.val, c.y0.val, c.z0.val, c.h0.val)
       
   219         else:
       
   220             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) +
       
   221                         'A={:.3f}, H0={}, H1={:.3f}, H2={:.3f}, R0={:.3f}, R1={:.3f}'
       
   222                         .format(degrees(c.A), c.h0.val, c.h1, c.h2, c.r0, c.r1))
       
   223 
       
   224         self.k.comm(c.confcomm)
       
   225         self.k.comm(c.coorcomm)
       
   226 
       
   227     def tour(self):
       
   228         fkml = '{}.kml'.format(int(time.time())) if self.c.zipped else self.c.kmlfile
       
   229         self.k.out = open(fkml, mode='w', encoding='utf-8')
       
   230         self.k.xml.head()
       
   231         self.k.tourProlog(self.c.name.val)
       
   232         self.headcomms()
       
   233         self.compTour()
       
   234         self.k.tourEpilog()
       
   235         self.k.xml.tail()
       
   236         self.k.out.close()
       
   237         if self.c.zipped:
       
   238             fkmz = '{}.kmz'.format(self.c.kmlfn)
       
   239             if os.path.exists(fkmz):
       
   240                 os.remove(fkmz)
       
   241             from subprocess import Popen
       
   242             p = Popen(['zip', fkmz, fkml], stdout=sys.stderr)
       
   243             p.wait()