示例#1
0
class ViewMap(BoxLayout):
    def __init__(self, **kwargs):
        super(ViewMap, self).__init__(**kwargs)
        self.build()

    def build(self):
        self.mapview = MapView(lat=51.48, lon=-3.17, zoom=11)
        self.mapLayer = MarkerMapLayer()
        for i in locations:
            locationLat = float(locations[i][0])
            locationLon = float(locations[i][1])
            marker = MapMarker(lat=locationLat, lon=locationLon)
            self.mapLayer.add_widget(marker)
        self.mapview.add_layer(self.mapLayer)
        self.add_widget(self.mapview)

    def update(self):
        print('updating map')

    def nodeExpanded(self):
        print('expanded node')

    def nodeColapsed(self):
        print('node colapsed')
示例#2
0
class Editor(GridLayout):
    current_layer = None
    edit_last_move = None
    markers = []
    mode = StringProperty("polygon")
    is_editing = BooleanProperty(False)
    map_source = ObjectProperty()
    geojson_fn = StringProperty()
    title = StringProperty()

    def __init__(self, **kwargs):
        super(Editor, self).__init__(**kwargs)
        self.marker_layer = MarkerMapLayer()
        self.current_layer = GeoJsonMapLayer()
        self.result_layer = GeoJsonMapLayer()
        self.result_layer.geojson = kwargs["geojson"]
        self.geojson_fn = kwargs["geojson_fn"]
        self.ids.mapview.add_widget(self.current_layer)
        self.ids.mapview.add_widget(self.result_layer)
        self.ids.mapview.add_widget(self.marker_layer)

    def on_touch_down(self, touch):
        if self.ids.mapview.collide_point(*touch.pos):
            if touch.is_double_tap and not self.is_editing:
                feature = self.select_feature(*touch.pos)
                if feature:
                    self.edit_feature(feature)
                else:
                    touch.grab(self)
                    self.forward_to_object(touch)
                return True
            elif touch.is_double_tap and self.is_editing:
                if self.remove_marker_at(touch):
                    return True
                touch.grab(self)
                return self.forward_to_object(touch)
            elif not self.is_editing:
                self.select_feature(*touch.pos)
            return self.ids.mapview.on_touch_down(touch)
        return super(Editor, self).on_touch_down(touch)

    def on_touch_move(self, touch):
        if touch.grab_current == self and self.is_editing:
            return self.forward_to_object(touch, move=True)
        return super(Editor, self).on_touch_move(touch)

    def switch_mode(self):
        if self.is_editing:
            self.finalize_object()
            return
        self.mode = "line" if self.mode == "polygon" else "polygon"

    def forward_to_object(self, touch, move=False):
        mapview = self.ids.mapview
        if not self.is_editing:
            self.is_editing = True
            self.clear_markers()
        coord = mapview.get_latlon_at(*touch.pos)
        if move:
            m = self.markers[-1]
        else:
            m = EditorMarker()
            m.mapview = mapview
            m.editor = self
            self.markers.append(m)
            self.marker_layer.add_widget(m)
            self.marker_layer.reposition()
        m.lat = coord.lat
        m.lon = coord.lon
        self._update_geojson()
        return True

    def clear_markers(self):
        while self.markers:
            self.remove_marker(self.markers.pop())

    def remove_marker(self, m):
        m.mapview = m.editor = None
        self.marker_layer.remove_widget(m)
        if m in self.markers:
            self.markers.remove(m)
        self._update_geojson()

    def remove_marker_at(self, touch):
        pos = self.ids.mapview.to_local(*touch.pos)
        for marker in self.markers[:]:
            if marker.collide_point(*pos):
                self.remove_marker(marker)
                return True

    def finalize_object(self):
        if self.markers:
            geojson = self.current_layer.geojson
            if "properties" not in geojson:
                geojson["features"][0]["properties"] = {"title": self.title}
            else:
                geojson["features"][0]["properties"]["title"] = self.title
            self.result_layer.geojson["features"].extend(geojson["features"])
            self.ids.mapview.trigger_update(True)
        self.clear_markers()
        self.is_editing = False
        self.title = ""
        self._update_geojson()

    def save_geojson(self):
        with open(self.geojson_fn, "wb") as fd:
            json.dump(self.result_layer.geojson, fd)

    def _update_geojson(self):
        features = []
        if self.mode == "polygon":
            geotype = "Polygon"
            geocoords = lambda x: [x]
        else:
            geotype = "LineString"
            geocoords = lambda x: x

        # current commited path
        if self.markers:
            coordinates = [[c.lon, c.lat] for c in self.markers]
            features.append({
                "type": "Feature",
                "properties": {},
                "geometry": {
                    "type": geotype,
                    "coordinates": geocoords(coordinates)
                }
            })

        geojson = {"type": "FeatureCollection", "features": features}
        self.current_layer.geojson = geojson
        self.ids.mapview.trigger_update(True)

    def point_inside_polygon(self, x, y, poly):
        n = len(poly)
        inside = False
        p1x, p1y = poly[0]
        for i in range(n + 1):
            p2x, p2y = poly[i % n]
            if y > min(p1y, p2y) and y <= max(p1y, p2y) and x <= max(p1x, p2x):
                if p1y != p2y:
                    xinters = (y - p1y) * (p2x - p1x) / (p2y - p1y) + p1x
                if p1x == p2x or x <= xinters:
                    inside = not inside
            p1x, p1y = p2x, p2y
        return inside

    def select_feature(self, x, y):
        coord = self.ids.mapview.get_latlon_at(x, y)
        for feature in self.result_layer.geojson["features"]:
            if feature["type"] != "Feature":
                continue
            geometry = feature["geometry"]
            if geometry["type"] == "Polygon":
                if self.point_inside_polygon(coord.lon, coord.lat,
                                             geometry["coordinates"][0]):
                    return feature

    def edit_feature(self, feature):
        self.result_layer.geojson["features"].remove(feature)
        #self.current_layer.geojson = feature
        self.ids.mapview.trigger_update(True)
        self.title = feature.get("properties", {}).get("title", "")
        self.is_editing = True
        self.clear_markers()
        for c in feature["geometry"]["coordinates"][0]:
            m = EditorMarker(lon=c[0], lat=c[1])
            m.mapview = self.ids.mapview
            m.editor = self
            self.marker_layer.add_widget(m)
            self.markers.append(m)
        self._update_geojson()
