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