|
1 import sys |
|
2 import xml.sax.saxutils |
|
3 from math import * |
|
4 |
|
5 class Kml(): |
|
6 def __init__(self): |
|
7 self.out = sys.stdout |
|
8 self.placemark = Placemark(self) |
|
9 self.tour = Tour(self) |
|
10 self.playlist = Playlist(self) |
|
11 self.flyto = FlyTo(self) |
|
12 self.lookat = LookAt(self) |
|
13 self.camera = Camera(self) |
|
14 self.document = Document(self) |
|
15 self.folder = Folder(self) |
|
16 self.xml = Xml(self) |
|
17 |
|
18 def documentProlog(self, fn): |
|
19 self.xml.head() |
|
20 self.document.head(fn) |
|
21 |
|
22 def documentEpilog(self): |
|
23 self.document.tail() |
|
24 self.xml.tail() |
|
25 |
|
26 def folderProlog(self, fn): |
|
27 self.folder.head(fn) |
|
28 |
|
29 def folderEpilog(self): |
|
30 self.folder.tail() |
|
31 |
|
32 def tourProlog(self, fn): |
|
33 self.tour.head(fn) |
|
34 self.playlist.head() |
|
35 |
|
36 def tourEpilog(self): |
|
37 self.playlist.tail() |
|
38 self.tour.tail() |
|
39 |
|
40 def placemarkProlog(self, fn): |
|
41 self.xml.head() |
|
42 self.placemark.head(fn) |
|
43 |
|
44 def placemarkEpilog(self): |
|
45 self.placemark.tail() |
|
46 self.xml.tail() |
|
47 |
|
48 def urlPlacemark(self, url, path): |
|
49 # ref = '<a href="http://{}/index.py">{}</a>'.format(qualname, qualname) |
|
50 ref = '<a href="{}">{}</a>'.format(url, path) |
|
51 p = self.pr |
|
52 p('<Placemark>') |
|
53 p('<name>{ref}</name>'.format(ref = xml.sax.saxutils.escape(ref))) |
|
54 p('</Placemark>') |
|
55 |
|
56 def wait(self, dur): |
|
57 self.pr('\n<gx:Wait><gx:duration>{}</gx:duration></gx:Wait>'.format(dur)) |
|
58 |
|
59 def comm(self, c): |
|
60 self.pr('\n<!-- {} -->'.format(c)) |
|
61 |
|
62 def pr(self, s): |
|
63 print(s, file=self.out) |
|
64 |
|
65 class Xml(): |
|
66 def __init__(self, kml): |
|
67 self.kml = kml |
|
68 |
|
69 def head(self): |
|
70 self.kml.pr('<?xml version="1.0" encoding="UTF-8"?>') |
|
71 self.kml.pr('<kml') |
|
72 self.kml.pr('xmlns="http://www.opengis.net/kml/2.2"') |
|
73 self.kml.pr('xmlns:gx="http://www.google.com/kml/ext/2.2"') |
|
74 self.kml.pr('>') |
|
75 |
|
76 def tail(self): |
|
77 self.kml.pr('\n</kml>') |
|
78 |
|
79 class Document(): |
|
80 def __init__(self, kml): |
|
81 self.kml = kml |
|
82 |
|
83 def head(self, fn): |
|
84 self.kml.pr('<Document>') |
|
85 self.kml.pr('<name>{}</name>'.format(fn)) |
|
86 self.kml.pr('<open>1</open>') |
|
87 |
|
88 def tail(self): |
|
89 self.kml.pr('\n</Document>') |
|
90 |
|
91 |
|
92 class Folder(): |
|
93 def __init__(self, kml): |
|
94 self.kml = kml |
|
95 |
|
96 def head(self, fn): |
|
97 self.kml.pr('<Folder>') |
|
98 self.kml.pr('<name>{}</name>'.format(fn)) |
|
99 self.kml.pr('<open>1</open>') |
|
100 |
|
101 def tail(self): |
|
102 self.kml.pr('\n</Folder>') |
|
103 |
|
104 class Tour(): |
|
105 def __init__(self, kml): |
|
106 self.kml = kml |
|
107 |
|
108 def head(self, fn): |
|
109 self.kml.pr('\n<gx:Tour>') |
|
110 self.kml.pr('<name>{}</name>'.format(fn)) |
|
111 |
|
112 def tail(self): |
|
113 self.kml.pr('\n</gx:Tour>') |
|
114 |
|
115 class Playlist(): |
|
116 def __init__(self, kml): |
|
117 self.kml = kml |
|
118 |
|
119 def head(self): |
|
120 self.kml.pr('\n<gx:Playlist>') |
|
121 |
|
122 def tail(self): |
|
123 self.kml.wait(1) |
|
124 self.kml.pr('\n</gx:Playlist>') |
|
125 |
|
126 class FlyTo(): |
|
127 def __init__(self, kml): |
|
128 self.kml = kml |
|
129 |
|
130 def head(self, dur, smooth): |
|
131 self.kml.pr('<gx:FlyTo>') |
|
132 self.kml.pr('<gx:duration>{}</gx:duration>'.format(dur)) |
|
133 self.kml.pr('<gx:flyToMode>{}</gx:flyToMode>'.format('smooth' if smooth else 'bounce')) |
|
134 |
|
135 def tail(self): |
|
136 self.kml.pr('\n</gx:FlyTo>') |
|
137 |
|
138 class LookAt(): |
|
139 def __init__(self, kml): |
|
140 self.kml = kml |
|
141 |
|
142 def run(self, long,lat,alt,head,tilt,range): |
|
143 self.kml.pr('\n<LookAt>') |
|
144 self.kml.pr('<latitude>{}</latitude>'.format(lat)) |
|
145 self.kml.pr('<longitude>{}</longitude>'.format(long)) |
|
146 self.kml.pr('<altitude>{}</altitude>'.format(alt)) |
|
147 self.kml.pr('<heading>{}</heading>'.format(head)) |
|
148 self.kml.pr('<tilt>{}</tilt>'.format(tilt)) |
|
149 self.kml.pr('<range>{}</range>'.format(range)) |
|
150 self.kml.pr('<altitudeMode>relativeToGround</altitudeMode>') |
|
151 self.kml.pr('</LookAt>') |
|
152 |
|
153 class Camera(): |
|
154 def __init__(self, kml): |
|
155 self.kml = kml |
|
156 |
|
157 def run(self,long,lat,alt,head,tilt,roll): |
|
158 self.kml.pr('<Camera>') |
|
159 self.kml.pr('<latitude>{}</latitude>'.format(lat)) |
|
160 self.kml.pr('<longitude>{}</longitude>'.format(long)) |
|
161 self.kml.pr('<altitude>{}</altitude>'.format(alt)) |
|
162 self.kml.pr('<heading>{}</heading>'.format(head)) |
|
163 self.kml.pr('<tilt>{}</tilt>'.format(tilt)) |
|
164 self.kml.pr('<roll>{}</roll>'.format(roll)) |
|
165 self.kml.pr('<altitudeMode>relativeToSeaFloor</altitudeMode>') |
|
166 self.kml.pr('</Camera>') |
|
167 |
|
168 def runL(self, long, lat, alt, head, tilt, range, roll): |
|
169 # dostává parametry LookAt, které konvertuje na parametry Camera tak, aby pohled byl stejný |
|
170 dLO, dLA, Z = l2c(lat, head, tilt, range) |
|
171 self.run(long + dLO, lat + dLA, Z, head, tilt, roll) |
|
172 |
|
173 class Placemark(): |
|
174 def __init__(self, kml): |
|
175 self.kml = kml |
|
176 |
|
177 def head(self, fn): |
|
178 self.kml.pr('<Placemark>') |
|
179 self.kml.pr('<name>{}</name>'.format(fn)) |
|
180 self.kml.pr('<visibility>0</visibility>') |
|
181 self.kml.pr('<styleUrl>#PIN_YELLOW</styleUrl>') |
|
182 |
|
183 def tail(self): |
|
184 self.kml.pr('\n</Placemark>') |
|
185 |
|
186 class SpeedAdjust(): |
|
187 keys = ['none', 'linear', 'parabolic', 'tangential', 'exponential'] |
|
188 abrv = {'none':'none', 'linear':'lin', 'parabolic':'par', 'tangential':'tang', 'exponential':'exp'} |
|
189 |
|
190 def __init__(self, const, koef, steps, config): |
|
191 self.slowdowns = {'none':self.Const, 'linear':self.Linear, 'parabolic':self.Parabolic, 'tangential':self.Tangent, 'exponential':self.Exponential} |
|
192 self.const = const |
|
193 self.koef = koef |
|
194 self.steps = steps |
|
195 self.c = config |
|
196 |
|
197 def phase(self): |
|
198 return 1 - self.c.xi / self.c.x0.val |
|
199 |
|
200 class Const(): |
|
201 p = 1 # empirická konstanta |
|
202 def __init__(self, sa): |
|
203 self.sa = sa |
|
204 def koef(self): |
|
205 return self.p / self.sa.const |
|
206 |
|
207 class Linear(): |
|
208 p = 2 # empirická konstanta |
|
209 def __init__(self, sa): |
|
210 self.sa = sa |
|
211 def koef(self): |
|
212 return self.p * self.sa.koef * self.sa.phase() / self.sa.const |
|
213 |
|
214 class Parabolic(): |
|
215 p = 2 # empirická konstanta |
|
216 def __init__(self, sa): |
|
217 self.sa = sa |
|
218 def koef(self): |
|
219 return self.p * pow(self.sa.koef * self.sa.phase(), 2) / self.sa.const |
|
220 |
|
221 class Tangent(): |
|
222 p = 1 # empirická konstanta |
|
223 def __init__(self, sa): |
|
224 self.sa = sa |
|
225 def koef(self): |
|
226 margin = atan(self.sa.koef) # < pi/2 |
|
227 return (1 + self.p * tan(self.sa.phase() * margin)) / self.sa.const |
|
228 |
|
229 class Exponential(): |
|
230 p = 1 # empirická konstanta |
|
231 def __init__(self, sa): |
|
232 self.sa = sa |
|
233 def koef(self): |
|
234 return pow(e, self.p * self.sa.koef * self.sa.phase()) / self.sa.const |
|
235 |
|
236 def canonGeodetic(a): |
|
237 if(a > 360 or a < -360): a = a % 360 |
|
238 if(a > 180): a = a - 360 |
|
239 if(a < -180): a = a + 360 |
|
240 return a |
|
241 |
|
242 def can360(a360): |
|
243 if(a360 < 0): a360 = a360 + 360 |
|
244 elif(a360 > 360): a360 = a360 - 360 |
|
245 return a360 |
|
246 |
|
247 def can180(a180): |
|
248 if(a180 < -180): a180 = a180 + 360 |
|
249 elif(a180 > 180): a180 = a180 - 360 |
|
250 return a180 |
|
251 |
|
252 def l2c(lat, head, tilt, range): |
|
253 RZ = 6378000 |
|
254 RL = RZ * cos(radians(lat)) |
|
255 Hc = can360(head + 180) |
|
256 Z = range * cos(radians(tilt)) |
|
257 d = sqrt(pow(range,2) - pow(Z,2)) |
|
258 dLA = degrees(atan(d * cos(radians(Hc)) / RZ)) |
|
259 dLO = degrees(atan(d * sin(radians(Hc)) / RL)) |
|
260 return dLO, dLA, Z |
|
261 |
|
262 def deb(s): |
|
263 print('+++ {}'.format(s), file=sys.stderr) |