-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathannotate.py
executable file
·203 lines (150 loc) · 6.45 KB
/
annotate.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
"""
annotate
======
Tools for calculating,transforming, and retrieving coordinates for various
plot annotations.
readYaml
calcSwpLocs
rangeRingCalc
"""
import numpy as np
import yaml
def readYaml(yamlFile):
"""
Read in a YAML file containing names and locations of annotations to be
plotted. Refer to the template file for proper formatting.
Parameters
----------
yamlFile : string
Path to the YAML file.
Returns
-------
yamlObj : dict-like
YAML python object, with a structure similar to a dictionary.
"""
with open(yamlFile, 'r') as yamlIn:
yamlObj = yaml.load(yamlIn,Loader=yaml.FullLoader)
return yamlObj
def calcSwpLocs(lat,lon,hdng,radRange):
"""
Calculates the lat,lon values at the terminus of the fore and aft
TDR beams, both left and right of the plane in the horizontal.
This is used when creating the so-called "Dragonfly" for visualizing
radar coverage for a P-3 mission.
Parameters
----------
lat,lon : floats
Lat and lon of the P-3 at a given moment in time, in decimal degrees
hdng : float
Heading (direction aircraft is flying) at a given moment in time (in degrees)
radRange : float
Maximum unambiguous range of the TDR in meters.
Returns
-------
foreSwpLocs,aftSwpLocs : dicts
Dictionaries containing the left and right lat and lon values
for the fore and after TDR beams.
"""
# Sweep unambiguous range (for NOAA TDR - 2017 VSE, 47966.79 m) converted to radians
# (relative to spherical Earth, of radius 6372797.6 m)
beamDistR = radRange/6372797.6
# Calculate hdngs of both right and left (relative to motion) fore and aft sweeps
aftLeftHead = hdng - (90+20)
aftRightHead = hdng + (90+20)
foreLeftHead = hdng - (90-20)
foreRightHead = hdng + (90-20)
if aftLeftHead < 0:
aftLeftHead += 360
if aftRightHead < 0:
aftRightHead += 360
if foreLeftHead < 0:
foreLeftHead += 360
if foreRightHead < 0:
foreRightHead += 360
# Convert hdngs and coords to radians
latR = np.deg2rad(lat)
lonR = np.deg2rad(lon)
aftLeftHeadR = np.deg2rad(aftLeftHead)
aftRightHeadR = np.deg2rad(aftRightHead)
foreLeftHeadR = np.deg2rad(foreLeftHead)
foreRightHeadR = np.deg2rad(foreRightHead)
# Calculate destination coordinates and convert back to degrees
lat2aftLeftR = np.arcsin(np.sin(latR)*np.cos(beamDistR) + np.cos(latR)*np.sin(beamDistR)*np.cos(aftLeftHeadR))
lon2aftLeftR = lonR + np.arctan2(np.sin(aftLeftHeadR)*np.sin(beamDistR)*np.cos(latR), np.cos(beamDistR) - np.sin(latR)*np.sin(lat2aftLeftR))
lat2aftRightR = np.arcsin(np.sin(latR)*np.cos(beamDistR) + np.cos(latR)*np.sin(beamDistR)*np.cos(aftRightHeadR))
lon2aftRightR = lonR + np.arctan2(np.sin(aftRightHeadR)*np.sin(beamDistR)*np.cos(latR), np.cos(beamDistR) - np.sin(latR)*np.sin(lat2aftRightR))
lat2foreLeftR = np.arcsin(np.sin(latR)*np.cos(beamDistR) + np.cos(latR)*np.sin(beamDistR)*np.cos(foreLeftHeadR))
lon2foreLeftR = lonR + np.arctan2(np.sin(foreLeftHeadR)*np.sin(beamDistR)*np.cos(latR), np.cos(beamDistR) - np.sin(latR)*np.sin(lat2foreLeftR))
lat2foreRightR = np.arcsin(np.sin(latR)*np.cos(beamDistR) + np.cos(latR)*np.sin(beamDistR)*np.cos(foreRightHeadR))
lon2foreRightR = lonR + np.arctan2(np.sin(foreRightHeadR)*np.sin(beamDistR)*np.cos(latR), np.cos(beamDistR) - np.sin(latR)*np.sin(lat2foreRightR))
latAL = np.rad2deg(lat2aftLeftR)
lonAL = np.rad2deg(lon2aftLeftR)
latAR = np.rad2deg(lat2aftRightR)
lonAR = np.rad2deg(lon2aftRightR)
aftSwpLocs = {'latL': np.rad2deg(lat2aftLeftR),
'lonL': np.rad2deg(lon2aftLeftR),
'latR': np.rad2deg(lat2aftRightR),
'lonR': np.rad2deg(lon2aftRightR)}
foreSwpLocs = {'latL': np.rad2deg(lat2foreLeftR),
'lonL': np.rad2deg(lon2foreLeftR),
'latR': np.rad2deg(lat2foreRightR),
'lonR': np.rad2deg(lon2foreRightR)}
return aftSwpLocs,foreSwpLocs
def rangeRingCalc(lat1,lon1,maxRngKm):
"""
Calculates lat/lon pairs at some distance from a given point.
Parameters
----------
lat1,lon1 : float
Lon/lat coordinates (degrees) of the initial point.
maxRngKm : float
Max range of radar (in KM).
Returns
-------
latCirc,lonCirc : 1D arrays of floats
Lat/lon (in degrees) following some radar max range
"""
lat1r = np.deg2rad(lat1)
lon1r = np.deg2rad(lon1)
rEarth = 6371
latCirc = []
lonCirc = []
for az in range(0,361):
hdngRad = np.deg2rad(az)
lat2r = np.arcsin( np.sin(lat1r)*np.cos(maxRngKm/rEarth) + np.cos(lat1r)*np.sin(maxRngKm/rEarth)*np.cos(hdngRad) )
lon2r = lon1r + np.arctan2( np.sin(hdngRad)*np.sin(maxRngKm/rEarth)*np.cos(lat1r), np.cos(maxRngKm/rEarth)-np.sin(lat1r)*np.sin(lat2r) )
latCirc.append(np.rad2deg(lat2r))
lonCirc.append(np.rad2deg(lon2r))
return latCirc,lonCirc
def domainCalc(lat0,lon0,xKm,yKm):
"""
Calculates lat/lon pairs which illustrate some rectangular domain.
Useful for plotting an analysis domain (i.e., the Ziegler objective
analysis code, WRF, etc...)
Parameters
----------
lat0,lon0 : float
Lon/lat coordinates (degrees) of the domain origin.
xKm : float
East-west dimension (from the origin) of the domain (in km).
yKm : float
North-south dimension (from the origin) of the domain (in km).
Returns
-------
latDom,lonDom : 1D arrays of floats
Lat/lon (in degrees) of the domain box to be plotted.
"""
lat0r = np.deg2rad(lat0)
lon0r = np.deg2rad(lon0)
rEarth = 6371
latDom = [lat0]
lonDom = [lon0]
for hdngD,rngKm in zip([90,0,270],[xKm,yKm,xKm]):
hdng = np.deg2rad(hdngD)
lat2r = np.arcsin( np.sin(np.deg2rad(latDom[-1]))*np.cos(rngKm/rEarth) + np.cos(np.deg2rad(latDom[-1]))*np.sin(rngKm/rEarth)*np.cos(hdng) )
lon2r = np.deg2rad(lonDom[-1]) + np.arctan2( np.sin(hdng)*np.sin(rngKm/rEarth)*np.cos(np.deg2rad(latDom[-1])), np.cos(rngKm/rEarth)-np.sin(np.deg2rad(latDom[-1]))*np.sin(lat2r) )
latDom.append(np.rad2deg(lat2r))
lonDom.append(np.rad2deg(lon2r))
latDom.append(lat0)
lonDom.append(lon0)
return latDom,lonDom