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