1

I've got an app which is receiving limited waypoint data and although the Google Maps Road Snapping does an admirable job of guessing the correct roads based on that data, I'm still experiencing a level of inaccuracy that won't work for our app.

Here's an example

In this example the purple markers represent the real-world "source" waypoints that are being sent in, while the blue markers show the snapped waypoint data coming back from Google based on the data from the source waypoints. I'm using the snapped blue waypoints to generate a polyline to show the route (purple polyline), unfortunately the snapped waypoints and subsequent route should really look more like the red polyline.

I have manually tested this on the online demo of the API with similar "source" waypoints and the route still snaps to the incorrect one, so I can only assume that there simply isn't enough data for Google to snap accurately. The question is, is there any way to improve the odds of a correct snap, given limited data like this? Is there a way I could possibly interpolate the limited source waypoints to attempt to "guide" Google to provide a more accurate snap?

Here's code similar to what I'm using - JSFiddle is here

//setup vars
var trip = [{
   "lat": -27.068,
   "lng": 153.1483
}, {
   "lat": -27.0642,
   "lng": 153.1546
}, {
   "lat": -27.0552,
   "lng": 153.156
}, {
   "lat": -27.0518,
   "lng": 153.1563
}, {
   "lat": -27.0503,
   "lng": 153.1552
}, {
   "lat": -27.0457,
   "lng": 153.1456
}, {
   "lat": -27.042,
   "lng": 153.1463
}, {
   "lat": -27.0349,
   "lng": 153.1476
}];

var unsnappedWaypoints = [];

var snappedWaypoints = [];

var map = new google.maps.Map(document.getElementById('map'), {
   zoom: 14,
   center: {
       lat: 0,
       lng: 0
   }
});

var bounds = new google.maps.LatLngBounds();

//add each waypoint to an array of lat/lngs
$.each(trip, function(key, waypoint) {

   unsnappedWaypoints.push(waypoint.lat + ',' + waypoint.lng);

   var marker = new google.maps.Marker({
       map: map,
       icon: 'http://mt.google.com/vt/icon/name=icons/spotlight/spotlight-ad.png',
       position: {
           lat: waypoint.lat,
           lng: waypoint.lng
       }
   });

});

//perform Google Maps API call with joined array for snapped results
$.ajax({
   url: 'https://roads.googleapis.com/v1/snapToRoads?path=' + unsnappedWaypoints.join('|') + '&key=AIzaSyA1JWR3ohBFQ_P7F5eSMSJb0dwV9PbB3pA&interpolate=true',
   crossDomain: true,
   dataType: 'jsonp'
}).done(function(response) {

   //iterate through returned waypoints to create array of lat/lngs for polyline
   $.each(response, function(key, snappedPoints) {
       $.each(snappedPoints, function(key, snappedPoint) {

           snappedWaypoints.push({
               lat: snappedPoint.location.latitude,
               lng: snappedPoint.location.longitude
           });

           //add snapped waypoints to map to show difference between originals and returned
           var marker = new google.maps.Marker({
               map: map,
               icon: 'http://mt.google.com/vt/icon?color=ff004C13&name=icons/spotlight/spotlight-waypoint-blue.png',
               position: {
                   lat: snappedPoint.location.latitude,
                   lng: snappedPoint.location.longitude
               }
           });

           //increase the bounds to take into account waypoints
           bounds.extend(new google.maps.LatLng(snappedPoint.location.latitude, snappedPoint.location.longitude));

       });
   });

   //create polyline from snapped waypoints
   var tripRoute = new google.maps.Polyline({
       path: snappedWaypoints,
       gseodesic: true,
       strokeColor: '#663496',
       strokeOpacity: 1.0,
       strokeWeight: 2
   });

   tripRoute.setMap(map);

   //fit these bounds to the map
   map.fitBounds(bounds);

});
George Inggs
  • 250
  • 2
  • 9
  • I've thought of using the Directions API as an alternative, but some trips will have over 100 waypoints, which make it pretty much impossible, given the current 8 waypoint limit. – George Inggs Dec 30 '15 at 01:18
  • Seems like the Roads API isn't working correctly in that area. [Cross checking the result against the DirectionsService shows that the data does exist in the database.](https://jsfiddle.net/geocodezip/w7Lnbbun/3/) – geocodezip Dec 30 '15 at 02:06
  • Thanks for checking that @geocodezip - if it _is_ an API problem, is it worth creating an issue at the API support page? Looking at how well your routing works, I _could_ use the direction service, but I don't know how practical it is potentially making 13 or 14 API calls for one trip with 100 waypoints. – George Inggs Dec 30 '15 at 02:55
  • I would think it would be worth creating an issue. Please post a link to the report here, and add a link to this SO question in the report. The problem with the directions service is it doesn't do a good job of snapping to the roads, if you look closely at the route generated, it backtracks because some of the points are on the "wrong" side of the road, I would expect the Roads API to handle that correctly (or if it doesn't that would be another issue). – geocodezip Dec 30 '15 at 03:05
  • I did notice the backtrack and will create an issue as you've suggested. I appreciate the assist! – George Inggs Dec 30 '15 at 03:08
  • [Issue has been raised](https://code.google.com/p/gmaps-api-issues/issues/detail?id=9078) - I will update here if / when a resolution is found. – George Inggs Dec 30 '15 at 03:37

1 Answers1

-1
var ActualRoadpoints = routes[0].overview_path;
 var resolution=100;// This number you can change.But less the number add more points on road.

 getFineData(ActualRoadpoints, resolution).forEach(function (point) {
 var ActualRoadmarker = new google.maps.Marker({
                                position: new google.maps.LatLng(point.lat(), point.lng()),
                                map: map,
                                // animation: google.maps.Animation.DROP,
                                visible: false
                            });
});

//This function call internally to find more points on route
 function getFineData(roughData, resolution) {
                var fineData = [];
                var latLngA;
                var latLngB;
                var steps;
                var step;
                for (var i = 1; i < roughData.length; i++) {
                    latLngA = roughData[i - 1];
                    latLngB = roughData[i];
                    distanceDiff = google.maps.geometry.spherical.computeDistanceBetween(latLngA, latLngB);
                    steps = Math.ceil(distanceDiff / resolution);
                    step = 1 / steps;
                    previousInterpolatedLatLng = latLngA;
                    for (var j = 0; j < steps; j++) {
                        var interpolated = google.maps.geometry.spherical.interpolate(latLngA, latLngB, step * j);
                        fineData.push(interpolated)
                    }
                }
               // console.log(fineData.length)
                return fineData;
            }