Search code examples
google-mapsgoogle-apigoogle-roads-api

Google Roads API's Nearest Roads function returns more points than given, contains duplicates


I'm sending a number of points to Google's Roads API to adjust them to roads. Note that this is the "Nearest Roads" function and not the "Snap To Roads" one, so the points don't form a path. When I get my results back, there are more points returned than given, but many of those points are duplicates. When I remove the duplicates there's less than what was given. The problem is reproducible with the URL and set of points below, just enter your own API key. I provide 20 points but end up getting 35 back.

'https://roads.googleapis.com/v1/nearestRoads?points=33.9882659912109,-118.47038269043001|33.9992523193359,-118.462142944336|33.9937591552734,-118.447036743164|33.9951324462891,-118.456649780273|33.991012573242195,-118.455276489258|33.9827728271484,-118.469009399414|33.9882659912109,-118.464889526367|33.981399536132805,-118.463516235352|34.003372192382805,-118.462142944336|33.986892700195305,-118.47175598144501|33.997879028320305,-118.463516235352|34.003372192382805,-118.452529907227|33.9882659912109,-118.474502563477|33.996505737304695,-118.47175598144501|33.981399536132805,-118.466262817383|34.001998901367195,-118.463516235352|33.996505737304695,-118.46076965331999|33.9937591552734,-118.466262817383|33.9992523193359,-118.469009399414|33.9937591552734,-118.463516235352&key=INSERT_YOUR_API_KEY_HERE'

I found this question with a similar issue, but it's specific to Snap To Roads so the solution doesn't apply here.


