-
Notifications
You must be signed in to change notification settings - Fork 661
/
mp_slipmap.py
executable file
·254 lines (213 loc) · 9.12 KB
/
mp_slipmap.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
#!/usr/bin/env python
# -*- coding: utf-8 -*-
'''
slipmap based on mp_tile
Andrew Tridgell
June 2012
'''
import functools
import math
import os, sys
import time
import cv2
import numpy as np
from MAVProxy.modules.mavproxy_map import mp_elevation
from MAVProxy.modules.mavproxy_map import mp_tile
from MAVProxy.modules.lib import mp_util
from MAVProxy.modules.lib import win_layout
from MAVProxy.modules.lib import multiproc
from MAVProxy.modules.mavproxy_map.mp_slipmap_util import *
class MPSlipMap():
'''
a generic map viewer widget for use in mavproxy
'''
def __init__(self,
title='SlipMap',
lat=-35.362938,
lon=149.165085,
width=800,
height=600,
ground_width=1000,
tile_delay=0.3,
service="MicrosoftSat",
max_zoom=19,
debug=False,
brightness=0,
elevation=False,
download=True,
show_flightmode_legend=True):
self.lat = lat
self.lon = lon
self.width = width
self.height = height
self.ground_width = ground_width
self.download = download
self.service = service
self.tile_delay = tile_delay
self.debug = debug
self.max_zoom = max_zoom
self.elevation = elevation
self.oldtext = None
self.brightness = brightness
self.legend = show_flightmode_legend
self.drag_step = 10
self.title = title
self.event_queue = multiproc.Queue()
self.object_queue = multiproc.Queue()
self.close_window = multiproc.Semaphore()
self.close_window.acquire()
self.child = multiproc.Process(target=self.child_task)
self.child.start()
self._callbacks = set()
def child_task(self):
'''child process - this holds all the GUI elements'''
mp_util.child_close_fds()
from MAVProxy.modules.lib import wx_processguard
from MAVProxy.modules.lib.wx_loader import wx
from MAVProxy.modules.mavproxy_map.mp_slipmap_ui import MPSlipMapFrame
state = self
self.mt = mp_tile.MPTile(download=self.download,
service=self.service,
tile_delay=self.tile_delay,
debug=self.debug,
max_zoom=self.max_zoom)
state.layers = {}
state.info = {}
state.need_redraw = True
self.app = wx.App(False)
self.app.SetExitOnFrameDelete(True)
self.app.frame = MPSlipMapFrame(state=self)
self.app.frame.Show()
self.app.MainLoop()
def close(self):
'''close the window'''
self.close_window.release()
count=0
while self.child.is_alive() and count < 30: # 3 seconds to die...
time.sleep(0.1) #?
count+=1
if self.child.is_alive():
self.child.terminate()
self.child.join()
def is_alive(self):
'''check if graph is still going'''
return self.child.is_alive()
def add_object(self, obj):
'''add or update an object on the map'''
self.object_queue.put(obj)
def remove_object(self, key):
'''remove an object on the map by key'''
self.object_queue.put(SlipRemoveObject(key))
def set_zoom(self, ground_width):
'''set ground width of view'''
self.object_queue.put(SlipZoom(ground_width))
def set_center(self, lat, lon):
'''set center of view'''
self.object_queue.put(SlipCenter((lat,lon)))
def set_follow(self, enable):
'''set follow on/off'''
self.object_queue.put(SlipFollow(enable))
def set_follow_object(self, key, enable):
'''set follow on/off on an object'''
self.object_queue.put(SlipFollowObject(key, enable))
def hide_object(self, key, hide=True):
'''hide an object on the map by key'''
self.object_queue.put(SlipHideObject(key, hide))
def set_position(self, key, latlon, layer='', rotation=0, label=None, colour=None):
'''move an object on the map'''
self.object_queue.put(SlipPosition(key, latlon, layer, rotation, label, colour))
def event_count(self):
'''return number of events waiting to be processed'''
return self.event_queue.qsize()
def set_layout(self, layout):
'''set window layout'''
self.object_queue.put(layout)
def get_event(self):
'''return next event or None'''
if self.event_queue.qsize() == 0:
return None
evt = self.event_queue.get()
while isinstance(evt, win_layout.WinLayout):
win_layout.set_layout(evt, self.set_layout)
if self.event_queue.qsize() == 0:
return None
evt = self.event_queue.get()
return evt
def add_callback(self, callback):
'''add a callback for events from the map'''
self._callbacks.add(callback)
def check_events(self):
'''check for events, calling registered callbacks as needed'''
while self.event_count() > 0:
event = self.get_event()
for callback in self._callbacks:
callback(event)
def icon(self, filename):
'''load an icon from the data directory'''
return mp_tile.mp_icon(filename)
if __name__ == "__main__":
multiproc.freeze_support()
import time
from optparse import OptionParser
parser = OptionParser("mp_slipmap.py [options]")
parser.add_option("--lat", type='float', default=-26.582218, help="start latitude")
parser.add_option("--lon", type='float', default=151.840113, help="start longitude")
parser.add_option("--service", default="MicrosoftSat", help="tile service")
parser.add_option("--offline", action='store_true', default=False, help="no download")
parser.add_option("--delay", type='float', default=0.3, help="tile download delay")
parser.add_option("--max-zoom", type='int', default=19, help="maximum tile zoom")
parser.add_option("--debug", action='store_true', default=False, help="show debug info")
parser.add_option("--boundary", default=None, help="show boundary")
parser.add_option("--mission", default=[], action='append', help="show mission")
parser.add_option("--thumbnail", default=None, help="show thumbnail")
parser.add_option("--icon", default=None, help="show icon")
parser.add_option("--flag", default=[], type='str', action='append', help="flag positions")
parser.add_option("--grid", default=False, action='store_true', help="add a UTM grid")
parser.add_option("--elevation", action='store_true', default=False, help="show elevation information")
parser.add_option("--verbose", action='store_true', default=False, help="show mount actions")
(opts, args) = parser.parse_args()
sm = MPSlipMap(lat=opts.lat,
lon=opts.lon,
download=not opts.offline,
service=opts.service,
debug=opts.debug,
max_zoom=opts.max_zoom,
elevation=opts.elevation,
tile_delay=opts.delay)
if opts.boundary:
boundary = mp_util.polygon_load(opts.boundary)
sm.add_object(SlipPolygon('boundary', boundary, layer=1, linewidth=2, colour=(0,255,0)))
if opts.mission:
from pymavlink import mavwp
for file in opts.mission:
wp = mavwp.MAVWPLoader()
wp.load(file)
boundary = wp.polygon()
sm.add_object(SlipPolygon('mission-%s' % file, boundary, layer=1, linewidth=1, colour=(255,255,255)))
if opts.grid:
sm.add_object(SlipGrid('grid', layer=3, linewidth=1, colour=(255,255,0)))
if opts.thumbnail:
thumb = cv2.imread(opts.thumbnail)
sm.add_object(SlipThumbnail('thumb', (opts.lat,opts.lon), layer=1, img=thumb, border_width=2, border_colour=(255,0,0)))
if opts.icon:
icon = cv2.imread(opts.icon)
sm.add_object(SlipIcon('icon', (opts.lat,opts.lon), icon, layer=3, rotation=90, follow=True))
sm.set_position('icon', mp_util.gps_newpos(opts.lat,opts.lon, 180, 100), rotation=45)
sm.add_object(SlipInfoImage('detail', icon))
sm.add_object(SlipInfoText('detail text', 'test text'))
for flag in opts.flag:
(lat,lon) = flag.split(',')
icon = sm.icon('flag.png')
sm.add_object(SlipIcon('icon - %s' % str(flag), (float(lat),float(lon)), icon, layer=3, rotation=0, follow=False))
while sm.is_alive():
while sm.event_count() > 0:
obj = sm.get_event()
if not opts.verbose:
continue
if isinstance(obj, SlipMouseEvent):
print("Mouse event at %s (X/Y=%u/%u) for %u objects" % (obj.latlon,
obj.event.X, obj.event.Y,
len(obj.selected)))
if isinstance(obj, SlipKeyEvent):
print("Key event at %s for %u objects" % (obj.latlon, len(obj.selected)))
time.sleep(0.1)