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