def get_visible_area(self): a = self.screenpoint2coord((0, 0)) b = self.screenpoint2coord((self.map_width, self.map_height)) return geo.Coordinate(min(a.lat, b.lat), min(a.lon, b.lon)), geo.Coordinate( max(a.lat, b.lat), max(a.lon, b.lon))
def fit_to_bounds(self, minlat, maxlat, minlon, maxlon): if minlat == maxlat and minlon == maxlon: self.set_center(geo.Coordinate(minlat, minlon)) self.set_zoom(self.get_max_zoom()) return logger.debug("Settings Bounds: lat(%f, %f) lon(%f, %f)" % (minlat, maxlat, minlon, maxlon)) req_deg_per_pix_lat = (maxlat - minlat) / self.map_height prop_zoom_lat = math.log( ((180.0 / req_deg_per_pix_lat) / self.tile_loader.TILE_SIZE), 2) req_deg_per_pix_lon = (maxlon - minlon) / self.map_width prop_zoom_lon = math.log( ((360.0 / req_deg_per_pix_lon) / self.tile_loader.TILE_SIZE), 2) target_zoom = math.floor(min(prop_zoom_lat, prop_zoom_lon)) logger.debug( "Proposed zoom lat: %f, proposed zoom lon: %f, target: %f" % (prop_zoom_lat, prop_zoom_lon, target_zoom)) center = geo.Coordinate((maxlat + minlat) / 2.0, (maxlon + minlon) / 2.0) logger.debug("New Center: %s" % center) self.set_center(center, False) self.set_zoom( max(min(target_zoom, self.get_max_zoom()), self.get_min_zoom()))
def fix_from_tuple(self, f, device): a = Fix() # check if this is an actual fix if (not f[1] & (location.GPS_DEVICE_LATLONG_SET | location.GPS_DEVICE_ALTITUDE_SET | location.GPS_DEVICE_TRACK_SET)): return a if f[0] in (location.GPS_DEVICE_MODE_NOT_SEEN, location.GPS_DEVICE_MODE_NO_FIX): return a # location independent data a.sats = device.satellites_in_use a.sats_known = device.satellites_in_view a.dgps = False #LOCATION_GPS_DEVICE_STATUS_DGPS_FIX The device has a DGPS fix. Deprecated: this constant is not used anymore. a.quality = 0 # if this fix is too old, discard it if f[2] == f[2]: # is not NaN a.timestamp = datetime.utcfromtimestamp(f[2]) else: a.timestamp = datetime.utcfromtimestamp(0) Fix.min_timediff = min(Fix.min_timediff, datetime.utcnow() - a.timestamp) # if this fix is too old, discard it if ((datetime.utcnow() - a.timestamp) - Fix.min_timediff).seconds > LocationGpsReader.TIMEOUT: logger.info( "Discarding fix: Timestamp diff is %d, should not be > %d" % (((datetime.utcnow() - a.timestamp) - Fix.min_timediff).seconds, LocationGpsReader.TIMEOUT)) return a # now on for location dependent data #if f[10] > Fix.BEARING_HOLD_EPD: # a.bearing = Fix.last_bearing #else: a.altitude = f[7] a.speed = f[11] if a.speed > self.BEARING_HOLD_SPEED: a.bearing = f[9] self.last_gps_bearing = a.bearing else: a.bearing = self.last_gps_bearing # Fix.last_bearing = a.bearing a.position = geo.Coordinate(f[4], f[5]) a.error = f[6] / 100.0 a.error_bearing = f[10] return a
def search(self, search, nearest_street=False): logger.info("Trying to search geonames for %s" % search) qurl = self.URL % {'query': self.my_quote(search), 'max_rows': 1} logger.debug("Query URL: %s" % qurl) page = self.downloader.get_reader(url=qurl, login=False).read() values = json.loads(page) if int(values['totalResultsCount']) == 0: raise Exception('No Record found for query "%s"' % search) res = values['geonames'][0] c = geo.Coordinate(float(res['lat']), float(res['lng']), search) logger.info("Using %s for query '%s'" % (c, search)) return c
def find_nearest_intersection(self, c): logger.info("trying to find nearest street...") url = self.URL_STREETS % (c.lat, c.lon) page = self.downloader.get_reader(url, login=False).read() values = json.loads(page) if (len(values) == 0): logger.warning( "Could NOT find nearest intersection to %s, using this" % c) return c intersection = values['intersection'] c = geo.Coordinate(float(intersection['lat']), float(intersection['lng'])) logger.info("Using nearest intersection at %s" % c) return c
def search_all(self, search, max_results=15, name_string="%(name)s, %(countryCode)s"): logger.info("Trying to search geonames for %s" % search) qurl = self.URL % { 'query': self.my_quote(search), 'max_rows': max_results } logger.debug("Query URL: %s" % qurl) page = self.downloader.get_reader(url=qurl, login=False).read() logger.debug("Result:\n%s\n" % page) values = json.loads(page) return [ geo.Coordinate(float(res['lat']), float(res['lng']), name_string % res) for res in values['geonames'] if 'countryCode' in res ]
def find_route(self, c1, c2, min_distance): page = self.downloader.get_reader(url=self.ORS_URL, values=self.ORS_DATA % (c1.lon, c1.lat, c2.lon, c2.lat), login=False).read() import xml.dom.minidom from xml.dom.minidom import Node doc = xml.dom.minidom.parseString(page) # @type doc xml.dom.minidom.Document errors = doc.getElementsByTagName('xls:Error') if len(errors) > 0: if errors[0].getAttribute( 'locationPath') == 'PathFinder - getPath()': raise Exception( "Could not find route. Please try another street as start or endpoint. The server said: ''%s''\n" % errors[0].getAttribute('message')) raise Exception("Could not find route. The server said: ''%s''\n" % errors[0].getAttribute('message')) segments = doc.getElementsByTagName('gml:LineString') route_points = [] # min_distance is in km, we need m mdist = (min_distance * 1000.0) / self.DIST_FACTOR for s in segments: for p in s.childNodes: if p.nodeType != Node.ELEMENT_NODE: continue lon, tmp, lat = p.childNodes[0].data.partition(' ') c = geo.Coordinate(float(lat), float(lon)) stop = False for o in route_points: if c.distance_to(o) < mdist: stop = True break if not stop: route_points.append(c) if len(route_points) > self.MAX_NODES: raise Exception("Too many waypoints! Try a bigger radius.") logger.info("Using the following Waypoints:") return route_points
def get_data(self): import random if self.index < len(self.data) - 1: self.index += 1 if self.data[self.index][0] == '0': return Fix() pos = geo.Coordinate(float(self.data[self.index][0]), float(self.data[self.index][1])) if self.lastpos != None: bearing = self.lastpos.bearing_to(pos) else: bearing = 0 self.lastpos = pos return Fix(position=pos, altitude=5, bearing=bearing, speed=4, sats=12, sats_known=6, dgps=True, quality=0, error=random.randrange(10, 100), error_bearing=10)
def get_target(): return geo.Coordinate(50.0000798795372000, 6.9949468020349700)
def get_data(self): try: if not self.connected: self.connect() if not self.connected: return self.EMPTY self.gpsd_connection.send("%s\r\n" % 'o') data = self.gpsd_connection.recv(512) self.gpsd_connection.send("%s\r\n" % 'y') quality_data = self.gpsd_connection.recv(512) # 1: Parse Quality Data # example output: # GPSD,Y=- 1243847265.000 10:32 3 105 0 0:2 36 303 20 0:16 9 65 26 # 1:13 87 259 35 1:4 60 251 30 1:23 54 60 37 1:25 51 149 24 0:8 2 # 188 0 0:7 33 168 24 1:20 26 110 28 1: if quality_data.strip() == "GPSD,Y=?": sats = 0 sats_known = 0 dgps = False else: sats = 0 dgps = False groups = quality_data.split(':') sats_known = int(groups[0].split(' ')[2]) for i in xrange(1, sats_known): sat_data = groups[i].split(' ') if sat_data[4] == "1": sats = sats + 1 if int(sat_data[0]) > 32: dgps = True if data.strip() == "GPSD,O=?": self.status = "No GPS signal" return Fix(sats=sats, sats_known=sats_known, dgps=dgps) # 2: Get current position, altitude, bearing and speed # example output: # GPSD,O=- 1243530779.000 ? 49.736876 6.686998 271.49 1.20 1.61 49.8566 0.050 -0.175 ? ? ? 3 # GPSD,O=- 1251325613.000 ? 49.734453 6.686360 ? 10.55 ? 180.1476 1.350 ? ? ? ? 2 # that means: # [tag, timestamp, time_error, lat, lon, alt, err_hor, err_vert, track, speed, delta_alt, err_track, err_speed, err_delta_alt, mode] # 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 # or # GPSD,O=? try: splitted = data.split(' ') lat, lon, alt, err_hor = splitted[3:7] track, speed = splitted[8:10] err_track = splitted[11] time = datetime.utcfromtimestamp(int(float(splitted[1]))) except: logger.info("GPSD Output: \n%s\n -- cannot be parsed." % data) self.status = "Could not read GPSD output." return Fix() alt = self.to_float(alt) track = self.to_float(track) speed = self.to_float(speed) err_hor = self.to_float(err_hor) err_track = self.to_float(err_track) # the following is probably wrong: # # it seems that gpsd doesn't take into account that the # receiver may get signals from space base augmentation systems # like egnos. therefore, we estimate that the error is about # self.DGPS_ADVANTAGE meters lower. this is a complete guess. if dgps: err_hor -= self.DGPS_ADVANTAGE if err_hor <= 0: quality = 1 elif err_hor > self.QUALITY_LOW_BOUND: quality = 0 else: quality = 1 - err_hor / self.QUALITY_LOW_BOUND # enable this to track speeds and see the max speed #self.speeds.append(speed) #print "Aktuell %f, max: %f" % (speed, max(self.speeds)) return Fix(position=geo.Coordinate(float(lat), float(lon)), altitude=alt, bearing=track, speed=speed, sats=int(sats), sats_known=sats_known, dgps=dgps, quality=quality, error=err_hor, error_bearing=err_track, timestamp=time) except Exception, e: logger.exception("Fehler beim Auslesen der Daten: %s " % e) return self.EMPTY
def draw(self): surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, self.map.map_width, self.map.map_height) cr = gtk.gdk.CairoContext(cairo.Context(surface)) coords = self.get_geocaches_callback(self.map.get_visible_area(), self.MAX_NUM_RESULTS_SHOW) if self.map.get_zoom() < self.CACHES_ZOOM_LOWER_BOUND: self.map.set_osd_message('Zoom in to see geocaches.') self.visualized_geocaches = [] self.result = surface return elif len(coords) >= self.MAX_NUM_RESULTS_SHOW: self.map.set_osd_message('Too many geocaches to display.') self.visualized_geocaches = [] self.result = surface return self.map.set_osd_message(None) self.visualized_geocaches = coords draw_short = (len(coords) > self.TOO_MANY_POINTS) default_radius = self.CACHE_DRAW_SIZE found, regular, multi, default = self.COLOR_FOUND, self.COLOR_REGULAR, self.COLOR_MULTI, self.COLOR_DEFAULT for c in coords: # for each geocache radius = default_radius if c.found: color = found elif c.type == geocaching.GeocacheCoordinate.TYPE_REGULAR: color = regular elif c.type == geocaching.GeocacheCoordinate.TYPE_MULTI: color = multi else: color = default cr.set_source_color(color) p = self.map.coord2point(c) if c.alter_lat != None and (c.alter_lat != 0 and c.alter_lon != 0): x = self.map.coord2point(geo.Coordinate(c.alter_lat, c.alter_lon)) if x != p: cr.move_to(p[0], p[1]) cr.line_to(x[0], x[1]) cr.set_line_width(2) cr.stroke() if draw_short: radius = radius / 2.0 if c.marked: cr.set_source_rgba(1, 1, 0, 0.5) cr.rectangle(p[0] - radius, p[1] - radius, radius * 2, radius * 2) cr.fill() cr.set_source_color(color) cr.set_line_width(4) cr.rectangle(p[0] - radius, p[1] - radius, radius * 2, radius * 2) cr.stroke() if draw_short: continue # if we have a description for this cache... if c.was_downloaded(): # draw something like: # ---- # ---- # ---- # besides the icon width = 6 dist = 3 count = 3 pos_x = p[0] + radius + 3 + 1 pos_y = p[1] + radius - (dist * count) + dist cr.set_line_width(1) for i in xrange(count): cr.move_to(pos_x, pos_y + dist * i) cr.line_to(pos_x + width, pos_y + dist * i) cr.set_line_width(2) cr.stroke() # if this cache is the active cache if self.current_cache != None and c.name == self.current_cache.name: cr.set_line_width(1) cr.set_source_color(self.COLOR_CURRENT_CACHE) #radius = 7 radius_outline = radius + 3 cr.rectangle(p[0] - radius_outline, p[1] - radius_outline, radius_outline * 2, radius_outline * 2) cr.stroke() # if this cache is disabled if c.status == geocaching.GeocacheCoordinate.STATUS_DISABLED: cr.set_line_width(3) cr.set_source_color(self.COLOR_DISABLED) radius_disabled = 7 cr.move_to(p[0]-radius_disabled, p[1]-radius_disabled) cr.line_to(p[0] + radius_disabled, p[1] + radius_disabled) cr.stroke() # if this cache is archived if c.status == geocaching.GeocacheCoordinate.STATUS_ARCHIVED: cr.set_line_width(3) cr.set_source_color(self.COLOR_ARCHIVED) radius_disabled = 7 cr.move_to(p[0]-radius_disabled, p[1]-radius_disabled) cr.line_to(p[0] + radius_disabled, p[1] + radius_disabled) cr.stroke() # print the name? if self.show_name: layout = self.map.create_pango_layout(AbstractGeocacheLayer.shorten_name(c.title, 20)) layout.set_font_description(self.CACHE_DRAW_FONT) width, height = layout.get_pixel_size() cr.move_to(p[0] + 4 + radius, p[1] - height + 2) #cr.set_line_width(1) cr.set_source_color(self.CACHE_DRAW_FONT_COLOR) cr.show_layout(layout) cr.set_source_color(self.COLOR_CACHE_CENTER) cr.set_line_width(1) cr.move_to(p[0], p[1] - 3) cr.line_to(p[0], p[1] + 3) # | cr.move_to(p[0] - 3, p[1],) cr.line_to(p[0] + 3, p[1]) # --- cr.stroke() # draw additional waypoints # --> print description! if self.current_cache != None: cr.set_source_color(self.COLOR_WAYPOINTS) cr.set_line_width(1) radius = 5 num = 0 seen = ["%9.6f %9.6f" % (self.current_cache.lat, self.current_cache.lon)] for w in self.current_cache.get_collected_coordinates(format = self.current_cache.FORMAT_DM, include_unknown = False).values(): text = "%9.6f %9.6f" % (w.lat, w.lon) if text in seen: continue seen.append(text) num = num + 1 p = self.map.coord2point(w) if not self.map.point_in_screen(p): continue cr.move_to(p[0], p[1] - radius) cr.line_to(p[0], p[1] + radius) # | #cr.stroke() cr.move_to(p[0] - radius, p[1]) cr.line_to(p[0] + radius, p[1]) # --- #cr.stroke() cr.arc(p[0], p[1], radius, 0, math.pi * 2) layout = self.map.create_pango_layout('') layout.set_markup('<i>%s</i>' % (self.shorten_name(w.display_text, 25))) layout.set_font_description(self.CACHE_DRAW_FONT) cr.move_to(p[0] + 3 + radius, p[1] - 3 - radius) #cr.set_line_width(1) cr.set_source_color(self.COLOR_WAYPOINTS) cr.show_layout(layout) cr.stroke() self.result = surface
def num2deg(self, xtile, ytile): n = 2**self.zoom lon_deg = xtile / n * 360.0 - 180.0 lat_rad = math.atan(math.sinh(math.pi * (1 - 2 * ytile / n))) lat_deg = lat_rad * 180.0 / math.pi return geo.Coordinate(lat_deg, lon_deg)