def __init__(self, *args, **kwargs): super(MapBrowser, self).__init__(**kwargs) mapview = MapView(lat=50.6394, lon=3.057, zoom=8, cache_dir="cache") self.add_widget(mapview) mapview.add_widget(MapMarker(lat=50.6394, lon=3.057)) mapview.add_widget(MapMarker(lat=-33.867, lon=151.206)) top_bar = Toolbar(pos_hint={'top': 1}) def center_on(lat, lon, instance): mapview.center_on(lat, lon) label_lat.text = "Latitude: {}".format(mapview.lat) label_lon.text = "Longitude: {}".format(mapview.lon) btn_lille = Button(text="Move to Lille, France") btn_lille.bind(on_release=partial(center_on, 50.6394, 3.057)) top_bar.add_widget(btn_lille) btn_sydney = Button(text="Move to Sydney, Autralia") btn_sydney.bind(on_release=partial(center_on, -33.867, 151.206)) top_bar.add_widget(btn_sydney) spinner_src = Spinner(text="mapnik", values=MapSource.providers.keys()) def set_source(instance, selected_text): mapview.map_source = selected_text spinner_src.bind(text=set_source) top_bar.add_widget(spinner_src) bottom_bar = Toolbar() label_lon = Label(text="Longitude: {}".format(mapview.lon)) label_lat = Label(text="Latitude: {}".format(mapview.lat)) bottom_bar.add_widget(label_lon) bottom_bar.add_widget(label_lat) self.add_widget(top_bar) self.add_widget(bottom_bar)
class ShowMap(BoxLayout): def __init__(self, *args, **kwargs): super(ShowMap, self).__init__(**kwargs) points = JsonStore("points_of_interest.json") self.view = MapView(lat=points["center"]['lat'], lon=points["center"]['lon'], zoom=15, cache_dir="cache") # Add Route layer = GeoJsonMapLayer(source="route.json") self.view.add_layer(layer) # Add User user_marker = MapMarker(lat=points["center"]['lat'], lon=points["center"]['lon'], source='assets/icon_user.png') self.view.add_widget(user_marker) # Add Icons self.icons = MapIcons(width='60sp') def zoom_in(instance): print('Zoom In:', self.view.zoom) if self.view.zoom == 19: return self.view.zoom += 1 self.icons.btn_zoom_in.bind(on_press=zoom_in) def zoom_out(instance): print('Zoom Out:', self.view.zoom) if self.view.zoom == 1: return self.view.zoom -= 1 self.icons.btn_zoom_out.bind(on_press=zoom_out) def center_on(instance): print('Center On:', user_marker.lat, user_marker.lon) self.view.center_on(user_marker.lat, user_marker.lon) self.icons.btn_center_on.bind(on_press=center_on) self.view.add_widget(self.icons) for point in points["list"]: bubble = Bubble(orientation='vertical', background_image=point['image']) map_marker = MapMarkerPopup(id="marker", lat=point['lat'], lon=point['lon'], source='assets/icon_marker.png') map_marker.add_widget(bubble) self.view.add_marker(map_marker) self.add_widget(self.view) ### Begin Close Bubble ### def close_bubbles(arg, touch): for c in self.view.children: for cc in c.children: if cc.id == 'marker': if len(cc.children) and cc.is_open: cc.is_open = False cc.refresh_open_status() self.view.children[-1].bind(on_touch_up=close_bubbles) ### End Close Bubble ### def on_size(self, *args): if self.view: self.icons.pos = (self.width - self.icons.width, (self.height - self.icons.height)/2.)
class ISSScreen(Screen): def __init__(self, **kwargs): super(ISSScreen, self).__init__(**kwargs) # Set the path for the folder self.path = os.path.dirname(os.path.abspath(__file__)) # Set the path for local images self.imagefolder = os.path.join(self.path, "images") # Ephem calculates the position using the Two Line Element data # We need to make sure we have up to date info tle = self.get_TLE() # Create an iss object from which we can get positional data self.iss = ephem.readtle(*tle) # Run the calculations self.iss.compute() # Get positon of iss and place a marker there lat, lon = self.get_loc() self.marker = MapMarker(lat=lat, lon=lon) # Create a value to check when we last drew ISS path self.last_path_update = 0 # Create the path icon self.path_icon = os.path.join(self.imagefolder, "dot.png") # Create the world map self.map = MapView(id="mpv", lat=0, lon=0, zoom=1, scale=1.5) x, y = self.map.get_window_xy_from(0, 0, 1) self.map.scale_at(1.2, x, y) # Add the ISS marker to the map and draw the map on the screen self.map.add_widget(self.marker) self.add_widget(self.map) # Add a new layer for the path self.mmlayer = MarkerMapLayer() self.draw_iss_path() self.timer = None def on_enter(self): self.timer = Clock.schedule_interval(self.update, 1) def on_leave(self): Clock.unschedule(self.timer) def utcnow(self): return (datetime.utcnow() - datetime(1970, 1, 1)).total_seconds() def draw_iss_path(self): # Path is drawn every 5 mins if self.utcnow() - self.last_path_update > 30: try: self.map.remove_layer(self.mmlayer) except: pass self.mmlayer = MarkerMapLayer() # Create markers showing the ISS's position every 5 mins for i in range(20): lat, lon = self.get_loc(datetime.now() + timedelta(0, i * 300)) self.mmlayer.add_widget( MapMarker(lat=lat, lon=lon, source=self.path_icon)) # Update the flag so we know when next update should be run self.last_path_update = self.utcnow() # Add the layer and call the reposition function otherwise the # markers don't show otherwise! self.map.add_layer(self.mmlayer) self.mmlayer.reposition() def get_TLE(self): # Set some flags need_update = False # Set our data source and the name of the object we're tracking source = "http://www.celestrak.com/NORAD/elements/stations.txt" ISS = "ISS (ZARYA)" # Get the current time utc_now = self.utcnow() # Set the name of our file to store data data = os.path.join(self.path, "iss_tle.json") # Try loading old data try: with open(data, "r") as savefile: saved = json.load(savefile) # If we can't create a dummy dict except IOError: saved = {"updated": 0} # If old data is more than an hour hold, let's check for an update if utc_now - saved["updated"] > 3600: need_update = True # If we don't have any TLE data then we need an update if not saved.get("tle"): need_update = True if need_update: # Load the TLE data raw = requests.get(source).text # Split the data into a neat list all_sats = [sat.strip() for sat in raw.split("\n")] # Find the ISS and grab the whole TLE (three lines) iss_index = all_sats.index(ISS) iss_tle = all_sats[iss_index:iss_index + 3] # Prepare a dict to save our data new_tle = {"updated": utc_now, "tle": iss_tle} # Save it with open(data, "w") as savefile: json.dump(new_tle, savefile, indent=4) # ephem needs strings not unicode return [str(x) for x in iss_tle] else: # return the saved data (as strings) return [str(x) for x in saved["tle"]] def update(self, *args): # Update the ISS with newest TLE self.iss = ephem.readtle(*self.get_TLE()) # Get the position and update marker lat, lon = self.get_loc() self.marker.lat = lat self.marker.lon = lon self.map.remove_widget(self.marker) self.map.add_widget(self.marker) # Check if the path needs redrawing self.draw_iss_path() def get_loc(self, dt=None): # We can get the location for a specific time as well if dt is None: self.iss.compute() else: self.iss.compute(dt) # Convert the ephem data into something that the map can use lat = float(self.iss.sublat / ephem.degree) lon = float(self.iss.sublong / ephem.degree) return lat, lon
class ISSScreen(Screen): def __init__(self, **kwargs): super(ISSScreen, self).__init__(**kwargs) # Set the path for the folder self.path = os.path.dirname(os.path.abspath(__file__)) # Set the path for local images self.imagefolder = os.path.join(self.path, "images") # Ephem calculates the position using the Two Line Element data # We need to make sure we have up to date info tle = self.get_TLE() # Create an iss object from which we can get positional data self.iss = ephem.readtle(*tle) # Run the calculations self.iss.compute() # Get positon of iss and place a marker there lat, lon = self.get_loc() self.marker = MapMarker(lat=lat, lon=lon) # Create a value to check when we last drew ISS path self.last_path_update = 0 # Create the path icon self.path_icon = os.path.join(self.imagefolder, "dot.png") # Create the world map self.map = MapView(id="mpv",lat=0, lon=0, zoom=1, scale=1.5) x, y = self.map.get_window_xy_from(0,0,1) self.map.scale_at(1.2, x, y) # Add the ISS marker to the map and draw the map on the screen self.map.add_widget(self.marker) self.add_widget(self.map) # Add a new layer for the path self.mmlayer = MarkerMapLayer() self.draw_iss_path() self.timer = None def on_enter(self): self.timer = Clock.schedule_interval(self.update, 1) def on_leave(self): Clock.unschedule(self.timer) def utcnow(self): return (datetime.utcnow() - datetime(1970,1,1)).total_seconds() def draw_iss_path(self): # Path is drawn every 5 mins if self.utcnow() - self.last_path_update > 30: try: self.map.remove_layer(self.mmlayer) except: pass self.mmlayer = MarkerMapLayer() # Create markers showing the ISS's position every 5 mins for i in range(20): lat, lon = self.get_loc(datetime.now() + timedelta(0, i * 300)) self.mmlayer.add_widget(MapMarker(lat=lat, lon=lon, source=self.path_icon)) # Update the flag so we know when next update should be run self.last_path_update = self.utcnow() # Add the layer and call the reposition function otherwise the # markers don't show otherwise! self.map.add_layer(self.mmlayer) self.mmlayer.reposition() def get_TLE(self): # Set some flags need_update = False # Set our data source and the name of the object we're tracking source = "http://www.celestrak.com/NORAD/elements/stations.txt" ISS = "ISS (ZARYA)" # Get the current time utc_now = self.utcnow() # Set the name of our file to store data data = os.path.join(self.path, "iss_tle.json") # Try loading old data try: with open(data, "r") as savefile: saved = json.load(savefile) # If we can't create a dummy dict except IOError: saved = {"updated": 0} # If old data is more than an hour hold, let's check for an update if utc_now - saved["updated"] > 3600: need_update = True # If we don't have any TLE data then we need an update if not saved.get("tle"): need_update = True if need_update: # Load the TLE data raw = requests.get(source).text # Split the data into a neat list all_sats = [sat.strip() for sat in raw.split("\n")] # Find the ISS and grab the whole TLE (three lines) iss_index = all_sats.index(ISS) iss_tle = all_sats[iss_index:iss_index + 3] # Prepare a dict to save our data new_tle = {"updated": utc_now, "tle": iss_tle} # Save it with open(data, "w") as savefile: json.dump(new_tle, savefile, indent=4) # ephem needs strings not unicode return [str(x) for x in iss_tle] else: # return the saved data (as strings) return [str(x) for x in saved["tle"]] def update(self, *args): # Update the ISS with newest TLE self.iss = ephem.readtle(*self.get_TLE()) # Get the position and update marker lat, lon = self.get_loc() self.marker.lat = lat self.marker.lon = lon self.map.remove_widget(self.marker) self.map.add_widget(self.marker) # Check if the path needs redrawing self.draw_iss_path() def get_loc(self, dt=None): # We can get the location for a specific time as well if dt is None: self.iss.compute() else: self.iss.compute(dt) # Convert the ephem data into something that the map can use lat = float(self.iss.sublat / ephem.degree) lon = float(self.iss.sublong / ephem.degree) return lat, lon