Jump to content

Google directions API (auto correction?)


Andy-H

Recommended Posts

I'm writing a sort of fake tracking unit in nodeJS, it basically selects a random location, limits it to within some bounds, then I plan to inset the data into a database on around 30 second intervals, it's for a real-time demo of our works tracking system, however, if the latlngs don't happen to land on a road, the directions API returns an empty route, anyone know if there's a way to auto-correct the start / destination of a route?

 

 

Thanks

 

 

// directions/directions.js


var http       = require('http'), 
    latlng     = require('./latlng'),
    Polyline   = require('./polyline');


var Directions = function(origin, destination, bounds) {
   // validate origin / destination
   origin      = latlng.parse(origin);
   destination = latlng.parse(destination);
   
   // validate bounds
   if ( typeof bounds == 'string' )
      this.bounds = latlng.convertBounds(bounds);
   this.bounds.NW = latlng.parse(this.bounds.NW);
   this.bounds.SE = latlng.parse(this.bounds.SE);
   if ( !latlng.parse(this.bounds.NW) || !latlng.parse(this.bounds.SE) )
      throw 'Invalid latitude / longitude supplied in bounds';
   if ( !origin )
      throw 'Invalid latlng supplied as origin';
   if ( !destination )
      throw 'Invalid latlng supplied as destination';


   origin      = latlng.restrictToBounds(origin, this.bounds);
   destination = latlng.restrictToBounds(destination, this.bounds);
   
   /** SET DESTINATION START / END POINT */
   this.origin      = [ origin.lat,      origin.lng ];
   this.destination = [ destination.lat, destination.lng ];


   /** GET DIRECTIONS / LAT LNG's */
   this.get         = function(callBack) {
         _requestDirections(this.origin, this.destination, callBack);
   };
   /** MILES PER SECOND TO MILES PER HOUR CONVERSION */
   var MPS2MPH      = 2.23693629;
   
   /** OPTIONS FOR HTTP REQUEST */
   var opts = {
      host : 'maps.googleapis.com',
      path : '/maps/api/directions/json?origin={origin}&destination={destination}&sensor=false',
      port : 80
   };
   
   /** REQUEST DIRECTIONS API */
   var _requestDirections = function(origin, destination, callBack) {
      // replace origin and destination
      opts.path = opts.path.replace('{origin}',      origin.join(','));
      opts.path = opts.path.replace('{destination}', destination.join(','));
      // request google directions api
      http.request(opts, function(response) {
         response.data = [];
         // UTF-8 ENCODING
         response.setEncoding('utf8');
         // WHEN DATA CHUNCKS ARE RECIEVED APPEND TO RESPONSE.DATA
         response.on('data', function (data) {
            response.data.push(data);
         });
         // WHEN RESPONSE HAS COMPLETED, USE RESPONSE.DATA
         response.on('end', function(){
            var points = _parseDirections(JSON.parse(response.data.join('')).routes[0].legs[0].steps);
            if ( typeof callBack == 'function' )
               callBack.call(null, points, JSON.parse(response.data.join('')).routes[0].overview_polyline, Polyline);
         });
      }).end();
   };
   
   /** PARSE DIRECTIONS INTO LAT, LNG, SPEED, BEARING, ALTITUDE */
   var _parseDirections = function(directions) {
      var k, direction;
      var points     = [];
      for ( k in directions )
      {
         direction          = {};
         direction.latlng   = directions[k].end_location;
         direction.speed    = ((directions[k].distance.value / directions[k].duration.value) * MPS2MPH);
         direction.bearing  = latlng.getBearing(directions[k].start_location, directions[k].end_location);
         direction.altitude = 0;
         direction.delay    = directions[k].duration.value;
         points.push(direction);
      }
      return points;
   };
};
module.exports.create = function(origin, destination, bounds) {
   return new Directions(origin, destination, bounds);
};

 

 

// directions/latlng.js


