/***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;}
以下是執行「將點對應至道路」要求後,上述資料的結果。紅線是原始資料,藍線則是經過對齊的資料。
有效運用配額
道路對齊要求的回應會包含地點 ID 清單,這些 ID 會對應到您提供的點,如果您設定 interpolate=true,則可能包含其他點。
/***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 的優點之一,是您可以在許多 Google 地圖平台 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-10 (世界標準時間)。"],[[["\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,["| **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\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\nGPX\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\nAndroid 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\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\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\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\nConsiderations\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\nDownload\n\nDownload the code from [GitHub](https://github.com/googlemaps/roads-api-samples)."]]