1 |
#!/usr/bin/env python |
---|
2 |
|
---|
3 |
""" |
---|
4 |
Generate glider goto list. |
---|
5 |
|
---|
6 |
Warning: This script has only been tested for operations in |
---|
7 |
the Northwestern hemispheric quadrant. It will most |
---|
8 |
certainly fail for operations crossing quadrants. |
---|
9 |
|
---|
10 |
Usage: |
---|
11 |
|
---|
12 |
python points.py glider_name \\ |
---|
13 |
glider_lat glider_lon \\ |
---|
14 |
bearing \\ |
---|
15 |
heading [distance [steps [no_copy]]] |
---|
16 |
|
---|
17 |
where glider_name is the whoru response from the glider, |
---|
18 |
|
---|
19 |
where glider_lat and glider_lon are the present glider |
---|
20 |
latitude and longitude in ISO format (+/-ddmm.mmmm), |
---|
21 |
|
---|
22 |
where bearing is the literal token bearing, |
---|
23 |
|
---|
24 |
where heading is the direction of movement in degrees |
---|
25 |
clockwise from north, |
---|
26 |
|
---|
27 |
where the optional distance is the spherical distance of |
---|
28 |
movement in kilometers per step, defaulting to 2km, |
---|
29 |
|
---|
30 |
where the optional steps are the number of waypoints to |
---|
31 |
generate with distance between each step, defaulting |
---|
32 |
to 20, |
---|
33 |
|
---|
34 |
and where if the optional no_copy is present, suppress |
---|
35 |
writing a goto list to the to-glider folder |
---|
36 |
(archive only); |
---|
37 |
|
---|
38 |
or |
---|
39 |
|
---|
40 |
python points.py glider_name \\ |
---|
41 |
glider_lat glider_lon \\ |
---|
42 |
target \\ |
---|
43 |
target_lat target_lon \\ |
---|
44 |
[steps [no_copy]] |
---|
45 |
|
---|
46 |
where glider_name is the whoru response from the glider, |
---|
47 |
|
---|
48 |
where glider_lat and glider_lon are the present glider |
---|
49 |
latitude and longitude in ISO format (+/-ddmm.mmmm), |
---|
50 |
|
---|
51 |
where target is the literal token target, |
---|
52 |
|
---|
53 |
where target_lat and target_lon are the desired glider |
---|
54 |
latitude and longitude in ISO format (+/-ddmm.mmmm), |
---|
55 |
|
---|
56 |
where the optional steps are the number of waypoints to |
---|
57 |
generate between present and desired glider positions, |
---|
58 |
defaulting to 20. |
---|
59 |
|
---|
60 |
and where if the optional no_copy is present, suppress |
---|
61 |
writing a goto list to the to-glider folder |
---|
62 |
(archive only). |
---|
63 |
""" |
---|
64 |
|
---|
65 |
import sys |
---|
66 |
import os |
---|
67 |
import math |
---|
68 |
import shutil |
---|
69 |
from datetime import datetime |
---|
70 |
|
---|
71 |
months = {1: 'Jan', |
---|
72 |
2: 'Feb', |
---|
73 |
3: 'Mar', |
---|
74 |
4: 'Apr', |
---|
75 |
5: 'May', |
---|
76 |
6: 'Jun', |
---|
77 |
7: 'Jul', |
---|
78 |
8: 'Aug', |
---|
79 |
9: 'Sep', |
---|
80 |
10: 'Oct', |
---|
81 |
11: 'Nov', |
---|
82 |
12: 'Dec'} |
---|
83 |
|
---|
84 |
LB1MOOR = [3310.353, -7819.800] |
---|
85 |
LB1ADCP = [3310.172, -7820.007] |
---|
86 |
LB2MOOR = [3256.491, -7805.667] |
---|
87 |
LB2ADCP = [3256.419, -7805.926] |
---|
88 |
LB3MOOR = [3251.142, -7800.793] |
---|
89 |
LB3ADCP = [3251.142, -7800.793] |
---|
90 |
|
---|
91 |
glider_dir = '/var/opt/gmc/gliders' |
---|
92 |
|
---|
93 |
goto_names = {"ramses": "goto_l10.ma", |
---|
94 |
"pelagia": "goto_l20.ma",} |
---|
95 |
|
---|
96 |
first_template = \ |
---|
97 |
"""# |
---|
98 |
# Filename: %s |
---|
99 |
# File creation time: %s |
---|
100 |
# Generated by: %s |
---|
101 |
# |
---|
102 |
|
---|
103 |
behavior_name=goto_list |
---|
104 |
|
---|
105 |
<start:b_arg> |
---|
106 |
b_arg: num_legs_to_run(nodim) -2 # -1 loop, -2 run once, > 0 = this m$ |
---|
107 |
b_arg: start_when(enum) 0 # 0 baw_immediately |
---|
108 |
b_arg: list_stop_when(enum) 7 # BAW_WHEN_WPT_DIST |
---|
109 |
|
---|
110 |
# SATISFYING RADIUS |
---|
111 |
b_arg: list_when_wpt_dist(m) 100 |
---|
112 |
|
---|
113 |
# LIST PARAMETERS |
---|
114 |
b_arg: initial_wpt(enum) 0 # 0 to n-1, -1 first after last, -2 c$ |
---|
115 |
b_arg: num_waypoints(nodim) %u |
---|
116 |
<end:b_arg> |
---|
117 |
|
---|
118 |
<start:waypoints> |
---|
119 |
""" |
---|
120 |
|
---|
121 |
last_template = \ |
---|
122 |
"""<end:waypoints> |
---|
123 |
|
---|
124 |
""" |
---|
125 |
|
---|
126 |
nmperrad = 360.0 * 60.0 / (2 * math.pi) # 1 nautical mile per minute lat |
---|
127 |
kmperrad = nmperrad * 1.852 # mean at 48 degrees |
---|
128 |
kmperdeg = kmperrad * math.pi / 180.0 |
---|
129 |
|
---|
130 |
def ddmm2decdeg(ddmm): |
---|
131 |
sign = ddmm < 0 |
---|
132 |
ddmm = abs(ddmm) |
---|
133 |
dd = (ddmm // 100) |
---|
134 |
mm = ddmm - (dd * 100) |
---|
135 |
dm = mm / 60 |
---|
136 |
if sign: |
---|
137 |
decdeg = -(dd + dm) |
---|
138 |
else: |
---|
139 |
decdeg = dd + dm |
---|
140 |
return decdeg |
---|
141 |
|
---|
142 |
def decdeg2ddmm(decdeg): |
---|
143 |
dd = int(decdeg) |
---|
144 |
dm = decdeg - dd |
---|
145 |
mm = dm * 60 |
---|
146 |
ddmm = (dd * 100) + mm |
---|
147 |
return ddmm |
---|
148 |
|
---|
149 |
def latlondict(latlonlist): |
---|
150 |
return {'lat': latlonlist[0], |
---|
151 |
'lon': latlonlist[1]} |
---|
152 |
|
---|
153 |
def latlonlist(latlondict): |
---|
154 |
return [latlondict['lat'], latlondict['lon']] |
---|
155 |
|
---|
156 |
def line(origin, target, steps): |
---|
157 |
vector = {'lat': target['lat'] - origin['lat'], |
---|
158 |
'lon': target['lon'] - origin['lon']} |
---|
159 |
divs = {'lat': vector['lat'] / steps, |
---|
160 |
'lon': vector['lon'] / steps} |
---|
161 |
points = [{'lat': origin['lat'] + (x * divs['lat']), |
---|
162 |
'lon': origin['lon'] + (x * divs['lon'])} |
---|
163 |
for x in range(1, steps + 1)] |
---|
164 |
return points |
---|
165 |
|
---|
166 |
def swap(seq): |
---|
167 |
return [seq[1], seq[0]] |
---|
168 |
|
---|
169 |
def _target(glider_name, glider_pos, target, steps, copy=False): |
---|
170 |
goto_name = goto_names[glider_name] |
---|
171 |
glider_pos = map(ddmm2decdeg, glider_pos) |
---|
172 |
target = map(ddmm2decdeg, target) |
---|
173 |
|
---|
174 |
glider_pos = latlondict(glider_pos) |
---|
175 |
target = latlondict(target) |
---|
176 |
|
---|
177 |
points = line(glider_pos, target, steps) |
---|
178 |
points = [latlonlist(point) for point in points] |
---|
179 |
points = [map(decdeg2ddmm, point) for point in points] |
---|
180 |
|
---|
181 |
points = [swap(point) for point in points] |
---|
182 |
|
---|
183 |
now = datetime.now() |
---|
184 |
now_string = "%02d-%s-%04d %02d:%02d:%02d UTC" % (now.day, |
---|
185 |
months[now.month], |
---|
186 |
now.year, |
---|
187 |
now.hour, |
---|
188 |
now.minute, |
---|
189 |
now.second, |
---|
190 |
) |
---|
191 |
now_stamp = "%04d%02d%02dT%02d%02d%02d" % (now.year, |
---|
192 |
now.month, |
---|
193 |
now.day, |
---|
194 |
now.hour, |
---|
195 |
now.minute, |
---|
196 |
now.second) |
---|
197 |
|
---|
198 |
backup_dir = os.path.join(os.path.dirname( |
---|
199 |
os.path.abspath(__file__)), |
---|
200 |
"archive", |
---|
201 |
glider_name) |
---|
202 |
backup_name = "%s_%s_%s" % (glider_name, |
---|
203 |
goto_name, |
---|
204 |
now_stamp) |
---|
205 |
goto_path = os.path.join(glider_dir, |
---|
206 |
glider_name, |
---|
207 |
"to-glider", |
---|
208 |
goto_name) |
---|
209 |
try: |
---|
210 |
os.makedirs(backup_dir) |
---|
211 |
except: |
---|
212 |
pass |
---|
213 |
backup_path = os.path.join(backup_dir, |
---|
214 |
backup_name) |
---|
215 |
|
---|
216 |
command_line = "%s %s" % (sys.executable, |
---|
217 |
" ".join(sys.argv)) |
---|
218 |
handle = open(backup_path, "w") |
---|
219 |
handle.write(first_template % (goto_name, |
---|
220 |
now_string, |
---|
221 |
command_line, |
---|
222 |
steps)) |
---|
223 |
handle.writelines(["\t%.3f\t%.3f\n" % tuple(point) for point in points]) |
---|
224 |
handle.write(last_template) |
---|
225 |
handle.close() |
---|
226 |
|
---|
227 |
if copy: |
---|
228 |
shutil.copy2(backup_path, goto_path) |
---|
229 |
return points |
---|
230 |
|
---|
231 |
def _bearing(glider_name, glider_pos, heading, distance, steps, copy=False): |
---|
232 |
glider_pos = map(ddmm2decdeg, glider_pos) |
---|
233 |
glider_pos = map(math.radians, glider_pos) |
---|
234 |
glider_pos = latlondict(glider_pos) |
---|
235 |
heading = math.radians(heading) |
---|
236 |
distance = distance / kmperrad |
---|
237 |
dlat = distance * math.cos(heading) |
---|
238 |
dlon = distance * math.sin(heading) / math.cos(glider_pos['lat']) |
---|
239 |
target = {} |
---|
240 |
target['lon'] = glider_pos['lon'] + (steps * dlon) |
---|
241 |
target['lat'] = glider_pos['lat'] + (steps * dlat) |
---|
242 |
target = latlonlist(target) |
---|
243 |
target = map(math.degrees, target) |
---|
244 |
target = map(decdeg2ddmm, target) |
---|
245 |
glider_pos = latlonlist(glider_pos) |
---|
246 |
glider_pos = map(math.degrees, glider_pos) |
---|
247 |
glider_pos = map(decdeg2ddmm, glider_pos) |
---|
248 |
return _target(glider_name, glider_pos, target, steps, copy) |
---|
249 |
|
---|
250 |
if __name__ == "__main__": |
---|
251 |
num_args = len(sys.argv) - 1 |
---|
252 |
if not (num_args == 5 or |
---|
253 |
num_args == 6 or |
---|
254 |
num_args == 7 or |
---|
255 |
num_args == 8): |
---|
256 |
sys.exit(__doc__) |
---|
257 |
|
---|
258 |
try: |
---|
259 |
glider_name = sys.argv[1] |
---|
260 |
glider_pos = [float(sys.argv[2]), float(sys.argv[3])] |
---|
261 |
method = sys.argv[4].lower() |
---|
262 |
if method == "bearing": |
---|
263 |
heading = target = float(sys.argv[5]) |
---|
264 |
if num_args > 5: |
---|
265 |
distance = float(sys.argv[6]) |
---|
266 |
else: |
---|
267 |
distance = 2 |
---|
268 |
if num_args > 6: |
---|
269 |
steps = int(sys.argv[7]) |
---|
270 |
else: |
---|
271 |
steps = 20 |
---|
272 |
if num_args > 7: |
---|
273 |
copy = False |
---|
274 |
else: |
---|
275 |
copy = True |
---|
276 |
_bearing(glider_name, glider_pos, heading, distance, steps, copy) |
---|
277 |
elif method == "target": |
---|
278 |
target = [float(sys.argv[5]), float(sys.argv[6])] |
---|
279 |
if num_args > 6: |
---|
280 |
steps = int(sys.argv[7]) |
---|
281 |
else: |
---|
282 |
steps = 20 |
---|
283 |
if num_args > 7: |
---|
284 |
copy = False |
---|
285 |
else: |
---|
286 |
copy = True |
---|
287 |
_target(glider_name, glider_pos, target, steps, copy) |
---|
288 |
else: |
---|
289 |
raise Exception("Incorrect points method type.") |
---|
290 |
except: |
---|
291 |
sys.exit(__doc__) |
---|
292 |
|
---|