Andy-H Posted March 21, 2012 Share Posted March 21, 2012 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 More sharing options...
Andy-H Posted March 21, 2012 Author Share Posted March 21, 2012 Sorry, didn't realise I was still in misc, does this need moving? Link to comment https://forums.phpfreaks.com/topic/259445-google-directions-api-auto-correction/#findComment-1329952 Share on other sites More sharing options...
Andy-H Posted March 21, 2012 Author Share Posted March 21, 2012 Ran it through the geocoding api first. Link to comment https://forums.phpfreaks.com/topic/259445-google-directions-api-auto-correction/#findComment-1330006 Share on other sites More sharing options...
Recommended Posts
Archived
This topic is now archived and is closed to further replies.