示例#3
0
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
示例#4
0
class Editor(GridLayout):
    current_layer = None
    edit_last_move = None
    markers = []
    mode = StringProperty("polygon")
    is_editing = BooleanProperty(False)
    map_source = ObjectProperty()
    geojson_fn = StringProperty()
    title = StringProperty()

    def __init__(self, **kwargs):
        super(Editor, self).__init__(**kwargs)
        self.marker_layer = MarkerMapLayer()
        self.current_layer = GeoJsonMapLayer()
        self.result_layer = GeoJsonMapLayer()
        self.result_layer.geojson = kwargs["geojson"]
        self.geojson_fn = kwargs["geojson_fn"]
        self.ids.mapview.add_widget(self.current_layer)
        self.ids.mapview.add_widget(self.result_layer)
        self.ids.mapview.add_widget(self.marker_layer)

    def on_touch_down(self, touch):
        if self.ids.mapview.collide_point(*touch.pos):
            if touch.is_double_tap and not self.is_editing:
                feature = self.select_feature(*touch.pos)
                if feature:
                    self.edit_feature(feature)
                else:
                    touch.grab(self)
                    self.forward_to_object(touch)
                return True
            elif touch.is_double_tap and self.is_editing:
                if self.remove_marker_at(touch):
                    return True
                touch.grab(self)
                return self.forward_to_object(touch)
            elif not self.is_editing:
                self.select_feature(*touch.pos)
            return self.ids.mapview.on_touch_down(touch)
        return super(Editor, self).on_touch_down(touch)

    def on_touch_move(self, touch):
        if touch.grab_current == self and self.is_editing:
            return self.forward_to_object(touch, move=True)
        return super(Editor, self).on_touch_move(touch)

    def switch_mode(self):
        if self.is_editing:
            self.finalize_object()
            return
        self.mode = "line" if self.mode == "polygon" else "polygon"

    def forward_to_object(self, touch, move=False):
        mapview = self.ids.mapview
        if not self.is_editing:
            self.is_editing = True
            self.clear_markers()
        coord = mapview.get_latlon_at(*touch.pos)
        if move:
            m = self.markers[-1]
        else:
            m = EditorMarker()
            m.mapview = mapview
            m.editor = self
            self.markers.append(m)
            self.marker_layer.add_widget(m)
            self.marker_layer.reposition()
        m.lat = coord.lat
        m.lon = coord.lon
        self._update_geojson()
        return True

    def clear_markers(self):
        while self.markers:
            self.remove_marker(self.markers.pop())

    def remove_marker(self, m):
        m.mapview = m.editor = None
        self.marker_layer.remove_widget(m)
        if m in self.markers:
            self.markers.remove(m)
        self._update_geojson()

    def remove_marker_at(self, touch):
        pos = self.ids.mapview.to_local(*touch.pos)
        for marker in self.markers[:]:
            if marker.collide_point(*pos):
                self.remove_marker(marker)
                return True

    def finalize_object(self):
        if self.markers:
            geojson = self.current_layer.geojson
            if "properties" not in geojson:
                geojson["features"][0]["properties"] = {"title": self.title}
            else:
                geojson["features"][0]["properties"]["title"] = self.title
            self.result_layer.geojson["features"].extend(geojson["features"])
            self.ids.mapview.trigger_update(True)
        self.clear_markers()
        self.is_editing = False
        self.title = ""
        self._update_geojson()

    def save_geojson(self):
        with open(self.geojson_fn, "wb") as fd:
            json.dump(self.result_layer.geojson, fd)

    def _update_geojson(self):
        features = []
        if self.mode == "polygon":
            geotype = "Polygon"
            geocoords = lambda x: [x]
        else:
            geotype = "LineString"
            geocoords = lambda x: x

        # current commited path
        if self.markers:
            coordinates = [[c.lon, c.lat] for c in self.markers]
            features.append({
                "type": "Feature",
                "properties": {},
                "geometry": {
                    "type": geotype,
                    "coordinates": geocoords(coordinates)
                }
            })

        geojson = {"type": "FeatureCollection", "features": features}
        self.current_layer.geojson = geojson
        self.ids.mapview.trigger_update(True)

    def point_inside_polygon(self, x, y, poly):
        n = len(poly)
        inside = False
        p1x, p1y = poly[0]
        for i in range(n + 1):
            p2x, p2y = poly[i % n]
            if y > min(p1y, p2y) and y <= max(p1y, p2y) and x <= max(p1x, p2x):
                if p1y != p2y:
                    xinters = (y - p1y) * (p2x - p1x) / (p2y - p1y) + p1x
                if p1x == p2x or x <= xinters:
                    inside = not inside
            p1x, p1y = p2x, p2y
        return inside

    def select_feature(self, x, y):
        coord = self.ids.mapview.get_latlon_at(x, y)
        for feature in self.result_layer.geojson["features"]:
            if feature["type"] != "Feature":
                continue
            geometry = feature["geometry"]
            if geometry["type"] == "Polygon":
                if self.point_inside_polygon(coord.lon, coord.lat,
                                             geometry["coordinates"][0]):
                    return feature

    def edit_feature(self, feature):
        self.result_layer.geojson["features"].remove(feature)
        #self.current_layer.geojson = feature
        self.ids.mapview.trigger_update(True)
        self.title = feature.get("properties", {}).get("title", "")
        self.is_editing = True
        self.clear_markers()
        for c in feature["geometry"]["coordinates"][0]:
            m = EditorMarker(lon=c[0], lat=c[1])
            m.mapview = self.ids.mapview
            m.editor = self
            self.marker_layer.add_widget(m)
            self.markers.append(m)
        self._update_geojson()
示例#5
0
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