from plyer import gps from kivy.app import App from kivy.clock import Clock from kivy.properties import NumericProperty, StringProperty from kivy.clock import mainthread from kivy.utils import platform from kivy.uix.screenmanager import ScreenManager, Screen, RiseInTransition from kivy_garden.mapview import MapView from kivy.vector import Vector from kivy.animation import Animation from math import floor import random from pprint import pprint root = None class MapScreen(Screen): def choose_destination(self): root.parent.dest_lat = self.ids.centermark.lat root.parent.dest_lon = self.ids.centermark.lon class CompassScreen(Screen): x_calib = NumericProperty(0) y_calib = NumericProperty(0) z_calib = NumericProperty(0) needle_angle = NumericProperty(0) gps_location = StringProperty() gps_status = StringProperty('Click Start to get GPS location updates') def get_field(self, dt): needle_angle = 7 if self.facade.field != (None, None, None): self.x_calib, self.y_calib, self.z_calib = self.facade.field x, y, z = self.facade.field needle_angle = Vector(x, y).angle((0, 1)) + 90. # fix animation transition around the unit circle if (self.needle_angle % 360) - needle_angle > 180: needle_angle += 360 elif (self.needle_angle % 360) - needle_angle < -180: needle_angle -= 360 # add the number of revolutions to the result needle_angle += 360 * floor(self.needle_angle / 360.) # animate the needle if self._anim: self._anim.stop(self) self._anim = Animation(needle_angle=needle_angle, d=.2, t='out_quad') self._anim.start(self) def sensors_start(self): self.compass_enable() self.gps_start(1000, 0) def sensors_stop(self): self.compass_disable() self.gps_stop() def compass_enable(self): self.facade.enable() Clock.schedule_interval(self.get_field, 1 / 5.0) def compass_disable(self): self.facade.disable() Clock.unschedule(self.get_field) def gps_start(self, minTime, minDistance): gps.start(minTime, minDistance) def gps_stop(self): gps.stop() def on_pause(self): self.compass_disable() self.gps_stop() return True def on_resume(self): self.compass_enable() self.gps_start(1000, 0) @mainthread def on_location(self, **kwargs): self.parent.parent.lat = kwargs['lat'] self.parent.parent.lon = kwargs['lon'] # self.parent.speed = kwargs['speed'] # self.parent.bearing = kwargs['bearing'] # self.gps_location = '\n'.join([ # '{}={}'.format(k, v) for k, v in kwargs.items()]) # bearing = atan2(sin(long2-long1)*cos(lat2), cos(lat1)*sin(lat2)-sin(lat1)*cos(lat2)*cos(long2-long1)) # bearing = degrees(bearing) # bearing = (bearing + 360) % 360 # https://stackoverflow.com/questions/4913349/haversine-formula-in-python-bearing-and-distance-between-two-gps-points#4913653 @mainthread def on_status(self, stype, status): self.gps_status = 'type={}\n{}'.format(stype, status) class FlockompassApp(App): lat = 19.3419 lon = -99.1499 dest_lat = 19.3429 dest_lon = -99.15 def move_around(self, t): self.lat += random.uniform(-0.01,0.01) self.lon += random.uniform(-0.01,0.01) self.ms.ids.mapview.center_on(self.lat, self.lon) # where the marker's at def request_android_permissions(self): from android.permissions import request_permissions, Permission def callback(permissions, results): if all([res for res in results]): print("aguas: callback. All permissions granted.") else: print("aguas: callback. Some permissions refused.Permission.ACCESS_FINE_LOCATION") request_permissions([Permission.ACCESS_COARSE_LOCATION, Permission.ACCESS_FINE_LOCATION], callback) def build(self): global root root = ScreenManager(transition=RiseInTransition()) self.ms = MapScreen(name='map') root.add_widget(self.ms) cs = CompassScreen(name='compass') cs._anim = None cs.p = None root.add_widget(cs) if platform == "android": print("gps.py: Android detected. Requesting permissions") self.request_android_permissions() try: gps.configure(on_location=cs.on_location, on_status=cs.on_status) except NotImplementedError: import traceback traceback.print_exc() print('GPS is not implemented for your platform') Clock.schedule_interval(self.move_around, 7.0) return root if __name__ == '__main__': FlockompassApp().run() # Button: # text: 'Use FallOutTransition' # on_release: root.manager.transition = FallOutTransition() # Button: # text: 'Use RiseInTransition' # on_release: root.manager.transition = RiseInTransition()