고급 개념

데이터 획득

수집된 위치 데이터를 가져오는 여러 가지 방법이 있습니다. 여기에서 두 가지 도로에 맞추기 기능과 함께 사용할 데이터를 Roads API

GPX

GPX는 경로, 트랙 및 경유지를 공유하기 위한 오픈 XML 기반 형식입니다. GPS 장치에 의해 캡처됩니다. 이 예에서는 XmlPull 파서, Java 서버와 모바일 환경 모두에 사용할 수 있는 경량 XML 파서입니다.

/**
 * 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;
}

다음은 지도에 로드된 몇 가지 원시 GPX 데이터입니다.

지도상의 원시 GPX 데이터

Android 위치 서비스

Android 기기에서 GPS 데이터를 캡처하는 가장 좋은 방법은 사용 중인 기기에 따라 살펴보겠습니다 위치 수신에 관한 Android 교육 과정을 살펴보세요. 업데이트Google Play의 GitHub를 참고하세요.

긴 경로 처리

도로에 맞추기 기능은 전체 경로를 기준으로 위치를 추론할 때 개별 포인트가 아닌 경로 (요청당 100포인트 한도를 초과하는 경로)입니다.

개별 요청을 하나의 긴 경로로 처리하려면 일부 중복이 있어서 이전 요청의 마지막 포인트가 포함됩니다. 첫 번째 지점으로 설정해야 합니다. 포함할 포인트 수 데이터의 정확성에 따라 달라집니다 포인트를 더 많이 포함해야 합니다. 를 사용합니다.

이 예에서는 Google 지도 서비스용 Java 클라이언트를 사용하여 페이징된 요청을 전송하고 그런 다음 보간된 점을 포함하여 데이터를 반환된 목록에 다시 결합합니다.

/**
 * 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;
}

다음은 Snap to Roads 요청을 실행한 후의 데이터입니다. 빨간색 선은 원시 데이터이고 파란색 선은 스냅된 데이터입니다.

도로에 맞춰진 데이터의 예

할당량의 효율적 사용

Snap to Roads 요청에 대한 응답에는 장소 ID 목록이 포함됩니다. 모든 포인트에 매핑되며, 서비스를 제공하는 경우 추가 포인트가 interpolate=true를 설정합니다.

속도 제한 요청에 허용된 할당량을 효율적으로 사용하려면 요청에 고유한 장소 ID만 쿼리해야 합니다. 이 예에서는 Google 지도 서비스용 Java 클라이언트: 장소 목록에서 속도 제한을 쿼리합니다. 있습니다.

/**
 * 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;
}

다음은 위에서 고유한 각 장소 ID에 속도 제한이 표시된 데이터입니다.

지도상의 속도 제한 표지

다른 API와의 상호작용

도로에 스냅하기에서 장소 ID를 반환할 때의 이점 중 하나는 여러 지역/지역에서 장소 ID를 사용할 수 있다는 Google Maps Platform API 이 예에서는 Google 지도 서비스용 Java 클라이언트를 사용합니다. 를 사용하여 위의 Snap to Road 요청에서 반환된 장소를 지오코딩합니다.

/**
 * 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;
}

여기에서 제한 속도 마커는 Geocoding API

마커에 표시된 지오코딩된 주소

샘플 코드

고려사항

이 도움말을 지원하는 코드는 설명 목적. 실제로는 서버 측에 배포하면 안 됩니다. 키를 무단 액세스로부터 보호할 수 없기 때문에 Android 앱의 API 키 액세스할 수 있습니다 대신 키를 보호하려면 API 페이싱 코드를 서버 측 프록시로 사용하고 Android 앱에서 요청을 전송하도록 합니다. 요청이 승인되었는지 확인합니다

다운로드

GitHub에서 코드를 다운로드합니다.