def nearby(query, near, radius, params): """Return X, Y and a list of dictionaries of places matching `query`.""" query = urllib.parse.quote_plus(query) sort_by_distance = str(int(poor.conf.guides.foursquare.sort_by_distance)) x, y = prepare_point(near) url = EXPLORE_URL.format(**locals()) with poor.util.silent(KeyError): return copy.deepcopy(cache[url]) results = poor.http.get_json(url) results = poor.AttrDict(results) results = [ poor.AttrDict( id=item.venue.id, title=item.venue.name, description=parse_description(item.venue), text=parse_text(item.venue), link=get_link(item.venue.id), x=float(item.venue.location.lng), y=float(item.venue.location.lat), ) for item in itertools.chain.from_iterable( group["items"] for group in results.response.get("groups", [])) ] with poor.util.silent(Exception, tb=True): inject_venue_details(results) if results and results[0]: cache[url] = copy.deepcopy((x, y, results)) return x, y, results
def route(fm, to, heading, params): """Find route and return its properties as a dictionary.""" fm, to = map(prepare_endpoint, (fm, to)) if heading is not None: fm["heading"] = heading lang = poor.util.get_default_language("en") input = dict(locations=[fm, to], costing=poor.conf.routers.mapzen.type, directions_options=dict(language=lang)) input = urllib.parse.quote(json.dumps(input)) url = URL.format(**locals()) with poor.util.silent(KeyError): return copy.deepcopy(cache[url]) result = poor.http.get_json(url) result = poor.AttrDict(result) legs = result.trip.legs[0] x, y = poor.util.decode_epl(legs.shape, precision=6) maneuvers = [ dict( x=float(x[maneuver.begin_shape_index]), y=float(y[maneuver.begin_shape_index]), icon=ICONS.get(maneuver.type, "flag"), narrative=maneuver.instruction, duration=float(maneuver.time), ) for maneuver in legs.maneuvers ] route = dict(x=x, y=y, maneuvers=maneuvers, mode="car") route["attribution"] = poor.util.get_routing_attribution("Mapzen") if route and route["x"]: cache[url] = copy.deepcopy(route) return route
def route(locations, params): """Find route and return its properties as a dictionary.""" loc = list(map(prepare_endpoint, locations)) heading = params.get('heading', None) optimized = params.get('optimized', False) if len(loc) > 3 else False if heading is not None: loc[0]["heading"] = heading language = poor.conf.routers.stadiamaps.language units = "kilometers" if poor.conf.units == "metric" else "miles" ctype = poor.conf.routers.stadiamaps.type if ctype == "auto" and poor.conf.routers.stadiamaps.shorter: ctype = "auto_shorter" co = {key: poor.conf.routers.stadiamaps[key] for key in MODEOPTIONS[ctype]} costing_options = {} costing_options[ctype] = co input = dict(locations=loc, costing=ctype, costing_options=costing_options, directions_options=dict(language=language, units=units)) input = urllib.parse.quote(json.dumps(input)) if optimized: url = URL_OPT.format(**locals()) else: url = URL.format(**locals()) with poor.util.silent(KeyError): return copy.deepcopy(cache[url]) result = poor.http.get_json(url) result = poor.AttrDict(result) mode = MODE.get(ctype, "car") return parse_result_valhalla(url, locations, optimized, result, mode)
def parse_legs(legs): """Parse legs from routing result.""" legs = [ poor.AttrDict( mode=leg.mode, mode_name=MODE_NAMES.get(leg.mode, "BUS"), color=COLORS.get(leg.mode, "BUS"), agency=parse_agency(leg), line=parse_line(leg), line_desc=parse_line_description(leg), length=float(leg.distance), duration=float(leg.duration), real_time=leg.realTime, dep_name=leg["from"].name, dep_x=float(leg["from"].lon), dep_y=float(leg["from"].lat), dep_time=parse_time(leg.startTime), dep_unix=float(leg.startTime) / 1000, arr_name=leg.to.name, arr_x=float(leg.to.lon), arr_y=float(leg.to.lat), arr_time=parse_time(leg.endTime), arr_unix=float(leg.endTime) / 1000, x=poor.util.decode_epl(leg.legGeometry.points, precision=5)[0], y=poor.util.decode_epl(leg.legGeometry.points, precision=5)[1], stops_x=[float(x.lon) for x in leg.intermediateStops or []], stops_y=[float(x.lat) for x in leg.intermediateStops or []], ) for leg in legs ] merge_bad_legs(legs) return legs
def route(fm, to, heading, params): """Find route and return its properties as a dictionary.""" fm, to = map(prepare_endpoint, (fm, to)) if heading is not None: fm["heading"] = heading language = poor.conf.routers.osmscout.language units = "kilometers" if poor.conf.units == "metric" else "miles" ctype = poor.conf.routers.osmscout.type if ctype == "auto" and poor.conf.routers.osmscout.shorter: ctype = "auto_shorter" co = {key: poor.conf.routers.osmscout[key] for key in MODEOPTIONS[ctype]} costing_options = {} costing_options[ctype] = co input = dict(locations=[fm, to], costing=ctype, costing_options=costing_options, directions_options=dict(language=language, units=units)) input = urllib.parse.quote(json.dumps(input)) url = URL.format(**locals()) with poor.util.silent(KeyError): return copy.deepcopy(cache[url]) result = poor.http.get_json(url) result = poor.AttrDict(result) mode = MODE.get(ctype,"car") if result.get("API version", "") == "libosmscout V1": return parse_result_libosmscout(url, result, mode) return parse_result_valhalla(url, result, mode)
def make(self, text, preserve=False): """Queue `text` for WAV file generation.""" if self._engine is None: return self._update_cache() self._used_counter += 1 if text in self._cache: # WAV file already generated, just update # file modification time to prevent removal. if self._cache[text] is not None: self._cache[text].used = self._used_counter return if self._worker_thread is None: self._result_queue = queue.Queue() self._task_queue = queue.Queue() self._worker_thread = threading.Thread( target=voice_worker, kwargs=dict(task_queue=self._task_queue, result_queue=self._result_queue, engine=self._engine, tmpdir=self._tmpdir), daemon=True) self._worker_thread.start() # Add an empty element into cache to ensure that we don't # run the same voice direction twice through the engine. self._cache[text] = poor.AttrDict(fname=None, preserve=preserve, text=text, used=self._used_counter) self._task_queue.put(text) self._clean_outdated_cache()
def nearby(query, near, radius, params): """Return X, Y and a list of dictionaries of places matching `query`.""" query = urllib.parse.quote_plus(query) limit = params.get("limit", 50) if isinstance(near, (list, tuple)): x, y = near[0], near[1] url = URL_XY.format(**locals()) else: search = urllib.parse.quote_plus(near) url = URL_SEARCH.format(**locals()) with poor.util.silent(KeyError): return copy.deepcopy(cache[url]) results = poor.http.get_json(url) results = poor.AttrDict(results) x = float(results.origin.lng) y = float(results.origin.lat) results = [dict( title=result.title, description=parse_description(result), x=float(result.lng), y=float(result.lat), ) for result in results.results] if results and results[0]: results = poor.util.sorted_by_distance(results, x, y) cache[url] = copy.deepcopy((x, y, results)) return x, y, results
def reverse(x, y, radius, limit=25, params={}): """Return a list of dictionaries of places nearby given coordinates.""" lng = x lat = y url = URL_REVERSE.format(**locals()) with poor.util.silent(KeyError): return copy.deepcopy(cache[url]) results = poor.http.get_json(url) results = poor.AttrDict(results) results = [ dict( address=parse_address(result), link=result.get("website", ""), phone=result.get("phone", ""), poi_type=parse_type(result), postcode=result.get("postal_code", ""), title=result.title, description=parse_description(result), distance=float(result.distance), x=float(result.lng), y=float(result.lat), ) for result in results.results ] if results and results[0]: cache[url] = copy.deepcopy(results) return results
def get_recursive(item, level=1): children = item.get("categories", []) children = list( itertools.chain.from_iterable( get_recursive(x, level=level + 1) for x in children)) return [ poor.AttrDict( id=item.get("id"), label=item.get("name"), level=level) ] + children
def parse_maneuvers(route): """Parse list of maneuvers from the legs of `route`.""" if not route.legs: return [] maneuvers = [] prev_mode = "w" modes = dict(WALK="w", BICYCLE="b") for i, leg in enumerate(route.legs): this_mode = modes.get(leg.mode, "t") key = prev_mode + this_mode # Handle the last leg differently since OpenTripPlanner # gives "Destination" as the destination name. if i == len(route.legs) - 1: key = key[0] + "a" narrative = NARRATIVE[key].format(**leg) narrative = re.sub(r"\.\.+$", ".", narrative) maneuvers.append( poor.AttrDict(x=leg.dep_x, y=leg.dep_y, icon="flag", narrative=narrative, duration=leg.duration)) if this_mode == "t": # Add intermediate stops as passive maneuver points. maneuvers.extend([ poor.AttrDict( x=leg.stops_x[i], y=leg.stops_y[i], passive=True, ) for i in range(len(leg.stops_x)) ]) prev_mode = this_mode maneuvers.append( poor.AttrDict(x=route.legs[-1].arr_x, y=route.legs[-1].arr_y, icon="flag", narrative=_("Arrive at your destination."), duration=0)) # For clarity, move stops to the nearest point # on the route polyline. for maneuver in maneuvers: i = poor.util.find_closest(route.x, route.y, maneuver.x, maneuver.y) maneuver.x = route.x[i] maneuver.y = route.y[i] return maneuvers
def _split_option(self, option, create=False): """Split dotted option to dictionary and option name.""" root = self for section in option.split(".")[:-1]: if create and section not in root: # Create missing hierarchies. root[section] = poor.AttrDict() root = root[section] name = option.split(".")[-1] return root, name
def route(fm, to, heading, params): """Find route and return its properties as a dictionary.""" fm, to = map(prepare_endpoint, (fm, to)) if heading is not None: fm["heading"] = heading language = poor.conf.routers.stadiamaps.language units = "kilometers" if poor.conf.units == "metric" else "miles" ctype = poor.conf.routers.stadiamaps.type if ctype == "auto" and poor.conf.routers.stadiamaps.shorter: ctype = "auto_shorter" co = {key: poor.conf.routers.stadiamaps[key] for key in MODEOPTIONS[ctype]} costing_options = {} costing_options[ctype] = co input = dict(locations=[fm, to], costing=ctype, costing_options=costing_options, directions_options=dict(language=language, units=units)) input = urllib.parse.quote(json.dumps(input)) url = URL.format(**locals()) with poor.util.silent(KeyError): return copy.deepcopy(cache[url]) result = poor.http.get_json(url) result = poor.AttrDict(result) legs = result.trip.legs[0] x, y = poor.util.decode_epl(legs.shape, precision=6) maneuvers = [ dict( x=float(x[maneuver.begin_shape_index]), y=float(y[maneuver.begin_shape_index]), icon=ICONS.get(maneuver.type, "flag"), narrative=maneuver.instruction, sign=dict(exit_branch=parse_exit(maneuver, "exit_branch_elements"), exit_name=parse_exit(maneuver, "exit_name_elements"), exit_number=parse_exit(maneuver, "exit_number_elements"), exit_toward=parse_exit(maneuver, "exit_toward_elements")), street=maneuver.get("begin_street_names", maneuver.get("street_names", None)), arrive_instruction=maneuver.get("arrive_instruction", None), depart_instruction=maneuver.get("depart_instruction", None), travel_type=maneuver.get("travel_type", None), verbal_alert=maneuver.get("verbal_transition_alert_instruction", None), verbal_pre=maneuver.get("verbal_pre_transition_instruction", None), verbal_post=maneuver.get("verbal_post_transition_instruction", None), duration=float(maneuver.time), ) for maneuver in legs.maneuvers ] route = dict(x=x, y=y, maneuvers=maneuvers, mode=MODE.get(ctype, "car")) route["language"] = result.trip.language if route and route["x"]: cache[url] = copy.deepcopy(route) return route
def get_types(): """Return a list of available venue types.""" results = poor.http.get_json(CATEGORIES_URL) results = poor.AttrDict(results) def get_recursive(item, level=1): children = item.get("categories", []) children = list(itertools.chain.from_iterable( get_recursive(x, level=level+1) for x in children)) return [poor.AttrDict(label=item.get("name"), level=level)] + children types = list(get_recursive(results.response)) return list(filter(lambda x: x.label, types))
def _register(self, values, root=None, defaults=None): """Add entries for `values` if missing.""" if root is None: root = self if defaults is None: defaults = DEFAULTS for name, value in values.items(): if isinstance(value, dict): self._register(values[name], root.setdefault(name, poor.AttrDict()), defaults.setdefault(name, {})) continue # Do not change values if they already exist. root.setdefault(name, copy.deepcopy(value)) defaults.setdefault(name, copy.deepcopy(value))
def route(fm, to, heading, params): """Find routes and return their properties as dictionaries.""" fm, to = map(prepare_endpoint, (fm, to)) region = poor.conf.routers.digitransit.region url = URL.format(**locals()) modes = ",".join(poor.conf.routers.digitransit.modes) # Add optional parameters, None if missing. date = params.get("date", None) time = params.get("time", None) if date is None and time is not None: date = datetime.date.today().isoformat() arrive_by = params.get("arrive_by", None) optimize = poor.conf.routers.digitransit.optimize transfer_penalty = (600 if optimize == "least-transfers" else None) walk_reluctance = (10 if optimize == "least-walking" else None) body = BODY.format(**locals()) body = re.sub(r"^.*\bNone\b.*$", "", body, flags=re.MULTILINE) body = "\n".join(x for x in body.splitlines() if x) result = poor.http.post_json(url, body, headers=HEADERS) result = poor.AttrDict(result) itineraries = result.data.plan.itineraries routes = [ poor.AttrDict( alternative=i + 1, length=sum(x.distance for x in itinerary.legs), duration=float(itinerary.duration), legs=parse_legs(itinerary.legs), ) for i, itinerary in enumerate(itineraries) ] for route in routes: route.x = [] route.y = [] for leg in route.legs: route.x.extend(leg.pop("x")) route.y.extend(leg.pop("y")) route.maneuvers = parse_maneuvers(route) route.mode = "transit" route.attribution = poor.util.get_routing_attribution("Digitransit") return routes
def autocomplete_type(query, params=None): """Return a list of autocomplete dictionaries matching `query`.""" if len(query) < 2: return [] query = urllib.parse.quote_plus(query) url = CATEGORY_URL.format(**locals()) with poor.util.silent(KeyError): return copy.deepcopy(cache[url]) results = poor.http.get_json(url) results = poor.AttrDict(results) results = [ dict(label=r.displayString, sic=r.sic[0]) for r in results.results ] cache[url] = copy.deepcopy(results) return results
def autocomplete_type(query, params=None): """Return a list of autocomplete dictionaries matching `query`.""" def normalize(x): # Relax matching for the common case of cafe vs. café. return x.lower().replace("é", "e") query = normalize(query) results = [] for i, type in enumerate(get_types()): pos = normalize(type.label).find(query) if pos < 0: continue results.append(poor.AttrDict( label=type.label, order=(pos, type.level, type.label), )) results.sort(key=lambda x: x.order) results = [{"label": x["label"]} for x in results] return results[:100]
def route(locations, params): """Find route and return its properties as a dictionary.""" loc = list(map(prepare_endpoint, locations)) if len(loc) < 2: return None loc[0]["type"] = "break" # pass through not supported for origin heading = params.get('heading', None) if heading is not None: loc[0]["heading"] = heading lang = poor.conf.routers.here.language units = "metric" if poor.conf.units == "metric" else "imperial" transportMode = poor.conf.routers.here.type traffic = poor.conf.routers.here.traffic routingMode = "short" if poor.conf.routers.here.shorter else "fast" origin = prepare_txtpoint(loc[0]) destination = prepare_txtpoint(loc[-1]) via = '' for point in loc[1:-1]: via += "&via=" + prepare_txtpoint(point) avoid = [] if poor.conf.routers.here.avoid_car_train: avoid.append("carShuttleTrain") if transportMode == "truck" and poor.conf.routers.here.avoid_difficult_turn: avoid.append("difficultTurns") if poor.conf.routers.here.avoid_dirt: avoid.append("dirtRoad") if poor.conf.routers.here.avoid_highway: avoid.append("controlledAccessHighway") if poor.conf.routers.here.avoid_ferry: avoid.append("ferry") if poor.conf.routers.here.avoid_seasonal_closure: avoid.append("seasonalClosure") if poor.conf.routers.here.avoid_toll: avoid.append("tollRoad") if poor.conf.routers.here.avoid_tunnel: avoid.append("tunnel") if len(avoid) > 0: avoid = "&avoid[features]=" + (",".join(avoid)) else: avoid = "" # skip cache if traffic update is expected skip_cache = traffic and transportMode in (["car", "bus", "taxi"]) url = URL.format(**locals()) + via + avoid if not traffic: url += "&departureTime=any" if not skip_cache: with poor.util.silent(KeyError): return copy.deepcopy(cache[url]) result = poor.http.get_json(url) result = poor.AttrDict(result) mode = MODE.get(transportMode, "car") return parse_result(url, locations, result, mode, lang, loc)
def route(locations, params): """Find route and return its properties as a dictionary.""" locstring = ";".join(map(prepare_endpoint, locations)) heading = params.get('heading', None) optimized = params.get('optimized', False) if len(locations) > 3 else False if optimized: url = URL_OPT.format(**locals()) else: url = URL.format(**locals()) with poor.util.silent(KeyError): return copy.deepcopy(cache[url]) routes = "trips" if optimized else "routes" result = poor.http.get_json(url) waypoints = result["waypoints"] result = poor.AttrDict(result[routes][0]) x, y = poor.util.decode_epl(result.geometry) maneuvers, loc_index = [], [0] for leg in result.legs: maneuvers.extend([ dict( x=float(step.maneuver.location[0]), y=float(step.maneuver.location[1]), icon=parse_icon(step.maneuver), narrative=parse_narrative(step.maneuver, step.get("name", "")), duration=float(step.duration), roundabout_exit_count=step.maneuver.get("exit", None), ) for step in leg.steps ]) loc_index.append(loc_index[-1] + len(leg.annotation.nodes) - 1) if optimized: li = {waypoints[i]["waypoint_index"]: i for i in range(len(waypoints))} locations = [locations[li[i]] for i in range(len(waypoints))] route = dict(x=x, y=y, locations=locations, location_indexes=loc_index, maneuvers=maneuvers, mode="car", optimized=optimized) route["language"] = "en_US" if route and route["x"]: cache[url] = copy.deepcopy(route) return route
def _update(self, values, root=None, defaults=None, path=()): """Load values of options after validation.""" if root is None: root = self if defaults is None: defaults = DEFAULTS for name, value in values.items(): if isinstance(value, dict): self._update(value, root.setdefault(name, poor.AttrDict()), defaults.setdefault(name, {}), path + (name, )) continue try: if name in defaults: # Be liberal, but careful in what to accept. value = self._coerce(value, defaults[name]) root[name] = copy.deepcopy(value) except Exception as error: full_name = ".".join(path + (name, )) print("Discarding bad option-value pair {}, {}: {}".format( repr(full_name), repr(value), str(error)), file=sys.stderr)
def route(fm, to, heading, params): """Find route and return its properties as a dictionary.""" fm, to = map(prepare_endpoint, (fm, to)) if heading is not None: fm["heading"] = heading lang = poor.util.get_default_language("en") input = dict(locations=[fm, to], costing=poor.conf.routers.osmscout.type, directions_options=dict(language=lang)) input = urllib.parse.quote(json.dumps(input)) url = URL.format(**locals()) with poor.util.silent(KeyError): return copy.deepcopy(cache[url]) result = poor.http.get_json(url) result = poor.AttrDict(result) if result.get("API version", "") == "libosmscout V1": return parse_result_libosmscout(url, result) return parse_result_valhalla(url, result)
def route(fm, to, heading, params): """Find route and return its properties as a dictionary.""" fname = poor.conf.routers.gpx_osmscout.file language = poor.conf.routers.gpx_osmscout.language rev = poor.conf.routers.gpx_osmscout.reverse units = "kilometers" if poor.conf.units == "metric" else "miles" ctype = poor.conf.routers.gpx_osmscout.type x, y = poor.util.read_gpx(fname) shape = [dict(lat=y[i], lon=x[i]) for i in range(len(x))] if rev: shape = list(reversed(shape)) input = dict(shape=shape, shape_match="map_snap", costing=ctype, directions_options=dict(language=language, units=units)) input = json.dumps({'json': json.dumps(input)}) result = poor.http.post_json(URL, input) result = poor.AttrDict(result) mode = MODE.get(ctype, "car") return parse_result_valhalla(result, mode)
def nearby(query, near, radius, params): """Return X, Y and a list of dictionaries of places matching `query`.""" query = urllib.parse.quote_plus(query) limit = params.get("limit", 50) name = params.get("name", "") name = urllib.parse.quote_plus(name) route_search = params.get("alongRoute", False) route = params.get("route", {}) use_reference = params.get("fromReference", True) if route_search and not use_reference: url = URL_ROUTEONLY.format(**locals()) elif isinstance(near, (list, tuple)): x, y = near[0], near[1] url = URL_XY.format(**locals()) else: search = urllib.parse.quote_plus(near) url = URL_SEARCH.format(**locals()) if route_search: results = poor.http.post_json(url, json.dumps(route)) else: with poor.util.silent(KeyError): return copy.deepcopy(cache[url]) results = poor.http.get_json(url) results = poor.AttrDict(results) x = float(results.origin.lng) y = float(results.origin.lat) results = [ dict( address=parse_address(result), link=result.get("website", ""), phone=result.get("phone", ""), poi_type=parse_type(result), postcode=result.get("postal_code", ""), title=result.title, description=parse_description(result), distance=float(result.distance), x=float(result.lng), y=float(result.lat), ) for result in results.results ] if not route_search and results and results[0]: cache[url] = copy.deepcopy((x, y, results)) return x, y, results
def route(fm, to, heading, params): """Find route and return its properties as a dictionary.""" fm, to = map(prepare_endpoint, (fm, to)) type = poor.conf.routers.mapquest_open.type locale = poor.conf.routers.mapquest_open.language locale = (locale if locale in SUPPORTED_LOCALES else "en_US") url = URL.format(**locals()) if type == "fastest": # Assume all avoids are related to cars. for avoid in poor.conf.routers.mapquest_open.avoids: url += "&avoids={}".format(urllib.parse.quote_plus(avoid)) with poor.util.silent(KeyError): return copy.deepcopy(cache[url]) result = poor.http.get_json(url) result = poor.AttrDict(result) x, y = poor.util.decode_epl(result.route.shape.shapePoints) maneuvers = [] for leg in result.route.legs: maneuvers.extend(leg.maneuvers) maneuvers = [ dict( x=float(maneuver.startPoint.lng), y=float(maneuver.startPoint.lat), icon=ICONS.get(maneuver.turnType, "flag"), narrative=maneuver.narrative, duration=float(maneuver.time), street=maneuver.get("streets", None), ) for maneuver in maneuvers ] if len(maneuvers) > 1: maneuvers[0]["icon"] = "depart" maneuvers[-1]["icon"] = "arrive" mode = MODE.get(type, "car") route = dict(x=x, y=y, maneuvers=maneuvers, mode=mode) route["language"] = locale if route and route["x"]: cache[url] = copy.deepcopy(route) return route
def route(fm, to, heading, params): """Find route and return its properties as a dictionary.""" fm, to = map(prepare_endpoint, (fm, to)) url = URL.format(**locals()) with poor.util.silent(KeyError): return copy.deepcopy(cache[url]) result = poor.http.get_json(url)["routes"][0] result = poor.AttrDict(result) x, y = poor.util.decode_epl(result.geometry) maneuvers = [ dict( x=float(step.maneuver.location[0]), y=float(step.maneuver.location[1]), icon=parse_icon(step.maneuver), narrative=parse_narrative(step.maneuver, step.get("name", "")), duration=float(step.duration), ) for step in result.legs[0].steps ] route = dict(x=x, y=y, maneuvers=maneuvers, mode="car") route["language"] = "en_US" if route and route["x"]: cache[url] = copy.deepcopy(route) return route
def parse_result(url, locations, result, mode, lang_translation, locations_processed): """Parse and return route""" X, Y, Man, LocPointInd = [], [], [], [0] location_candidates = [] for legs in result.routes[0].sections: x, y = [], [] for p in poor.flexpolyline.decode(legs.polyline): x.append(p[1]) y.append(p[0]) instructions = {i.offset: i.instruction for i in legs.actions} language = legs.language transport_mode = legs.transport.mode maneuvers = [] if "preActions" in legs: for maneuver in legs.preActions: m = dict( x=float(x[0]), y=float(y[0]), ) m.update( process_maneuver(maneuver, transport_mode=transport_mode, language=language, lang_translation=lang_translation, fill_narrative=True)) maneuvers.append(m) # preprocess roundabouts for i in range(len(legs.turnByTurnActions) - 1): m0 = legs.turnByTurnActions[i] m1 = legs.turnByTurnActions[i + 1] if m0.action == "roundaboutEnter" and m1.action == "roundaboutExit": m0["exit"] = m1.get("exit", None) for maneuver in legs.turnByTurnActions: m = dict( x=float(x[maneuver.offset]), y=float(y[maneuver.offset]), narrative=instructions.get(maneuver.offset, None), ) m.update( process_maneuver(maneuver, transport_mode=transport_mode, language=language, lang_translation=lang_translation, fill_narrative=(m["narrative"] is None))) maneuvers.append(m) if "postActions" in legs: for maneuver in legs.postActions: m = dict( x=float(x[-1]), y=float(y[-1]), ) m.update( process_maneuver(maneuver, transport_mode=transport_mode, language=language, lang_translation=lang_translation, fill_narrative=True)) maneuvers.append(m) X.extend(x) Y.extend(y) Man.extend(maneuvers) location_candidates.append( poor.AttrDict(dict(index=len(X) - 1, x=x[-1], y=y[-1]))) # HERE sets segments not always by waypoints. When boarding a # ferry, segment can be introduced without waypoint. When having # pass through waypoint, it is not reflected in segments ic = 0 while len(LocPointInd) < len(locations_processed) - 1: target = locations_processed[len(LocPointInd)] if target["type"] == "break_through": LocPointInd.append(-1) # will be found by navigator continue t_lat = target["lat"] t_lon = target["lon"] delta = [ calculate_distance(c.x, c.y, t_lon, t_lat) for c in location_candidates[ic:-1] ] # move along locations and accept one which is reasonable # and close enough to the location. have to handle the # case where the same location is in the route multiple # times min_i = min(range(len(delta)), key=delta.__getitem__) min_v = delta[min_i] # check if we have multiple minima mins = [min_i] for i in range(1, len(delta) - 1): if i != min_i and delta[i] < 1.1 * min_v and delta[ i - 1] > delta[i] and delta[i + 1] > delta[i]: mins.append(i) # get the first minimum ic = ic + min(mins) LocPointInd.append(location_candidates[ic].index) ic += 1 # add last location LocPointInd.append(location_candidates[-1].index) if len(LocPointInd) != len(locations_processed): print( "Error while filling location indexes. Please file and issue at the project page" ) print("Data:", locations_processed, location_candidates, LocPointInd) return dict() route = dict(x=X, y=Y, locations=locations, location_indexes=LocPointInd, maneuvers=Man, mode=mode) route["language"] = result.routes[0].sections[0].language.replace("-", "_") if route and route["x"]: cache[url] = copy.deepcopy(route) return route
def route(locations, params): """Find route and return its properties as a dictionary.""" loc = list(map(prepare_endpoint, locations)) heading = params.get('heading', None) optimized = params.get('optimized', False) if len(loc) > 3 else False type = poor.conf.routers.mapquest_open.type locale = poor.conf.routers.mapquest_open.language locale = (locale if locale in SUPPORTED_LOCALES else "en_US") service = "optimizedroute" if optimized else "route" url = URL.format(**locals()) options = dict(ambiguities="ignore", unit="k", routeType=type, doReverseGeocode=False, shapeFormat="cmp", generalize=5, manMaps=False, locale=locale) if type == "fastest": # Assume all avoids are related to cars. options["avoids"] = poor.conf.routers.mapquest_open.avoids input = dict(locations=loc, options=options) input = json.dumps(input) with poor.util.silent(KeyError): return copy.deepcopy(cache[url + input]) result = poor.http.post_json(url, input) result = poor.AttrDict(result) # with open('route.json', 'w') as f: # f.write(json.dumps(result)) x, y = poor.util.decode_epl(result.route.shape.shapePoints) maneuvers = [] for leg in result.route.legs: maneuvers.extend(leg.maneuvers) maneuvers = [ dict( x=float(maneuver.startPoint.lng), y=float(maneuver.startPoint.lat), icon=ICONS.get(maneuver.turnType, "flag"), narrative=maneuver.narrative, duration=float(maneuver.time), street=maneuver.get("streets", None), ) for maneuver in maneuvers ] if len(maneuvers) > 1: maneuvers[0]["icon"] = "depart" maneuvers[-1]["icon"] = "arrive" loc_index = result.route.shape.legIndexes loc_index[-1] -= 1 mode = MODE.get(type, "car") route = dict( x=x, y=y, locations=[locations[i] for i in result.route.locationSequence], location_indexes=loc_index, maneuvers=maneuvers, mode=mode, optimized=optimized) route["language"] = locale if route and route["x"]: cache[url + input] = copy.deepcopy(route) return route