Solution

  • According to the documentation, that API returns 1 response for one way roads, 2 responses for two way roads and includes the index of the original input point as well:

    For each valid request, the Roads API will return a response in the format indicated within the request URL. The following elements may be present in a Snap to Roads response.

    For each valid request, the Roads API will return a response in the format indicated within the request URL. The following elements may be present in a Snap to Roads response.

    snappedPoints — An array of snapped points. Each point consists of the following fields:

    • location — Contains a latitude and longitude value.
    • originalIndex — An integer that indicates the corresponding value in the original request. Each point in the request maps to at most two segments in the response:

    If there are no nearby roads, no segment is returned.
    If the nearest road is one-way, one segment is returned.
    If the nearest road is bidirectional, two segments are returned. placeId

    So if the nearby roads are two way, one would expect twice as many points in the response as in the request.

    And it looks like with your data, many of the roads are two way, return two points, but the data is such that the two points are the same. According to the response that comes back for your request, there are 35 points returned, all of the original points are represented in the response.

    proof of concept fiddle putting the response data into a MarkerClusterer

    screenshot of resulting map

    code snippet:

    var geocoder;
    var map;
    
    function initialize() {
      var map = new google.maps.Map(
        document.getElementById("map_canvas"), {
          center: new google.maps.LatLng(37.4419, -122.1419),
          zoom: 13,
          mapTypeId: google.maps.MapTypeId.ROADMAP
        });
      var bounds = new google.maps.LatLngBounds();
      var gmarkers = [];
      console.log("snappedPoints.length=" + roadsApiSnapToRoadResult.snappedPoints.length);
      for (var i = 0; i < roadsApiSnapToRoadResult.snappedPoints.length; i++) {
        var marker = new google.maps.Marker({
          position: {
            lat: roadsApiSnapToRoadResult.snappedPoints[i].location.latitude,
            lng: roadsApiSnapToRoadResult.snappedPoints[i].location.longitude,
          },
          icon: {
            url: "https://maps.gstatic.com/intl/en_us/mapfiles/markers2/measle.png",
            size: new google.maps.Size(7, 7),
            anchor: new google.maps.Point(3.5, 3.5)
          },
          title: "" + roadsApiSnapToRoadResult.snappedPoints[i].originalIndex,
          map: map
        });
        gmarkers.push(marker);
        bounds.extend(marker.getPosition());
      }
      map.fitBounds(bounds);
      var markerClusterer = new MarkerClusterer(map, gmarkers, {
        imagePath: 'https://developers.google.com/maps/documentation/javascript/examples/markerclusterer/m',
        maxZoom: 18
      });
    }
    google.maps.event.addDomListener(window, "load", initialize);
    var roadsApiSnapToRoadResult = {
      "snappedPoints": [{
          "location": {
            "latitude": 33.988152465043711,
            "longitude": -118.4704415352344
          },
          "originalIndex": 0,
          "placeId": "ChIJ07TI4bi6woARVzS3zNDS75A"
        },
        {
          "location": {
            "latitude": 33.999373102445233,
            "longitude": -118.46239768997125
          },
          "originalIndex": 1,
          "placeId": "ChIJVwy5xOm6woARsndu3i5UqVw"
        },
        {
          "location": {
            "latitude": 33.999373102445233,
            "longitude": -118.46239768997125
          },
          "originalIndex": 1,
          "placeId": "ChIJVwy5xOm6woARs3du3i5UqVw"
        },
        {
          "location": {
            "latitude": 33.993767373940663,
            "longitude": -118.44703991835411
          },
          "originalIndex": 2,
          "placeId": "ChIJHUeXXoy6woARSrO6Q7pKMCc"
        },
        {
          "location": {
            "latitude": 33.993767373940663,
            "longitude": -118.44703991835411
          },
          "originalIndex": 2,
          "placeId": "ChIJHUeXXoy6woARS7O6Q7pKMCc"
        },
        {
          "location": {
            "latitude": 33.995020152633714,
            "longitude": -118.45642063549312
          },
          "originalIndex": 3,
          "placeId": "ChIJbdaMr-y6woAR7kSZm8ROfMc"
        },
        {
          "location": {
            "latitude": 33.995020152633714,
            "longitude": -118.45642063549312
          },
          "originalIndex": 3,
          "placeId": "ChIJbdaMr-y6woAR70SZm8ROfMc"
        },
        {
          "location": {
            "latitude": 33.991049979984176,
            "longitude": -118.45535641955625
          },
          "originalIndex": 4,
          "placeId": "ChIJtb81pZO6woARcCdVIfSh_G8"
        },
        {
          "location": {
            "latitude": 33.991049979984176,
            "longitude": -118.45535641955625
          },
          "originalIndex": 4,
          "placeId": "ChIJtb81pZO6woARcSdVIfSh_G8"
        },
        {
          "location": {
            "latitude": 33.98285945845808,
            "longitude": -118.46908608980472
          },
          "originalIndex": 5,
          "placeId": "ChIJISAPfbu6woARyKxdnrZG5oE"
        },
        {
          "location": {
            "latitude": 33.98285945845808,
            "longitude": -118.46908608980472
          },
          "originalIndex": 5,
          "placeId": "ChIJISAPfbu6woARyaxdnrZG5oE"
        },
        {
          "location": {
            "latitude": 33.988333802620495,
            "longitude": -118.46480571557542
          },
          "originalIndex": 6,
          "placeId": "ChIJs7rlQb66woARIeOfKMcdQX4"
        },
        {
          "location": {
            "latitude": 33.981527850209972,
            "longitude": -118.4636347455167
          },
          "originalIndex": 7,
          "placeId": "ChIJnZB4paK6woARXLQoGfodVh0"
        },
        {
          "location": {
            "latitude": 33.981527850209972,
            "longitude": -118.4636347455167
          },
          "originalIndex": 7,
          "placeId": "ChIJnZB4paK6woARXbQoGfodVh0"
        },
        {
          "location": {
            "latitude": 34.003497235152565,
            "longitude": -118.46240183188755
          },
          "originalIndex": 8,
          "placeId": "ChIJd5Hp-ue6woARatY78BByNBg"
        },
        {
          "location": {
            "latitude": 34.003497235152565,
            "longitude": -118.46240183188755
          },
          "originalIndex": 8,
          "placeId": "ChIJd5Hp-ue6woARa9Y78BByNBg"
        },
        {
          "location": {
            "latitude": 33.98685767022473,
            "longitude": -118.47172496327262
          },
          "originalIndex": 9,
          "placeId": "ChIJ3TKdobm6woARS2DIe-NRymk"
        },
        {
          "location": {
            "latitude": 33.997747613047771,
            "longitude": -118.46341368261827
          },
          "originalIndex": 10,
          "placeId": "ChIJc3IO_um6woARWgni7EMZaJ0"
        },
        {
          "location": {
            "latitude": 33.997747613047771,
            "longitude": -118.46341368261827
          },
          "originalIndex": 10,
          "placeId": "ChIJc3IO_um6woARWwni7EMZaJ0"
        },
        {
          "location": {
            "latitude": 34.00333556691659,
            "longitude": -118.45250243554641
          },
          "originalIndex": 11,
          "placeId": "ChIJK7ABtu-6woARyCzwvT7-vco"
        },
        {
          "location": {
            "latitude": 34.00333556691659,
            "longitude": -118.45250243554641
          },
          "originalIndex": 11,
          "placeId": "ChIJK7ABtu-6woARySzwvT7-vco"
        },
        {
          "location": {
            "latitude": 33.988346309645785,
            "longitude": -118.4743705301974
          },
          "originalIndex": 12,
          "placeId": "ChIJ1TslIri6woARQ_h9FkDa-yc"
        },
        {
          "location": {
            "latitude": 33.9964313646278,
            "longitude": -118.47170049959587
          },
          "originalIndex": 13,
          "placeId": "ChIJhZYhN8S6woAR5pUEEEhYbCU"
        },
        {
          "location": {
            "latitude": 33.9964313646278,
            "longitude": -118.47170049959587
          },
          "originalIndex": 13,
          "placeId": "ChIJhZYhN8S6woAR55UEEEhYbCU"
        },
        {
          "location": {
            "latitude": 33.981307554994437,
            "longitude": -118.46641918691026
          },
          "originalIndex": 14,
          "placeId": "ChIJxTT5KKO6woAR_uY0J0oCLDU"
        },
        {
          "location": {
            "latitude": 33.981307554994437,
            "longitude": -118.46641918691026
          },
          "originalIndex": 14,
          "placeId": "ChIJxTT5KKO6woAR_-Y0J0oCLDU"
        },
        {
          "location": {
            "latitude": 34.002195599071726,
            "longitude": -118.46391163712804
          },
          "originalIndex": 15,
          "placeId": "ChIJqXQkrcK6woAR_sD5qVq2Yl8"
        },
        {
          "location": {
            "latitude": 34.002195599071726,
            "longitude": -118.46391163712804
          },
          "originalIndex": 15,
          "placeId": "ChIJqXQkrcK6woAR_8D5qVq2Yl8"
        },
        {
          "location": {
            "latitude": 33.99648760375095,
            "longitude": -118.46073154820924
          },
          "originalIndex": 16,
          "placeId": "ChIJl0OqT-q6woARstLIStpm2NU"
        },
        {
          "location": {
            "latitude": 33.99648760375095,
            "longitude": -118.46073154820924
          },
          "originalIndex": 16,
          "placeId": "ChIJl0OqT-q6woARs9LIStpm2NU"
        },
        {
          "location": {
            "latitude": 33.993670902273607,
            "longitude": -118.46619470748932
          },
          "originalIndex": 17,
          "placeId": "ChIJWes6V8C6woARc4NO9L0r978"
        },
        {
          "location": {
            "latitude": 33.999376276569294,
            "longitude": -118.46882770430223
          },
          "originalIndex": 18,
          "placeId": "ChIJ2TxBfcO6woAR4oW0l5gn22c"
        },
        {
          "location": {
            "latitude": 33.999376276569294,
            "longitude": -118.46882770430223
          },
          "originalIndex": 18,
          "placeId": "ChIJ2TxBfcO6woAR44W0l5gn22c"
        },
        {
          "location": {
            "latitude": 33.99367154305785,
            "longitude": -118.46333135141523
          },
          "originalIndex": 19,
          "placeId": "ChIJL1Q9H8C6woAR6JtmbvA0dcU"
        },
        {
          "location": {
            "latitude": 33.99367154305785,
            "longitude": -118.46333135141523
          },
          "originalIndex": 19,
          "placeId": "ChIJL1Q9H8C6woAR6ZtmbvA0dcU"
        }
      ]
    }
    html,
    body,
    #map_canvas {
      height: 100%;
      width: 100%;
      margin: 0px;
      padding: 0px
    }
    <script src="https://cdn.rawgit.com/googlemaps/v3-utility-library/master/markerclustererplus/src/markerclusterer.js"></script>
    <script src="https://maps.googleapis.com/maps/api/js?ext=.js"></script>
    <div id="map_canvas"></div>