/** CONVERTS NUMERIC DEGREES TO RADIANS */
toRad = function(n) {
   return n * Math.PI / 180;
}
/** CONVERTS RADIANS TO NUMERIC (SIGNED) DEGREES */
toDeg = function(n)
{
   return n * 180 / Math.PI;
}
module.exports.getBearing = function(origin, destination) {
   var lat   = [ origin.lat, destination.lat ];
   var lng   = [ origin.lng, destination.lng ];
   var R     = 6371; // km
   var dLat  = toRad(lat[1]-lat[0]);
   var dLon  = toRad(lng[1]-lng[0]);
   lat[0]    = toRad(lat[0]);
   lat[1]    = toRad(lat[1]);
   // calculate bearing
   var y = Math.sin(dLon)   * Math.cos(lat[1]);
   var x = Math.cos(lat[0]) * Math.sin(lat[1]) -
           Math.sin(lat[0]) * Math.cos(lat[1]) * Math.cos(dLon);
   var brng = toDeg(Math.atan2(y, x));
  return ( brng < 0 ) ? brng += 360 : brng;
};
module.exports.restrictToBounds = function(latlng, bounds) {
   if ( (typeof latlng.length).toLowerCase() == 'number' && latlng.length > 1 )
   {
      latlng.lat = latlng[0];
      latlng.lng = latlng[1];
   }
   if ( latlng.lat > bounds.NW.lat )
      latlng.lat = bounds.NW.lat;
   if ( latlng.lat < bounds.SE.lat )
      latlng.lat = bounds.SE.lat;
   if ( latlng.lng > bounds.NW.lng )
      latlng.lng = bounds.NW.lng;
   if ( latlng.lng < bounds.SE.lng )
      latlng.lng = bounds.SE.lng;
   return latlng;
};
module.exports.convertBounds = function(bound_name) {
   var bounds = {
      Nigeria : { 
         NW : [ 12.637242349197756, 3.927704592284158  ],
         SE : [ 7.871121752587033,  11.980683107909158 ]
      }
   };
   if ( !bounds.hasOwnProperty(bound_name) )
      return false;
   return bounds[bound_name];
};
module.exports.parse = function(latlng) {
   if ( (typeof latlng.length).toLowerCase() == 'number' && latlng.length > 1 )
   {
      latlng.lat = latlng[0];
      latlng.lng = latlng[1];
   }
   latlng.lat = parseFloat(latlng.lat);
   latlng.lng = parseFloat(latlng.lng);
   
   if ( typeof latlng.lat != 'number' || typeof latlng.lng != 'number' )
      return false;
   if ( latlng.lat < -90 || latlng.lat > 90 )
      return false;
   if ( latlng.lng < -180 || latlng.lng > 180 )
      return false;
   return latlng;
};

// directions/polyline.js


var Polyline = (function() {
   return {
      decode : function(polyline) {
         var pts   = [];
         var lat      = 0;
         var lng      = 0;
         while ( polyline.points.length )
         {
            lat += _decode(polyline);
            lng += _decode(polyline);
            pts.push({
               'lat' : (lat * 1e-5),
               'lng' : (lng * 1e-5)
            });
         }
         return pts;
      }
   };
   function _decode(polyline) {
      var shift  = 0, 
          result = 0, 
          i      = 0,
          b;
      do { // while ascii(polyline['polyline']) > ascii([space] " ")
         b       = polyline.points.charCodeAt(i++) - 63;
         result |= (b & 0x1f) << shift;
         shift  += 5;
      } while ( b >= 0x20 );
      polyline.points = polyline.points.substr(i);
      return ((result & 1) ? ~(result >> 1) : (result >> 1));
   };
})();
module.exports = Polyline;

 

 

// test.js


var start = [ 9.7, 8.4 ];
var end   = [ 9.8, 8.1 ];


var directions = require('./directions/directions').create(start, end, 'Nigeria');


directions.get(function(directions, polyline, decoder) {
   var decoded = decoder.decode(polyline);
   console.log(polyline);
});

 

 

Just in-case anyone's interested.

 

 

Thanks for any help.

Link to comment
https://forums.phpfreaks.com/topic/259445-google-directions-api-auto-correction/
Share on other sites

Archived

This topic is now archived and is closed to further replies.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.