/***SnapsthepointstotheirmostlikelypositiononroadsusingtheRoadsAPI.*/privateList<SnappedPoint>snapToRoads(GeoApiContextcontext)throwsException{List<SnappedPoint>snappedPoints=newArrayList<>();intoffset=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.}intlowerBound=offset;intupperBound=Math.min(offset+PAGE_SIZE_LIMIT,mCapturedLocations.size());// Get the data we need for this page.LatLng[]page=mCapturedLocations.subList(lowerBound,upperBound).toArray(newLatLng[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();booleanpassedOverlap=false;for(SnappedPointpoint:points){if(offset==0||point.originalIndex>=PAGINATION_OVERLAP-1){passedOverlap=true;}if(passedOverlap){snappedPoints.add(point);}}offset=upperBound;}returnsnappedPoints;}
/***Retrievesspeedlimitsforthepreviously-snappedpoints.Thismethodisefficientinterms*ofquotausageasitwillonlyqueryforuniqueplaces.**Note:SpeedlimitdataisonlyavailableforrequestsusinganAPIkeyenabledfora*GoogleMapsAPIsPremiumPlanlicense.*/privateMap<String,SpeedLimit>getSpeedLimits(GeoApiContextcontext,List<SnappedPoint>points)throwsException{Map<String,SpeedLimit>placeSpeeds=newHashMap<>();// Pro tip: Save on quota by filtering to unique place IDs.for(SnappedPointpoint:points){placeSpeeds.put(point.placeId,null);}String[]uniquePlaceIds=placeSpeeds.keySet().toArray(newString[placeSpeeds.keySet().size()]);// Loop through the places, one page (API request) at a time.for(inti=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(SpeedLimitsl:placeLimits){placeSpeeds.put(sl.placeId,sl);}}returnplaceSpeeds;}
上記のデータを、各一意のプレイス ID に制限速度をマークした状態で示します。
他の API との連携
道路へのスナップ レスポンスでプレイス ID が返されるメリットの 1 つは、多くの Google Maps Platform API でプレイス ID を使用できることです。この例では、Google マップ サービス用 Java クライアントを使用して、上記の道路へのスナップ リクエストから返された場所をジオコーディングします。
[[["わかりやすい","easyToUnderstand","thumb-up"],["問題の解決に役立った","solvedMyProblem","thumb-up"],["その他","otherUp","thumb-up"]],[["必要な情報がない","missingTheInformationINeed","thumb-down"],["複雑すぎる / 手順が多すぎる","tooComplicatedTooManySteps","thumb-down"],["最新ではない","outOfDate","thumb-down"],["翻訳に関する問題","translationIssue","thumb-down"],["サンプル / コードに問題がある","samplesCodeIssue","thumb-down"],["その他","otherDown","thumb-down"]],["最終更新日 2025-08-31 UTC。"],[[["\u003cp\u003eThis document explains how to use the Google Maps Roads API to snap GPS data to roads, inferring the location based on the full path.\u003c/p\u003e\n"],["\u003cp\u003eIt provides guidance on handling long paths exceeding the API's request limit, emphasizing the need for overlap between requests for accurate location inference.\u003c/p\u003e\n"],["\u003cp\u003eThe document highlights efficient quota usage by querying for speed limits using unique place IDs obtained from the snap to roads response.\u003c/p\u003e\n"],["\u003cp\u003eIt demonstrates the interplay of the Roads API with other Google Maps APIs by geocoding snapped points using their place IDs for address retrieval.\u003c/p\u003e\n"],["\u003cp\u003eThe provided code samples, available in Java, Python, Go, and Node.js, illustrate the concepts and functionalities discussed.\u003c/p\u003e\n"]]],[],null,["# Advanced Concepts\n\n| **Note:** The examples below use the Roads API in the [Java Client for Google Maps Services](https://github.com/googlemaps/google-maps-services-java). You can adapt the concepts to your language of choice. The [Python Client](https://github.com/googlemaps/google-maps-services-python) , [Go Client](https://github.com/googlemaps/google-maps-services-go) and [Node.js Client](https://github.com/googlemaps/google-maps-services-js) are also available on GitHub.\n\nAcquire data\n------------\n\nThere are many ways to obtain collected location data. Here we describe two\ntechniques for acquiring data to use with the [snap to roads](/maps/documentation/roads/snap) feature of\nthe Roads API.\n\n### GPX\n\nGPX is an open XML-based format for sharing routes, tracks and waypoints\ncaptured by GPS devices. This example uses the\n[XmlPull](http://www.xmlpull.org/) parser, a lightweight XML\nparser available for both Java server and mobile environments. \n\n```gdscript\n/**\n * Parses the waypoint (wpt tags) data into native objects from a GPX stream.\n */\nprivate List\u003cLatLng\u003e loadGpxData(XmlPullParser parser, InputStream gpxIn)\n throws XmlPullParserException, IOException {\n // We use a List\u003c\u003e as we need subList for paging later\n List\u003cLatLng\u003e latLngs = new ArrayList\u003c\u003e();\n parser.setInput(gpxIn, null);\n parser.nextTag();\n\n while (parser.next() != XmlPullParser.END_DOCUMENT) {\n if (parser.getEventType() != XmlPullParser.START_TAG) {\n continue;\n }\n\n if (parser.getName().equals(\"wpt\")) {\n // Save the discovered latitude/longitude attributes in each \u003cwpt\u003e.\n latLngs.add(new LatLng(\n Double.valueOf(parser.getAttributeValue(null, \"lat\")),\n Double.valueOf(parser.getAttributeValue(null, \"lon\"))));\n }\n // Otherwise, skip irrelevant data\n }\n\n return latLngs;\n}\n```\n\nHere's some raw GPX data loaded onto a map.\n\n### Android location services\n\nThe best way to capture GPS data from an Android device varies depending on your\nuse case. Take a look at the Android training class on\n[Receiving Location Updates](https://developer.android.com/training/location/receive-location-updates.html),\nas well as the\n[Google Play Location samples on GitHub](https://github.com/googlesamples/android-play-location).\n\nProcess long paths\n------------------\n\nAs the [snap to roads](/maps/documentation/roads/snap) feature infers the location based on the full path,\nrather than individual points, you need to take care when processing long\npaths (that is, paths over the 100-point-per-request limit).\n\nIn order to treat the individual requests as one long path, you should include\nsome overlap, such that the final points from the previous request are included\nas the first points of the subsequent request. The number of points to include\ndepends on the accuracy of your data. You should include more points\nfor low-accuracy requests.\n\nThis example uses the\n[Java Client for Google Maps Services](https://github.com/googlemaps/google-maps-services-java)\nto send paged requests and\nthen rejoins the data, including interpolated points, into the returned list. \n\n```scilab\n/**\n * Snaps the points to their most likely position on roads using the Roads API.\n */\nprivate List\u003cSnappedPoint\u003e snapToRoads(GeoApiContext context) throws Exception {\n List\u003cSnappedPoint\u003e snappedPoints = new ArrayList\u003c\u003e();\n\n int offset = 0;\n while (offset \u003c mCapturedLocations.size()) {\n // Calculate which points to include in this request. We can't exceed the API's\n // maximum and we want to ensure some overlap so the API can infer a good location for\n // the first few points in each request.\n if (offset \u003e 0) {\n offset -= PAGINATION_OVERLAP; // Rewind to include some previous points.\n }\n int lowerBound = offset;\n int upperBound = Math.min(offset + PAGE_SIZE_LIMIT, mCapturedLocations.size());\n\n // Get the data we need for this page.\n LatLng[] page = mCapturedLocations\n .subList(lowerBound, upperBound)\n .toArray(new LatLng[upperBound - lowerBound]);\n\n // Perform the request. Because we have interpolate=true, we will get extra data points\n // between our originally requested path. To ensure we can concatenate these points, we\n // only start adding once we've hit the first new point (that is, skip the overlap).\n SnappedPoint[] points = RoadsApi.snapToRoads(context, true, page).await();\n boolean passedOverlap = false;\n for (SnappedPoint point : points) {\n if (offset == 0 || point.originalIndex \u003e= PAGINATION_OVERLAP - 1) {\n passedOverlap = true;\n }\n if (passedOverlap) {\n snappedPoints.add(point);\n }\n }\n\n offset = upperBound;\n }\n\n return snappedPoints;\n}\n```\n\nHere's the data from above after running the snap to roads requests. The red\nline is the raw data and the blue line is the snapped data.\n\nEfficient use of quota\n----------------------\n\nThe response to a [snap to roads](/maps/documentation/roads/snap) request includes a list of place IDs\nthat map to the points you provided, potentially with additional points if you\nset `interpolate=true`.\n\nIn order to make efficient use of your allowed quota for a speed limits request,\nyou should only query for unique place IDs in your request. This example uses\nthe\n[Java Client for Google Maps Services](https://github.com/googlemaps/google-maps-services-java)\nto query speed limits from a list of place IDs. \n\n```scilab\n/**\n * Retrieves speed limits for the previously-snapped points. This method is efficient in terms\n * of quota usage as it will only query for unique places.\n *\n * Note: Speed limit data is only available for requests using an API key enabled for a\n * Google Maps APIs Premium Plan license.\n */\nprivate Map\u003cString, SpeedLimit\u003e getSpeedLimits(GeoApiContext context, List\u003cSnappedPoint\u003e points)\n throws Exception {\n Map\u003cString, SpeedLimit\u003e placeSpeeds = new HashMap\u003c\u003e();\n\n // Pro tip: Save on quota by filtering to unique place IDs.\n for (SnappedPoint point : points) {\n placeSpeeds.put(point.placeId, null);\n }\n\n String[] uniquePlaceIds =\n placeSpeeds.keySet().toArray(new String[placeSpeeds.keySet().size()]);\n\n // Loop through the places, one page (API request) at a time.\n for (int i = 0; i \u003c uniquePlaceIds.length; i += PAGE_SIZE_LIMIT) {\n String[] page = Arrays.copyOfRange(uniquePlaceIds, i,\n Math.min(i + PAGE_SIZE_LIMIT, uniquePlaceIds.length));\n\n // Execute!\n SpeedLimit[] placeLimits = RoadsApi.speedLimits(context, page).await();\n for (SpeedLimit sl : placeLimits) {\n placeSpeeds.put(sl.placeId, sl);\n }\n }\n\n return placeSpeeds;\n}\n```\n\nHere's the data from above with speed limits marked at each unique place ID.\n\nInterplay with other APIs\n-------------------------\n\nOne of the benefits of having place IDs returned in the [snap to roads](/maps/documentation/roads/snap)\nresponses is that you can use the place ID across many of the\nGoogle Maps Platform APIs. This example uses the [Java Client for Google Maps Services](https://github.com/googlemaps/google-maps-services-java)\nto geocode a place returned from the above snap to road request. \n\n```scilab\n/**\n * Geocodes a snapped point using the place ID.\n */\nprivate GeocodingResult geocodeSnappedPoint(GeoApiContext context, SnappedPoint point) throws Exception {\n GeocodingResult[] results = GeocodingApi.newRequest(context)\n .place(point.placeId)\n .await();\n\n if (results.length \u003e 0) {\n return results[0];\n }\n return null;\n}\n```\n\nHere the speed limit marker has been annotated with the address from the\nGeocoding API.\n\nSample code\n-----------\n\n### Considerations\n\nThe code supporting this document is available as a single Android app for\nillustrative purposes. In practice you shouldn't distribute your server-side\nAPI keys in an Android app as your key cannot be secured against unauthorized\naccess from a third party. Instead, to secure your keys you should deploy the\nAPI-facing code as a server-side proxy and have your Android app send requests\nusing the proxy, to be sure requests are authorized.\n\n### Download\n\nDownload the code from [GitHub](https://github.com/googlemaps/roads-api-samples)."]]