Adquirir datos
Hay muchas formas de obtener datos de ubicación recopilados. Aquí describimos dos técnicas de adquisición de datos para usar con la función ajustar a las rutas de Roads API.
GPX
GPX es un formato abierto basado en XML para compartir rutas, puntos de referencia y puntos de referencia capturados por dispositivos GPS. En este ejemplo, se usa el analizador XmlPull, un analizador XML liviano disponible para entornos de Java y de dispositivos móviles.
/** * Parses the waypoint (wpt tags) data into native objects from a GPX stream. */ private List<LatLng> loadGpxData(XmlPullParser parser, InputStream gpxIn) throws XmlPullParserException, IOException { // We use a List<> as we need subList for paging later List<LatLng> latLngs = new ArrayList<>(); parser.setInput(gpxIn, null); parser.nextTag(); while (parser.next() != XmlPullParser.END_DOCUMENT) { if (parser.getEventType() != XmlPullParser.START_TAG) { continue; } if (parser.getName().equals("wpt")) { // Save the discovered latitude/longitude attributes in each <wpt>. latLngs.add(new LatLng( Double.valueOf(parser.getAttributeValue(null, "lat")), Double.valueOf(parser.getAttributeValue(null, "lon")))); } // Otherwise, skip irrelevant data } return latLngs; }
A continuación, se muestran algunos datos GPX sin procesar cargados en un mapa.
Servicios de ubicación de Android
La mejor manera de capturar datos de GPS desde un dispositivo Android varía según tu caso de uso. Consulta la clase de capacitación de Android sobre la recepción de actualizaciones de ubicación y los ejemplos de ubicación de Google Play en GitHub.
Procesa rutas largas
A medida que la función de ajustar a rutas infiere la ubicación en función de la ruta de acceso completa, en lugar de puntos individuales, debes tener cuidado cuando se procesan rutas largas (es decir, aquellas que superan el límite de 100 puntos por solicitud).
Para tratar las solicitudes individuales como una ruta de acceso larga, debes incluir cierta superposición, de modo que los puntos finales de la solicitud anterior se incluyan como los primeros puntos de la solicitud posterior. La cantidad de puntos que debes incluir depende de la precisión de tus datos. Debes incluir más puntos para las solicitudes de baja precisión.
En este ejemplo, se usa el cliente de Java para los servicios de Google Maps a fin de enviar solicitudes paginadas y, luego, volver a unir los datos, incluidos los puntos interpolados, en la lista que se muestra.
/** * Snaps the points to their most likely position on roads using the Roads API. */ private List<SnappedPoint> snapToRoads(GeoApiContext context) throws Exception { List<SnappedPoint> snappedPoints = new ArrayList<>(); int offset = 0; while (offset < mCapturedLocations.size()) { // Calculate which points to include in this request. We can't exceed the API's // maximum and we want to ensure some overlap so the API can infer a good location for // the first few points in each request. if (offset > 0) { offset -= PAGINATION_OVERLAP; // Rewind to include some previous points. } int lowerBound = offset; int upperBound = Math.min(offset + PAGE_SIZE_LIMIT, mCapturedLocations.size()); // Get the data we need for this page. LatLng[] page = mCapturedLocations .subList(lowerBound, upperBound) .toArray(new LatLng[upperBound - lowerBound]); // Perform the request. Because we have interpolate=true, we will get extra data points // between our originally requested path. To ensure we can concatenate these points, we // only start adding once we've hit the first new point (that is, skip the overlap). SnappedPoint[] points = RoadsApi.snapToRoads(context, true, page).await(); boolean passedOverlap = false; for (SnappedPoint point : points) { if (offset == 0 || point.originalIndex >= PAGINATION_OVERLAP - 1) { passedOverlap = true; } if (passedOverlap) { snappedPoints.add(point); } } offset = upperBound; } return snappedPoints; }
Estos son los datos anteriores después de ejecutar las solicitudes de ajuste a las rutas. La línea roja corresponde a los datos sin procesar y la azul, a los datos ajustados.
Uso eficiente de la cuota
La respuesta a una solicitud de ajuste a rutas incluye una lista de los IDs de lugar que se asignan a los puntos que proporcionaste, posiblemente con puntos adicionales si configuraste interpolate=true
.
A fin de usar de manera eficiente la cuota permitida para una solicitud de límites de velocidad, solo debes consultar los IDs de lugar únicos en tu solicitud. En este ejemplo, se usa el cliente de Java para los servicios de Google Maps a fin de consultar los límites de velocidad de una lista de ID de lugar.
/** * Retrieves speed limits for the previously-snapped points. This method is efficient in terms * of quota usage as it will only query for unique places. * * Note: Speed limit data is only available for requests using an API key enabled for a * Google Maps APIs Premium Plan license. */ private Map<String, SpeedLimit> getSpeedLimits(GeoApiContext context, List<SnappedPoint> points) throws Exception { Map<String, SpeedLimit> placeSpeeds = new HashMap<>(); // Pro tip: Save on quota by filtering to unique place IDs. for (SnappedPoint point : points) { placeSpeeds.put(point.placeId, null); } String[] uniquePlaceIds = placeSpeeds.keySet().toArray(new String[placeSpeeds.keySet().size()]); // Loop through the places, one page (API request) at a time. for (int i = 0; i < uniquePlaceIds.length; i += PAGE_SIZE_LIMIT) { String[] page = Arrays.copyOfRange(uniquePlaceIds, i, Math.min(i + PAGE_SIZE_LIMIT, uniquePlaceIds.length)); // Execute! SpeedLimit[] placeLimits = RoadsApi.speedLimits(context, page).await(); for (SpeedLimit sl : placeLimits) { placeSpeeds.put(sl.placeId, sl); } } return placeSpeeds; }
Estos son los datos anteriores con los límites de velocidad marcados en cada ID de lugar único.
Interactúa con otras APIs
Uno de los beneficios de contar con IDs de lugar en las respuestas de ajustar a rutas es que puedes usarlo en muchas de las APIs de Google Maps Platform. En este ejemplo, se usa el cliente de Java para los servicios de Google Maps a fin de geocodificar un lugar devuelto por la solicitud de ajuste a carretera anterior.
/** * Geocodes a snapped point using the place ID. */ private GeocodingResult geocodeSnappedPoint(GeoApiContext context, SnappedPoint point) throws Exception { GeocodingResult[] results = GeocodingApi.newRequest(context) .place(point.placeId) .await(); if (results.length > 0) { return results[0]; } return null; }
Aquí, el marcador de límite de velocidad tiene la anotación de la dirección de la API de Geocoding.
Código de muestra
Consideraciones
El código que admite este artículo está disponible como una sola app para Android con fines ilustrativos. En la práctica, no debes distribuir tus claves de API del servidor en una app para Android, ya que no se puede proteger tu clave contra el acceso no autorizado de un tercero. En su lugar, a fin de proteger tus claves, debes implementar el código orientado a la API como un proxy del servidor y hacer que tu app para Android envíe solicitudes a través del proxy, lo que garantiza la autorización de las solicitudes.
Descargar
Descarga el código desde GitHub.