Adquirir dados
Há diversas maneiras de se obter dados de localização coletados. Aqui, descrevemos duas técnicas para adquirir dados a serem usados com o recurso ajustar a vias do Roads API.
GPX
O GPX é um formato XML aberto para compartilhar rotas, trajetos e pontos de referência capturados por dispositivos GPS. Este exemplo usa o analisador XmlPull, um analisador XML leve disponível para ambientes de servidor Java e dispositivos móveis.
/** * 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; }
Confira alguns dados GPX brutos carregados em um mapa.
Serviços de localização do Android
A melhor maneira de capturar dados de GPS de um dispositivo Android varia de acordo com seu caso de uso. Confira a aula de treinamento do Android sobre Recebimento de atualizações de local e os exemplos de local do Google Play no GitHub.
Processar caminhos longos
Como o recurso ajustar às vias infere a localização com base no caminho completo, e não em pontos individuais, é preciso ter cuidado ao processar caminhos longos (ou seja, caminhos acima do limite de 100 pontos por solicitação).
Para tratar as solicitações individuais como um caminho longo, inclua alguma sobreposição, de modo que os pontos finais da solicitação anterior sejam incluídos como os primeiros pontos da solicitação subsequente. O número de pontos a serem incluídos depende da precisão dos dados. Inclua mais pontos para solicitações de baixa acurácia.
Este exemplo usa o cliente Java para serviços do Google Maps para enviar solicitações paginadas e depois junta os dados, incluindo pontos interpolados, na lista retornada.
/** * 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; }
Estes são os dados acima após a execução das solicitações de ajuste a vias. A linha vermelha são os dados brutos, e a azul são os dados ajustados.
Uso eficiente da cota
A resposta a uma solicitação de ajuste a vias inclui uma lista de IDs de lugar
que correspondem aos pontos fornecidos, possivelmente com pontos extras se você
definir interpolate=true
.
Para usar de forma eficiente a cota permitida para uma solicitação de limites de velocidade, consulte apenas IDs de lugar exclusivos na sua solicitação. Este exemplo usa o cliente Java para serviços do Google Maps para consultar limites de velocidade de uma lista de IDs 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; }
Estes são os dados acima com os limites de velocidade marcados em cada ID de lugar exclusivo.
Interação com outras APIs
Um dos benefícios de ter IDs de lugar retornados nas respostas de ajuste a vias é que você pode usar o ID de lugar em muitas das APIs da Plataforma Google Maps. Este exemplo usa o cliente Java para serviços do Google Maps para geocodificar um lugar retornado da solicitação de ajuste à via acima.
/** * 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; }
Aqui, o marcador de limite de velocidade foi anotado com o endereço da API Geocoding.
Código de amostra
Considerações
O código que oferece suporte a este documento está disponível como um único app Android para fins ilustrativos. Na prática, não distribua suas chaves de API do lado do servidor em um app Android, porque elas não podem ser protegidas contra acesso não autorizado de terceiros. Em vez disso, para proteger suas chaves, implante o código voltado para a API como um proxy do lado do servidor e faça com que seu app Android envie solicitações usando o proxy para garantir que as solicitações sejam autorizadas.
Download
Faça o download do código no GitHub.