def _build_stop(self, stop, osm_type): """Helper function to build a Stop object Returns a initiated Stop object from raw data """ if self._is_valid_stop_candidate(stop): # Make sure name is not empty if "name" not in stop.tags: stop.tags["name"] = "[{}]".format(self.stop_no_name) # Ways don't have a pair of coordinates and need to be calculated if osm_type == "way": (stop.lat, stop.lon) = Helper.get_center_of_nodes( stop.get_nodes()) # Move to Elements class, once attributes with defaults play well # with inheritance https://github.com/python-attrs/attrs/issues/38 osm_url = "https://osm.org/" + str( osm_type) + "/" + str(stop.id) # Create and return Stop object stop = Stop(osm_id=stop.id, osm_type=osm_type, osm_url=osm_url, tags=stop.tags, name=stop.tags['name'], lat=stop.lat, lon=stop.lon) return stop else: logging.warning( "Warning: Potential stop is invalid and has been ignored.") logging.warning( " Check tagging: https://osm.org/%s/%s", osm_type, stop.id) return None
def _find_best_name_for_unnamed_stop(self, stop): """Define name for stop without explicit name based on sourroundings """ api = overpy.Overpass() result = api.query(""" <osm-script> <query type="way"> <around lat="%s" lon="%s" radius="50.0"/> <has-kv k="name" /> <has-kv modv="not" k="highway" v="trunk"/> <has-kv modv="not" k="highway" v="primary"/> <has-kv modv="not" k="highway" v="secondary"/> <has-kv modv="not" k="amenity" v="bus_station"/> </query> <print order="quadtile"/> <query type="node"> <around lat="%s" lon="%s" radius="50.0"/> <has-kv k="name"/> <has-kv modv="not" k="highway" v="bus_stop"/> </query> <print order="quadtile"/> </osm-script> """ % (stop.lat, stop.lon, stop.lat, stop.lon)) candidates = [] # get all node candidates for node in result.get_nodes(): if 'name' in node.tags and node.tags["name"] is not None: candidates.append(node) # get way node candidates for way in result.get_ways(): if 'name' in way.tags and way.tags["name"] is not None: candidates.append(way) # leave if no candidates if len(candidates) == 0: # give stop a different name, so we won't search again without # refreshing data stop.name = self.stop_no_name return # find closest candidate winner = None winner_distance = sys.maxint for candidate in candidates: if isinstance(candidate, overpy.Way): lat, lon = Helper.get_center_of_nodes( candidate.get_nodes(resolve_missing=True)) distance = util.ApproximateDistance(lat, lon, stop.lat, stop.lon) else: distance = util.ApproximateDistance(candidate.lat, candidate.lon, stop.lat, stop.lon) if distance < winner_distance: winner = candidate winner_distance = distance # take name from winner stop.name = winner.tags["name"]
def _build_station(self, stop_area, osm_type): """Helper function to build Station objects from stop_areas The function creates a Station object for the stop_area flagged as location_type = 1. This means station, that can group stops. The members of this relation add this station their parent. Returns a initiated Station object from raw data """ # Check relation to be a station or used differently if 'route' in stop_area.tags: return None else: # Check tagging whether this is a stop area. if 'public_transport' not in stop_area.tags: logging.warning( "Potential station has no public_transport tag.") logging.warning(" Please fix on OSM: https://osm.org/%s/%s", osm_type, stop_area.id) return None elif stop_area.tags['public_transport'] != 'stop_area': logging.warning( "Warning: Potential station is not tagged as stop_area.") logging.warning(" Please fix on OSM: https://osm.org/%s/%s", osm_type, stop_area.id) return None # Analzyse member objects (stops) of this stop area members = {} for member in stop_area.members: if member.role == "platform": if isinstance(member, overpy.RelationNode): member_osm_type = "node" elif isinstance(member, overpy.RelationWay): member_osm_type = "way" identifier = member_osm_type + "/" + str(member.ref) if identifier in self.stops['regular']: # Collect the Stop objects that are members # of this Station members[identifier] = self.stops['regular'][identifier] else: logging.error("Station member was not found in data") logging.error(" https://osm.org/relation/%s", stop_area.id) logging.error(" https://osm.org/node/%s", member.ref) if len(members) < 1: # Stop areas with only one stop, are not stations they just # group different elements of one stop together. logging.error("Station with no members has been discarted:") logging.error(" https://osm.org/relation/%s", stop_area.id) return None elif len(members) == 1: logging.warning( "OSM stop area has only one platform and can't be used as a GTFS station:" ) logging.warning(" https://osm.org/relation/%s", stop_area.id) return None # Check name of stop area if 'name' not in stop_area.tags: logging.warning( "Stop area without name. Please fix in OpenStreetMap:") logging.warning(" https://osm.org/relation/%s", stop_area.id) stop_area.name = self.stop_no_name else: stop_area.name = stop_area.tags["name"] # Calculate coordinates for stop area based on the center of it's # members stop_area.lat, stop_area.lon = Helper.get_center_of_nodes( members.values()) # Move to Elements class, once attributes with defaults play well # with inheritance https://github.com/python-attrs/attrs/issues/38 osm_url = "https://osm.org/" + str(osm_type) + "/" + str(stop_area.id) # Create and return Station object station = Station(osm_id=stop_area.id, osm_type=osm_type, osm_url=osm_url, tags=stop_area.tags, name=stop_area.name, lat=stop_area.lat, lon=stop_area.lon) station.set_members(members) logging.info( "Stop area (OSM) has been used to create a station (GTFS):\n") logging.info(" https://osm.org/relation/%s\n", str(stop_area.id)) return station