-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcreate_traj_kml.py
executable file
·341 lines (281 loc) · 11.6 KB
/
create_traj_kml.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# pylint: disable=trailing-whitespace,bad-whitespace,invalid-name
# pylint: disable=anomalous-backslash-in-string,bad-continuation
# pylint: disable=multiple-statements,redefined-outer-name,global-statement
"""
FILE: create_traj_kml.py
DATE: 16 Sep 2020
AUTH: G. E. Deschaines
PROG: Creates trajectory KML file for display with Google Earth.
DESC: Given traj3D version and name of input namelist file,
this program reads associated traj3D case input and
output files to create KML trajectory file containing
following sections.
HEADER:
- Open kml tag
- Open Document tag
- Label, Line and Poly Style tags
- Open Folder tag
- Open Placemark for trajectory LineString
- Open coordinates tag
COORDS:
- lines of CSV for longitude, latitude & height
FOOTER:
- Close coordinates tag
- Close Placemark for trajectory LineString
- Placemark for trajectory launch point
- Placemark for trajectory maximum altitude point
- Placemark for trajectory impact point
- Placemark for great circle ground path
- Close Folder tag
- Close Document tag
- CLose kml tag
The following traj3D case namelist input and output files
are assumed to exist for the given version 'vers' and
namelist input .txt file with 'name'.
- namelist input: ./txt/traj3D{vers}_{name}.txt
- standard output: ./out/traj3D{vers}_{name}.out
- geodesic data output: ./dat/traj3D{vers}_geod_{name}.dat
The created KML file will be:
./kml/traj3D{vers}_traj_{name}.kml
using following trajectory KML header template, folder
description and footer template files.
- ./kml/traj_header.kml
- ./kml/traj_folder_desc_{name}.kml
- ./kml/traj_footer.kml
"""
import sys
from math import pi, asin, atan2, sin, cos
try:
import numpy as np
except ImportError:
print("* Error: NumPy required.")
print(" Suggest installing the SciPy stack.")
sys.exit()
# Units of Measure Conversion Constants
RPD = pi/180.0 # radians per degree
DPR = 180.0/pi # degrees per radian
MPFT = 0.3048 # meters per foot
MPNM = 1853.184 # meters per nautical mile
def aviation_bearing(latA,lonA,latB,lonB):
""" Assumes latitudes and longitudes given in radians.
"""
dlon = lonB - lonA
azd = atan2(sin(dlon)*cos(latB),\
cos(latA)*sin(latB)-sin(latA)*cos(latB)*cos(dlon))*DPR
azd = np.mod(azd+360.0, 360.0)
return azd
def survey_coords(lat0, lon0, az, dst):
""" Assumes latitude, longitude and bearing given in radians,
distance in meters.
"""
Ro = 6371008.8 # mean radius of earth (meters)
thto = dst/Ro # arc distance (radians)
lat1 = asin(sin(thto)*cos(lat0)*cos(az) + cos(thto)*sin(lat0))
lon1 = lon0 + atan2(sin(az)*sin(thto)*cos(lat0), cos(thto)-sin(lat0)*sin(lat1))
return (lat1, lon1)
if __name__ == "__main__":
# Check arguments for version and input namelist name.
name = ''
if len(sys.argv) > 2:
vers = sys.argv[1]
name = sys.argv[2]
else:
print("usage: create_kml [0|1] name")
print("where: [0|1] - traj3D executable version.")
print(" name - name of input namelist .txt file.")
exit()
xname = 'traj3D' + vers
# Open traj3D namelist input text file.
ipath = './txt/' + name + '.txt'
try:
txt_file = open(ipath, 'r')
except OSError:
print('open error for', ipath)
exit()
# Read case description from namelist file.
lines = txt_file.readlines()
txt_file.close()
sdesc = lines[0].lstrip().rstrip()
# Read TFINAL value to determine trajectory mode (Observed or Inertial).
tfinal_idx = lines[2].find('TFINAL')
if tfinal_idx > -1:
equal_idx = lines[2].find('=', tfinal_idx)+1
comma_idx = lines[2].find(',', tfinal_idx)
tfinal = float(lines[2][equal_idx:comma_idx])
if tfinal > -1.0:
if tfinal > 0.0:
smode = 'Inertial'
sevnt = 'Impact Time - __TOFHRS__ hours'
color = 'Red'
else:
smode = 'Relative'
sevnt = 'Launch and Impact Time'
color = 'Purple'
else:
smode = 'Observed'
sevnt = 'Launch Time + __TOFHRS__ hours'
color = 'Green'
else:
smode = 'Observed'
sevnt = 'Launch Time + __TOFHRS__ hours'
color = 'Green'
# Read ROTOPT value to determine trajectory color (Observed, Inertial or Non-rotating).
rotopt_idx = lines[6].find('ROTOPT')
if rotopt_idx > -1:
equal_idx = lines[6].find('=', rotopt_idx)+1
comma_idx = lines[6].find(',', rotopt_idx)
rotopt = float(lines[6][equal_idx:comma_idx])
if rotopt == 0.0:
smode = 'Non-rotating'
sevnt = 'Launch and Impact Time'
color = 'Blue'
# Read GAMREL value.
gamrel_idx = lines[3].find('GAMREL')
if gamrel_idx > -1:
equal_idx = lines[3].find('=', gamrel_idx)+1
comma_idx = lines[3].find(',', gamrel_idx)
el0d = float(lines[3][equal_idx:comma_idx])
else:
el0d = 0.0
# Open traj3D standard output file.
opath = './out/' + xname + '_' + name + '.out'
try:
out_file = open(opath, 'r')
except OSError:
print('open error for', opath)
exit()
# Read trajectory final state values from standard output file.
lines = out_file.readlines()
out_file.close()
[stofsec, svrfps, saltft, slatdeg, _] = lines[-6][1:].split(None,4)
[ sgsec, smach, srngnm, slondeg, _] = lines[-5][1:].split(None,4)
[ sppsf, sazdeg, sgamma, _] = lines[-4][1:].split(None,3)
tofsec = float(stofsec[0:]) # time of flight (seconds)
tofhrs = tofsec/3600.0 # time of flight (hours)
vrfps = float(svrfps[0:]) # relative velocity (feet per second)
vrmps = vrfps*MPFT # relative velocity (meters per second)
altft = float(saltft[0:]) # altitude (feet)
altm = altft*MPFT # altitude (meters)
rngnm = float(srngnm[0:]) # ground range (nautical miles)
rngkm = rngnm*MPNM/1000.0 # ground range (kilometers)
azdeg = float(sazdeg[0:]) # flight path heading (degrees)
gamma = float(sgamma[0:]) # flight path pitch angle (degrees)
period_idx = slatdeg.find('.')
latdeg = float(slatdeg[0:period_idx+3]) # latitude (degrees)
period_idx = slondeg.find('.')
londeg = float(slondeg[0:period_idx+3]) # longitude (degrees)
if londeg > 180.0: londeg = londeg - 360.0
if londeg < -180.0: londeg = londeg + 360.0
# Open traj3D geodesic data output file.
dpath = './dat/' + xname + '_geod_' + name + '.dat'
try:
dat_file = open(dpath, 'r')
except OSError:
print('open error for', dpath)
exit()
# Read lines of geodesic data and store in lists
# of latitude, longitude and height values.
lines = dat_file.readlines()
dat_file.close()
n = len(lines)
flon = np.ndarray(n, dtype=float)
flat = np.ndarray(n, dtype=float)
ihgt = np.ndarray(n, dtype=int)
for i in range(n):
[slon, slat, shgt] = lines[i].split(',')
flon[i] = float(slon)
flat[i] = float(slat)
ihgt[i] = int(shgt)
m = np.argmax(ihgt)
# Calculate bearings at launch, midpoint and impact.
az0d = aviation_bearing(flat[0]*RPD,flon[0]*RPD,flat[1]*RPD,flon[1]*RPD)
azMd = aviation_bearing(flat[0]*RPD,flon[0]*RPD,flat[m]*RPD,flon[m]*RPD)
azNd = aviation_bearing(flat[-1]*RPD,flon[-1]*RPD,flat[-2]*RPD,flon[-2]*RPD)
# Generate coordinates of relative velocity horizontal component at impact.
(latZr, lonZr) = survey_coords(flat[-1]*RPD,flon[-1]*RPD,azdeg*RPD,1000.0)
latZd = latZr*DPR
lonZd = lonZr*DPR
# Read trajectory header KML file.
kml_file = open('./kml/traj_folder_desc_' + name + '.kml', 'r')
folder_kml = kml_file.read()
kml_file.close()
# Read trajectory header KML file.
kml_file = open('./kml/traj_header.kml', 'r')
header_kml = kml_file.read()
kml_file.close()
# Read trajectory footer KML file.
kml_file = open('./kml/traj_footer.kml', 'r')
footer_kml = kml_file.read()
kml_file.close()
# Replace header and footer key values with those read
# from traj3D input namelist text file, standard output
# and geodesic data output files.
srngkm = "%.3f" % rngkm
stofhrs = "%.4f" % tofhrs
slon0 = "%.6f" % flon[0]
slat0 = "%.6f" % flat[0]
shgt0 = "%d" % ihgt[0]
saz0d = "%.2f" % az0d
sel0d = "%.2f" % el0d
slonM = "%.6f" % flon[m]
slatM = "%.6f" % flat[m]
shgtM = "%d" % ihgt[m]
shgtMkm = "%.3f" % (float(ihgt[m])/1000.0)
sazMd = "%.2f" % azMd
slonN = "%.6f" % flon[n-1]
slatN = "%.6f" % flat[n-1]
shgtN = "%d" % ihgt[n-1]
sazNd = "%.2f" % azNd
svrel = "%.2f" % vrfps
svazim = "%.2f" % azdeg
svelev = "%.2f" % gamma
slonZ = "%.6f" % lonZd
slatZ = "%.6f" % latZd
header_kml = header_kml.replace('__FLDRDESC__', folder_kml)
header_kml = header_kml.replace('__VERS__', vers)
header_kml = header_kml.replace('__DESC__', sdesc)
header_kml = header_kml.replace('__MODE__', smode)
header_kml = header_kml.replace('__RNGKM__', srngkm)
header_kml = header_kml.replace('__TOFHRS__', stofhrs)
header_kml = header_kml.replace('__LON0__', slon0)
header_kml = header_kml.replace('__LAT0__', slat0)
header_kml = header_kml.replace('__AZ0__', saz0d)
header_kml = header_kml.replace('__EL0__', sel0d)
header_kml = header_kml.replace('__COLOR__', color)
footer_kml = footer_kml.replace('__DESC__', sdesc)
footer_kml = footer_kml.replace('__MODE__', smode)
footer_kml = footer_kml.replace('__EVNT__', sevnt)
footer_kml = footer_kml.replace('__TOFHRS__', stofhrs)
footer_kml = footer_kml.replace('__LON0__', slon0)
footer_kml = footer_kml.replace('__LAT0__', slat0)
footer_kml = footer_kml.replace('__HGT0__', shgt0)
footer_kml = footer_kml.replace('__AZ0__', saz0d)
footer_kml = footer_kml.replace('__HGTMKM__', shgtMkm)
footer_kml = footer_kml.replace('__LONM__', slonM)
footer_kml = footer_kml.replace('__LATM__', slatM)
footer_kml = footer_kml.replace('__HGTM__', shgtM)
footer_kml = footer_kml.replace('__AZM__', sazMd)
footer_kml = footer_kml.replace('__LONN__', slonN)
footer_kml = footer_kml.replace('__LATN__', slatN)
footer_kml = footer_kml.replace('__HGTN__', shgtN)
footer_kml = footer_kml.replace('__AZN__', sazNd)
footer_kml = footer_kml.replace('__COLOR__', color)
footer_kml = footer_kml.replace('__VREL__', svrel)
footer_kml = footer_kml.replace('__VAZIM__', svazim)
footer_kml = footer_kml.replace('__VELEV__', svelev)
footer_kml = footer_kml.replace('__LONZ__', slonZ)
footer_kml = footer_kml.replace('__LATZ__', slatZ)
# Create trajectory KML file.
kpath = './kml/' + xname + '_traj_' + name + '.kml'
kml_file = open(kpath, 'w')
# Write header section
kml_file.write(header_kml)
# Write coords section.
for i in range(n):
line = " %.6f,%.6f,%d\n" % (flon[i],flat[i],ihgt[i])
kml_file.write(line)
# Write footer section.
kml_file.write(footer_kml)
kml_file.close()