Currently the formula I am using is below, but it is less accurate as the Vincenty formula, which you can find on this link:
http://www.movable-type.co.uk/scripts/latlong-vincenty-direct.html
My question is, can someone help simplify the javascript code so i can implement it in my formula? I am trying to learn javascript but it is a bit beyond my capabilities.
ex = lat2
ey = lon2
Im thinking the easiest way would be to run through the code and do an array of 360 degrees to calculate the ex/ey coordinates.
<script type="text/javascript">
function drawCircle(point, radius, dir, addtoBounds) {
var d2r = Math.PI / 180; // degrees to radians
var r2d = 180 / Math.PI; // radians to degrees
var earthsradius = 6378137;
var points = 360;
// find the radius in lat/lon
var rlat = (radius / earthsradius) * r2d;
var rlng = rlat / Math.cos(point.lat() * d2r);
var extp = new Array();
if (dir==1) {var start=0;var end=points+1} // one extra here makes sure we connect the
else {var start=points+1;var end=0}
for (var i=start; (dir==1 ? i < end : i > end); i=i+dir)
{
var theta = Math.PI * (i / (points/2));//i is number of points + 1
var lat1=point.lat()*d2r;
var lon1=point.lng()*d2r;
var d=radius;
var R=earthsradius;
var ex = Math.asin( Math.sin(lat1)*Math.cos(d/R) +
Math.cos(lat1)*Math.sin(d/R)*Math.cos(theta));
var ey = lon1 + Math.atan2(Math.sin(theta)*Math.sin(d/R)*Math.cos(lat1),
Math.cos(d/R)-Math.sin(lat1)*Math.sin(ex));
extp.push(new google.maps.LatLng(ex*r2d, ey*r2d));
if (addtoBounds) bounds.extend(extp[extp.length-1]);
}
// alert(extp.length);
return extp;
}
Here is the direct formula converted to php. I am trying to put this code into the google maps code. The movable type link actually has this code in javascript, but since I know php much better, I converted it over to test it out, this works perfectly.
<?php
$lat1 = 29.10860062;
$lon1 = -95.46209717;
$a = 6378137;
$b = 6356752.314245;
$f = 1/298.257223563; // WGS-84 ellipsoid params
$brng = 32.8;
$s = 1796884.48;
$alpha1 = deg2rad($brng);
$sinAlpha1 = sin($alpha1);
$cosAlpha1 = cos($alpha1);
$tanU1 = (1-$f) * tan(deg2rad($lat1));
$cosU1 = 1 / sqrt((1 + pow($tanU1,2)));
$sinU1 = $tanU1*$cosU1;
$sigma1 = atan2($tanU1, $cosAlpha1);
$sinAlpha = $cosU1 * $sinAlpha1;
$cosSqAlpha = 1 - pow($sinAlpha,2);
$uSq = $cosSqAlpha * (pow($a,2) - pow($b,2)) / (pow($b,2));
$A = 1 + $uSq/16384*(4096+$uSq*(-768+$uSq*(320-175*$uSq)));
$B = $uSq/1024 * (256+$uSq*(-128+$uSq*(74-47*$uSq)));
$sigma = $s / ($b*$A);
$sigmaP = 2*pi;
$limit = 100;
$counter = 1;
while ( $counter <= $limit ) {
$cos2SigmaM = cos(2*$sigma1 + $sigma);
$sinSigma = sin($sigma);
$cosSigma = cos($sigma);
$deltaSigma = $B*$sinSigma*($cos2SigmaM+$B/4*($cosSigma*(-1+2*pow($cos2SigmaM,2))-$B/6*$cos2SigmaM*(-3+4*pow($sinSigma,2))*(-3+4*pow($cos2SigmaM,2))));
$sigmaP = $sigma;
$sigma = $s / ($b*$A) + $deltaSigma;
$counter = $counter+1;
};
$tmp = $sinU1*$sinSigma - $cosU1*$cosSigma*$cosAlpha1;
$lat2 = atan2($sinU1*$cosSigma + $cosU1*$sinSigma*$cosAlpha1,(1-$f)*sqrt(pow($sinAlpha,2)+ pow($tmp,2)));
$lambda = atan2($sinSigma*$sinAlpha1, $cosU1*$cosSigma - $sinU1*$sinSigma*$cosAlpha1);
$C = $f/16*$cosSqAlpha*(4+$f*(4-3*$cosSqAlpha));
$L = $lambda - (1-$C) * $f * $sinAlpha *($sigma + $C*$sinSigma*($cos2SigmaM+$C*$cosSigma*(-1+2*pow($cos2SigmaM,2))));
if (deg2rad($lon1)+$L+(3*pi)<(2*pi)) {
( $lon2 = (deg2rad($lon1)+$L+(3*pi))-pi);
} else {
( $lon2 = ((deg2rad($lon1)+$L+3*pi))%(2*pi))-pi;}
$revAz = atan2($sinAlpha, -$tmp); // final bearing, if required
?>
Since the link you provided already provides the formula in javascript the hard part is complete, you can just copy it and call it rather than rewriting it into your function. Just remember to attribute the source. I removed the variables that were not being used. Also, I just hard coded 361 into the formula since you were just assigning it to a points variable. You can change this back if you are going to be passing the number of degrees into the formula. I separated the for loops, to me this is more readable, and I dont think the way you had before was working like you intended it. When working with degrees and radians I always wrap these conversions into functions since it improves readability. To do this I hooked them up to the Number object in JavaScript using prototype as seen here:
Number.prototype.toRad = function() {
//'this' is the current number the function is acting on.
//e.g. 360.toRad() == 2PI radians
return this * Math.PI / 180;
}
Number.prototype.toDeg = function() {
return this * 180 / Math.PI;
}
Not too tough to understand, prototype allows you to extend objects in JavaScript, similar to inheritance in class based languages. There are plenty of resources online that can help clarify.
Here is the reworked drawCircle function:
function drawCircle(point, radius, dir, addtoBounds) {
//best practice is to use [] rather then new Array(),
//both do the same thing.
var extp = [];
if (dir == 1) {
for (var i = 0; i < 361; i++) {
//destVincenty function returns a object with
//lat, lon, and final bearing.
var destPoint = destVincenty(point.lat(), point.lng(), i, radius);
//add new point
extp.push(new google.maps.LatLng(destPoint.lat, destPoint.lon));
if (addtoBounds) bounds.extend(extp[extp.length - 1]);
}
}
else {
for (var i = 361; i > 0; i--) {
var destPoint = destVincenty(point.lat(), point.lng(), i, radius);
extp.push(new google.maps.LatLng(destPoint.lat, destPoint.lon));
if (addtoBounds) bounds.extend(extp[extp.length - 1]);
}
}
return extp;
}
here is a fiddle of it working.
Related
I'm using HERE maps and I would like to know the area of a polygon drawn on the map. Is there a way to know that? I didn't find anything in the documentation.
There is no function within the JS API but you can easily do it yourself.
Below is provided a sample function for computing the area (in square meters) of a polygonal area:
function computeArea(latLngs) {
var pointsCount = latLngs.length,
area = 0.0,
d2r = Math.PI / 180.0,
radius = 6378137.0,
p1, p2;
if (pointsCount <= 2)
return 0;
for (var i = 0; i < pointsCount; i++) {
p1 = latLngs[i];
p2 = latLngs[(i + 1) % pointsCount];
area += ((p2.lng() - p1.lng()) * d2r) *
(2 + Math.sin(p1.lat() * d2r) + Math.sin(p2.lat() * d2r));
}
area = area * radius * radius / 2.0;
return Math.abs(area);
}
I've been trying to implement collision detection between circles and polygons based on Randy Gaul's C++ Impulse Engine, following the code pretty closely, but the algorithm never returns true.
Here's the JSFiddle. (the bodies are rendered using the HTML5 Canvas API for convenience)
A snippet of the code (just collision detection):
const circPoly = (a, b) => {
let data = {},
center = a.pos;
data.contacts = [];
center = b.mat.clone().trans().mult(center.clone().sub(b.pos));
let sep = -Number.MAX_VALUE,
faceNorm = 0;
for (let i = 0; i < b.verts2.length; ++i) {
let sep2 = b.norms[i].dot(center.clone().sub(b.verts2[i]));
if (sep2 > a.radius) return data;
if (sep2 > sep) { sep = sep2; faceNorm = i; }
}
let v1 = b.verts2[faceNorm],
v2 = b.verts2[faceNorm + 1 < b.verts2.length ? faceNorm + 1 : 0];
if (sep < 0.0001) {
data.depth = a.radius;
data.norm = b.mat.clone().mult(b.norms[faceNorm]).neg();
data.contacts[0] = data.norm.clone().vmult(a.pos.clone().sadd(a.radius));
return data;
}
let dot1 = center.clone().sub(v1).dot(v2.clone().sub(v1)),
dot2 = center.clone().sub(v2).dot(v1.clone().sub(v2));
data.depth = a.radius - sep;
if (dot1 <= 0) {
if (center.dist2(v1) > a.radius * a.radius) return data;
let norm = v1.clone().sub(center);
norm = b.mat.clone().mult(norm);
norm.norm();
data.norm = norm;
v1 = b.mat.clone().mult(v1.clone().add(b.pos));
data.contacts[0] = v1;
} else if (dot2 <= 0) {
if (center.dist2(v2) > a.radius * a.radius) return data;
let norm = v2.clone().sub(center);
norm = b.mat.clone().mult(norm);
norm.norm();
data.norm = norm;
v2 = b.mat.clone().mult(v2.clone().add(b.pos));
data.contacts[0] = v2;
} else {
let norm = b.norms[faceNorm];
if (center.clone().sub(v1).dot(norm) > a.radius) return data;
norm = b.mat.clone().mult(norm);
data.norm = norm.clone().neg();
data.contacts[0] = data.norm.clone().vmult(a.pos.clone().sadd(a.radius));
}
return data;
};
Note that b.verts2 refers to the polygon's vertices in real world coordinates.
I know for a fact that there are no problems with the Vector class but as I don't exactly have very much experience with transformation matrices, that class could be the root of these errors, although the code for it is pretty much entirely derived from the Impulse Engine as well, so it should work. As mentioned before, the algorithm always returns false, even when a collision really has occurred. What am I doing wrong here? I tried taking out the early returns, but that just returns weird results like contact points with negative coordinates which obviously is not quite correct.
EDIT: Modified my vector class's perpendicular function to work the same way as the Impulse Engine's (both ways are right, but I think one is clockwise and the other one counterclockwise -- I also modified my vertices to reflect the counterclockwise-ness). Unfortunately, it still fails the test.
https://jsfiddle.net/khanfused/tv359kgL/4/
Well the are many problems and I really dont understand what you are trying to do as it seem overly complex. Eg why does matrix have trans??? and why are you using the Y up screen as the coordinate system for the transform??? (rhetorical)
In the first loop.
The first is that you are testing the distance of the normal vectors
of each vert, should be testing the vert position.
Also you are finding the distance using the vec.dot function that
returns the square of the distance. But you test for the radius, you
should be testing for if(sep2 < radius * radius)
And you have the comparison the wrong way around you should be
testing if less than radius squared (not greater than)
Then when you do detect a vert within the radius you return the data
object but forget to put the vert that was found inside the circle on
the data.contacts array.
I am not sure what the intention of keeping the index of the most
distant vect is but then the rest of the function make zero sense to
me???? :( and I have tried to understand it.
All you need to do is
A check if any verts on the poly are closer than radius, if so then you have a intercept (or is completely inside)
Then you need to check the distance of each line segment
Can be done for each line segment with the following if you dont need the intercepts (or below that if you need intercepts) only use one or the other.
// circle is a point {x:?,y:?}
// radius = is the you know what
// p1,p2 are the start and end points of a line
checkLineCircle = function(circle,radius,p1,p2){
var v1 = {};
var v2 = {};
var v3 = {};
var u;
// get dist to end of line
v2.x = circle.x - p1.x;
v2.y = circle.y - p1.y;
// check if end points are inside the circle
if( Math.min(
Math.hypot(p2.x - circle.x, p2.y - circle.y),
Math.hypot(v2.x, v2.y)
) <= radius){
return true;
}
// get the line as a vector
v1.x = p2.x - p1.x;
v1.y = p2.y - p1.y;
// get the unit distance of the closest point on the line
u = (v2.x * v1.x + v2.y * v1.y)/(v1.y * v1.y + v1.x * v1.x);
// is this on the line segment
if(u >= 0 && u <= 1){
v3.x = v1.x * u; // get the point on the line segment
v3.y = v1.y * u;
// get the distance to that point and return true or false depending on the
// it being inside the circle
return (Math.hypot(v3.y - v2.y, v3.x - v2.x) <= radius);
}
return false; // no intercept
}
Do that for each line.To save time transform the circle center to the polygon local, rather than transform each point on the poly.
If you need the points of intercept then use the following function
// p1,p2 are the start and end points of a line
// returns an array empty if no points found or one or two points depending on the number of intercepts found
// If two points found the first point in the array is the point closest to the line start (p1)
function circleLineIntercept(circle,radius,p1,p2){
var v1 = {};
var v2 = {};
var ret = [];
var u1,u2,b,c,d;
// line as vector
v1.x = p2.x - p1.x;
v1.y = p2.y - p1.y;
// vector to circle center
v2.x = p1.x - circle.x;
v2.y = p1.y - circle.y;
// dot of line and circle
b = (v1.x * v2.x + v1.y * v2.y) * -2;
// length of line squared * 2
c = 2 * (v1.x * v1.x + v1.y * v1.y);
// some math to solve the two triangles made by the intercept points, the circle center and the perpendicular line to the line.
d = Math.sqrt(b * b - 2 * c * (v2.x * v2.x + v2.y * v2.y - radius * radius));
// will give a NaN if no solution
if(isNaN(d)){ // no intercept
return ret;
}
// get the unit distance of each intercept to the line
u1 = (b - d) / c;
u2 = (b + d) / c;
// check the intercept is on the line segment
if(u1 <= 1 && u1 >= 0){
ret.push({x:line.p1.x + v1.x * u1, y : line.p1.y + v1.y * u1 });
}
// check the intercept is on the line segment
if(u2 <= 1 && u2 >= 0){
ret.push({x:line.p1.x + v1.x * u2, y : line.p1.y + v1.y * u2});
}
return ret;
}
I will leave it up to you to do the polygon iteration.
I'm trying to write code to track real-time positions of roughly 100 vehicles via GPS. I'd like to smoothly "animate" the google map marker for each vehicle by setting its position along an interpolated path between its last X/Y point and the current one. I call the URL to get a JSON object with all the current vehicle positions every 15 sec via a setInterval call. Inside that I iterate over each vehicle in the JSON object and set the vehicle position. I have functions to animate the motion but it only works reliably for one vehicle, I believe because my nested setInterval function will not complete before the next step in the for loop it's enclosed in. Is there anyway to have the inner setInterval function run to completion before the next "i" in my for loop?
setInterval(function() {
$(document).ready(function() {
$.getJSON("http://localhost:8080/portal/frfeed/query/tampa_sw/paraVehicle?r=" + Math.random(),function(vehicles){
$.each(vehicles, function(index, d){
if(d.heading>=0 && d.heading<22.5) direction="NORTH";
else if(d.heading>=22.5 && d.heading<67.5) direction="NORTHEAST";
else if(d.heading>=67.5 && d.heading<112.5) direction="EAST";
else if(d.heading>=112.5 && d.heading<157.5) direction="SOUTHEAST";
else if(d.heading>=157.5 && d.heading<202.5) direction="SOUTH";
else if(d.heading>=202.5 && d.heading<247.5) direction="SOUTHWEST";
else if(d.heading>=247.5 && d.heading<292.5) direction="WEST";
else if(d.heading>=292.5 && d.heading<338) direction="NORTHWEST";
else direction="NORTH";
vehicle = "";
for (var i=0; i<vMarkers.length; i++) {
if( vMarkers[i][0] === d.internalVehicleId ) {
var path;
var latlng = new google.maps.LatLng(d.latitude,d.longitude);
vMarkers[i][2] = vMarkers[i][1].getPosition().lat();
vMarkers[i][3] = vMarkers[i][1].getPosition().lng();
vMarkers[i][4] = latlng;
vMarkers[i][1].setTitle('Vehicle: ' + d.internalVehicleId + '\r\n' + 'Last Update: ' + d.time + '\r\n' + 'Traveling: ' + direction + ' # ' + d.speed + ' mph');
path = vPolys[i][1].getPath();
path.push(latlng);
vPolys[i][1].setPath(path);
vehicle = vMarkers[i][0];
var lat = vMarkers[i][2];
var lng = vMarkers[i][3];
var latlngTo = vMarkers[i][4];
var latLngFrom = new google.maps.LatLng(lat,lng);
j = 0;
// function below only works correctly if filtered for one vehicle as below, otherwise, all
// markers randomly move and don't stop due to the setInterval being called inside the for loop
if (distance(latlngTo.lat(), latlngTo.lng(),latLngFrom.lat(), latLngFrom.lng()) > 20 && vMarkers[i][0] == "1329") {
iv = window.setInterval(function() {
j++;
var pos = mercatorInterpolate(map, latLngFrom, latlngTo, j/50);
vMarkers[i][1].setPosition(pos);
if (j >= 50) {
window.clearInterval(iv);
}
}, 20);
}
else {
vMarkers[i][1].setPosition(latlngTo);
};
break;
}
}
if( vehicle == "") {
color = get_random_color();
marker = new StyledMarker({
styleIcon:new StyledIcon(StyledIconTypes.BUBBLE,{color:color, fore: "ffffff",text: d.internalVehicleId}),
position: new google.maps.LatLng(d.latitude,d.longitude),
title: 'Vehicle: ' + d.internalVehicleId + '\r\n' + 'Last Update: ' + d.time + '\r\n' + 'Traveling: ' + direction + ' # ' + d.speed + ' mph',
map: map
});
var polyOptions = {
strokeColor: color,
strokeOpacity: 1.0,
map: map,
strokeWeight: 3
};
poly = new google.maps.Polyline(polyOptions);
var latlng = new google.maps.LatLng(d.latitude,d.longitude);
vMarkers.push([d.internalVehicleId, marker, d.latitude, d.longitude, latlng]);
var path = poly.getPath();
path.push(latlng);
poly.setPath(path);
vPolys.push([d.internalVehicleId, poly])
vehicle = "";
}
});//$.each(vehicles, function(index, d){
function mercatorInterpolate(map, latLngFrom, latLngTo, fraction) {
// Get projected points
var projection = map.getProjection();
var pointFrom = projection.fromLatLngToPoint(latLngFrom);
var pointTo = projection.fromLatLngToPoint(latLngTo);
// Adjust for lines that cross the 180 meridian
if (Math.abs(pointTo.x - pointFrom.x) > 128) {
if (pointTo.x > pointFrom.x)
pointTo.x -= 256;
else
pointTo.x += 256;
}
// Calculate point between
var x = pointFrom.x + (pointTo.x - pointFrom.x) * fraction;
var y = pointFrom.y + (pointTo.y - pointFrom.y) * fraction;
var pointBetween = new google.maps.Point(x, y);
// Project back to lat/lng
var latLngBetween = projection.fromPointToLatLng(pointBetween);
return latLngBetween;
}
function distance(lat1,lon1,lat2,lon2) {
var R = 6371;
var dLat = (lat2-lat1) * Math.PI / 180;
var dLon = (lon2-lon1) * Math.PI / 180;
var a = Math.sin(dLat/2) * Math.sin(dLat/2) +
Math.cos(lat1 * Math.PI / 180 ) * Math.cos(lat2 * Math.PI / 180 ) *
Math.sin(dLon/2) * Math.sin(dLon/2);
var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
var d = R * c;
return Math.abs(d*1000);
}
}); //$.getJSON(...., function(vehicles) {
}); //$(document).ready(function() {
}, 16000); // setInterval(function(){
No, setInterval is Asynchronous. You have to program in a way that works with asycronous code, rather then trying to force it to be synchronous.
For animation you should really be using requestAnimationFrame to get smooth results.
I would create a frames array, pushing an array of the cars every 15 seconds. Each car storing it's position
var frames = [[{x: 10, y:2},{x: 5, y:6}], [{x: 12, y:4},{x: 7, y:8}]]
I would then use requestAnimationFrame and interpolate the current position of each car
var currentFrame = 0;
var startTime = 0;
function update(){
var currentTime = newDate();
startTime || startTime = currentTime;
var elaspedTime = Math.floor(currentTime.getTime() - startTime.getTime())/1000;
// increment the current frame if 15 seconds have elapsed
elaspedTime%15 === 0 && currentFrame++;
// Get the current frame
var frame = frames[currentFrame],
nextFrame = frames[++currentFrame];
// Loop over each car in the frame
for(var i = 0; i < frame.length; i++){
// Calculate the difference in location
var xDiff = nextFrame[i].x - frame[i].x;
var yDiff = nextFrame[i].y - frame[i].y;
// interpolate the current position of the cars
var xPos = xDiff / elaspedTime%15;
var yPos = yDiff / elaspedTime%15;
// do some work here to set the position of the cars
}
requestAnimationFrame(update);
}
requestAnimationFrame(update);
You could optimize this much better then what I've done, but this is how I'd approach it.
Instead of trying to run multiple setInterval(), run just one, and iterate over all your vehicles within that one function call.
For example:
iv = setInterval(function() {
for (int i=0; i<vehicleArray.length;i++) {
// Do stuff for each vehicle.
}
}, 40);
Note that setInterval() doesn't guarantee the frequency at which it will be called, just the minumum interval. This can lead to haphazard tracking. Avoid this by reading the clock every time you enter the setInterval() function, and calculating new positions based on that.
Your code is trying to achieve 50 frames per second, which might prove to be optimistic. You can get a smooth effect at half that. i.e. at 40ms intervals.
How do you calculate the distance between two markers in Google maps V3? (Similar to the distanceFrom function inV2.)
Thanks..
If you want to calculate it yourself, then you can use the Haversine formula:
var rad = function(x) {
return x * Math.PI / 180;
};
var getDistance = function(p1, p2) {
var R = 6378137; // Earth’s mean radius in meter
var dLat = rad(p2.lat() - p1.lat());
var dLong = rad(p2.lng() - p1.lng());
var a = Math.sin(dLat / 2) * Math.sin(dLat / 2) +
Math.cos(rad(p1.lat())) * Math.cos(rad(p2.lat())) *
Math.sin(dLong / 2) * Math.sin(dLong / 2);
var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
var d = R * c;
return d; // returns the distance in meter
};
There actually seems to be a method in GMap3. It's a static method of the google.maps.geometry.spherical namespace.
It takes as arguments two LatLng objects and will utilize a default Earth radius of 6378137 meters, although the default radius can be overridden with a custom value if necessary.
Make sure you include:
<script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=false&v=3&libraries=geometry"></script>
in your head section.
The call will be:
google.maps.geometry.spherical.computeDistanceBetween (latLngA, latLngB);
Example using GPS latitude/longitude of 2 points.
var latitude1 = 39.46;
var longitude1 = -0.36;
var latitude2 = 40.40;
var longitude2 = -3.68;
var distance = google.maps.geometry.spherical.computeDistanceBetween(new google.maps.LatLng(latitude1, longitude1), new google.maps.LatLng(latitude2, longitude2));
Just add this to the beginning of your JavaScript code:
google.maps.LatLng.prototype.distanceFrom = function(latlng) {
var lat = [this.lat(), latlng.lat()]
var lng = [this.lng(), latlng.lng()]
var R = 6378137;
var dLat = (lat[1]-lat[0]) * Math.PI / 180;
var dLng = (lng[1]-lng[0]) * Math.PI / 180;
var a = Math.sin(dLat/2) * Math.sin(dLat/2) +
Math.cos(lat[0] * Math.PI / 180 ) * Math.cos(lat[1] * Math.PI / 180 ) *
Math.sin(dLng/2) * Math.sin(dLng/2);
var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
var d = R * c;
return Math.round(d);
}
and then use the function like this:
var loc1 = new GLatLng(52.5773139, 1.3712427);
var loc2 = new GLatLng(52.4788314, 1.7577444);
var dist = loc2.distanceFrom(loc1);
alert(dist/1000);
//p1 and p2 are google.maps.LatLng(x,y) objects
function calcDistance(p1, p2) {
var d = (google.maps.geometry.spherical.computeDistanceBetween(p1, p2) / 1000).toFixed(2);
console.log(d);
}
Here is the c# implementation of the this forumula
public class DistanceAlgorithm
{
const double PIx = 3.141592653589793;
const double RADIO = 6378.16;
/// <summary>
/// This class cannot be instantiated.
/// </summary>
private DistanceAlgorithm() { }
/// <summary>
/// Convert degrees to Radians
/// </summary>
/// <param name="x">Degrees</param>
/// <returns>The equivalent in radians</returns>
public static double Radians(double x)
{
return x * PIx / 180;
}
/// <summary>
/// Calculate the distance between two places.
/// </summary>
/// <param name="lon1"></param>
/// <param name="lat1"></param>
/// <param name="lon2"></param>
/// <param name="lat2"></param>
/// <returns></returns>
public static double DistanceBetweenPlaces(
double lon1,
double lat1,
double lon2,
double lat2)
{
double dlon = Radians(lon2 - lon1);
double dlat = Radians(lat2 - lat1);
double a = (Math.Sin(dlat / 2) * Math.Sin(dlat / 2)) + Math.Cos(Radians(lat1)) * Math.Cos(Radians(lat2)) * (Math.Sin(dlon / 2) * Math.Sin(dlon / 2));
double angle = 2 * Math.Atan2(Math.Sqrt(a), Math.Sqrt(1 - a));
return (angle * RADIO) * 0.62137;//distance in miles
}
}
With google you can do it using the spherical api, google.maps.geometry.spherical.computeDistanceBetween (latLngA, latLngB);.
However, if the precision of a spherical projection or a haversine solution is not precise enough for you (e.g. if you're close to the pole or computing longer distances), you should use a different library.
Most information on the subject I found on Wikipedia here.
A trick to see if the precision of any given algorithm is adequate is to fill in the maximum and minimum radius of the earth and see if the difference might cause problems for your use case. Many more details can be found in this article
In the end the google api or haversine will serve most purposes without problems.
Using PHP, you can calculate the distance using this simple function :
// to calculate distance between two lat & lon
function calculate_distance($lat1, $lon1, $lat2, $lon2, $unit='N')
{
$theta = $lon1 - $lon2;
$dist = sin(deg2rad($lat1)) * sin(deg2rad($lat2)) + cos(deg2rad($lat1)) * cos(deg2rad($lat2)) * cos(deg2rad($theta));
$dist = acos($dist);
$dist = rad2deg($dist);
$miles = $dist * 60 * 1.1515;
$unit = strtoupper($unit);
if ($unit == "K") {
return ($miles * 1.609344);
} else if ($unit == "N") {
return ($miles * 0.8684);
} else {
return $miles;
}
}
// function ends here
OFFLINE SOLUTION - Haversine Algorithm
In Javascript
var _eQuatorialEarthRadius = 6378.1370;
var _d2r = (Math.PI / 180.0);
function HaversineInM(lat1, long1, lat2, long2)
{
return (1000.0 * HaversineInKM(lat1, long1, lat2, long2));
}
function HaversineInKM(lat1, long1, lat2, long2)
{
var dlong = (long2 - long1) * _d2r;
var dlat = (lat2 - lat1) * _d2r;
var a = Math.pow(Math.sin(dlat / 2.0), 2.0) + Math.cos(lat1 * _d2r) * Math.cos(lat2 * _d2r) * Math.pow(Math.sin(dlong / 2.0), 2.0);
var c = 2.0 * Math.atan2(Math.sqrt(a), Math.sqrt(1.0 - a));
var d = _eQuatorialEarthRadius * c;
return d;
}
var meLat = -33.922982;
var meLong = 151.083853;
var result1 = HaversineInKM(meLat, meLong, -32.236457779983745, 148.69094705162837);
var result2 = HaversineInKM(meLat, meLong, -33.609020205923713, 150.77061469270831);
C#
using System;
public class Program
{
public static void Main()
{
Console.WriteLine("Hello World");
var meLat = -33.922982;
double meLong = 151.083853;
var result1 = HaversineInM(meLat, meLong, -32.236457779983745, 148.69094705162837);
var result2 = HaversineInM(meLat, meLong, -33.609020205923713, 150.77061469270831);
Console.WriteLine(result1);
Console.WriteLine(result2);
}
static double _eQuatorialEarthRadius = 6378.1370D;
static double _d2r = (Math.PI / 180D);
private static int HaversineInM(double lat1, double long1, double lat2, double long2)
{
return (int)(1000D * HaversineInKM(lat1, long1, lat2, long2));
}
private static double HaversineInKM(double lat1, double long1, double lat2, double long2)
{
double dlong = (long2 - long1) * _d2r;
double dlat = (lat2 - lat1) * _d2r;
double a = Math.Pow(Math.Sin(dlat / 2D), 2D) + Math.Cos(lat1 * _d2r) * Math.Cos(lat2 * _d2r) * Math.Pow(Math.Sin(dlong / 2D), 2D);
double c = 2D * Math.Atan2(Math.Sqrt(a), Math.Sqrt(1D - a));
double d = _eQuatorialEarthRadius * c;
return d;
}
}
Reference:
https://en.wikipedia.org/wiki/Great-circle_distance
Had to do it... The action script way
//just make sure you pass a number to the function because it would accept you mother in law...
public var rad = function(x:*) {return x*Math.PI/180;}
protected function distHaversine(p1:Object, p2:Object):Number {
var R:int = 6371; // earth's mean radius in km
var dLat:Number = rad(p2.lat() - p1.lat());
var dLong:Number = rad(p2.lng() - p1.lng());
var a:Number = Math.sin(dLat/2) * Math.sin(dLat/2) +
Math.cos(rad(p1.lat())) * Math.cos(rad(p2.lat())) * Math.sin(dLong/2) * Math.sin(dLong/2);
var c:Number = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
var d:Number = R * c;
return d;
}
In my case it was best to calculate this in SQL Server, since i wanted to take current location and then search for all zip codes within a certain distance from current location. I also had a DB which contained a list of zip codes and their lat longs. Cheers
--will return the radius for a given number
create function getRad(#variable float)--function to return rad
returns float
as
begin
declare #retval float
select #retval=(#variable * PI()/180)
--print #retval
return #retval
end
go
--calc distance
--drop function dbo.getDistance
create function getDistance(#cLat float,#cLong float, #tLat float, #tLong float)
returns float
as
begin
declare #emr float
declare #dLat float
declare #dLong float
declare #a float
declare #distance float
declare #c float
set #emr = 6371--earth mean
set #dLat = dbo.getRad(#tLat - #cLat);
set #dLong = dbo.getRad(#tLong - #cLong);
set #a = sin(#dLat/2)*sin(#dLat/2)+cos(dbo.getRad(#cLat))*cos(dbo.getRad(#tLat))*sin(#dLong/2)*sin(#dLong/2);
set #c = 2*atn2(sqrt(#a),sqrt(1-#a))
set #distance = #emr*#c;
set #distance = #distance * 0.621371 -- i needed it in miles
--print #distance
return #distance;
end
go
--get all zipcodes within 2 miles, the hardcoded #'s would be passed in by C#
select *
from cityzips a where dbo.getDistance(29.76,-95.38,a.lat,a.long) <3
order by zipcode
//JAVA
public Double getDistanceBetweenTwoPoints(Double latitude1, Double longitude1, Double latitude2, Double longitude2) {
final int RADIUS_EARTH = 6371;
double dLat = getRad(latitude2 - latitude1);
double dLong = getRad(longitude2 - longitude1);
double a = Math.sin(dLat / 2) * Math.sin(dLat / 2) + Math.cos(getRad(latitude1)) * Math.cos(getRad(latitude2)) * Math.sin(dLong / 2) * Math.sin(dLong / 2);
double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
return (RADIUS_EARTH * c) * 1000;
}
private Double getRad(Double x) {
return x * Math.PI / 180;
}
/**
* Calculates the haversine distance between point A, and B.
* #param {number[]} latlngA [lat, lng] point A
* #param {number[]} latlngB [lat, lng] point B
* #param {boolean} isMiles If we are using miles, else km.
*/
function haversineDistance(latlngA, latlngB, isMiles) {
const squared = x => x * x;
const toRad = x => (x * Math.PI) / 180;
const R = 6371; // Earth’s mean radius in km
const dLat = toRad(latlngB[0] - latlngA[0]);
const dLon = toRad(latlngB[1] - latlngA[1]);
const dLatSin = squared(Math.sin(dLat / 2));
const dLonSin = squared(Math.sin(dLon / 2));
const a = dLatSin +
(Math.cos(toRad(latlngA[0])) * Math.cos(toRad(latlngB[0])) * dLonSin);
const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
let distance = R * c;
if (isMiles) distance /= 1.609344;
return distance;
}
I found a version online which is 80% right but plugged in the wrong parameter and is inconsistent in using the inputs, this version fixed that completely
It's Quite easy using Google Distance Matrix service
First step is to activate Distance Matrix service from google API console.
it returns distances between a set of locations.
And apply this simple function
function initMap() {
var bounds = new google.maps.LatLngBounds;
var markersArray = [];
var origin1 = {lat:23.0203, lng: 72.5562};
//var origin2 = 'Ahmedabad, India';
var destinationA = {lat:23.0436503, lng: 72.55008939999993};
//var destinationB = {lat: 23.2156, lng: 72.6369};
var destinationIcon = 'https://chart.googleapis.com/chart?' +
'chst=d_map_pin_letter&chld=D|FF0000|000000';
var originIcon = 'https://chart.googleapis.com/chart?' +
'chst=d_map_pin_letter&chld=O|FFFF00|000000';
var map = new google.maps.Map(document.getElementById('map'), {
center: {lat: 55.53, lng: 9.4},
zoom: 10
});
var geocoder = new google.maps.Geocoder;
var service = new google.maps.DistanceMatrixService;
service.getDistanceMatrix({
origins: [origin1],
destinations: [destinationA],
travelMode: 'DRIVING',
unitSystem: google.maps.UnitSystem.METRIC,
avoidHighways: false,
avoidTolls: false
}, function(response, status) {
if (status !== 'OK') {
alert('Error was: ' + status);
} else {
var originList = response.originAddresses;
var destinationList = response.destinationAddresses;
var outputDiv = document.getElementById('output');
outputDiv.innerHTML = '';
deleteMarkers(markersArray);
var showGeocodedAddressOnMap = function(asDestination) {
var icon = asDestination ? destinationIcon : originIcon;
return function(results, status) {
if (status === 'OK') {
map.fitBounds(bounds.extend(results[0].geometry.location));
markersArray.push(new google.maps.Marker({
map: map,
position: results[0].geometry.location,
icon: icon
}));
} else {
alert('Geocode was not successful due to: ' + status);
}
};
};
for (var i = 0; i < originList.length; i++) {
var results = response.rows[i].elements;
geocoder.geocode({'address': originList[i]},
showGeocodedAddressOnMap(false));
for (var j = 0; j < results.length; j++) {
geocoder.geocode({'address': destinationList[j]},
showGeocodedAddressOnMap(true));
//outputDiv.innerHTML += originList[i] + ' to ' + destinationList[j] + ': ' + results[j].distance.text + ' in ' + results[j].duration.text + '<br>';
outputDiv.innerHTML += results[j].distance.text + '<br>';
}
}
}
});
}
Where origin1 is your location and destinationA is destindation location.you can add above two or more data.
Rad Full Documentation with an example
To calculate distance on Google Maps, you can use Directions API. That will be one of the easiest way to do it. To get data from Google Server, you can use Retrofit or Volley. Both has their own advantage. Take a look at following code where I have used retrofit to implement it:
private void build_retrofit_and_get_response(String type) {
String url = "https://maps.googleapis.com/maps/";
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(url)
.addConverterFactory(GsonConverterFactory.create())
.build();
RetrofitMaps service = retrofit.create(RetrofitMaps.class);
Call<Example> call = service.getDistanceDuration("metric", origin.latitude + "," + origin.longitude,dest.latitude + "," + dest.longitude, type);
call.enqueue(new Callback<Example>() {
#Override
public void onResponse(Response<Example> response, Retrofit retrofit) {
try {
//Remove previous line from map
if (line != null) {
line.remove();
}
// This loop will go through all the results and add marker on each location.
for (int i = 0; i < response.body().getRoutes().size(); i++) {
String distance = response.body().getRoutes().get(i).getLegs().get(i).getDistance().getText();
String time = response.body().getRoutes().get(i).getLegs().get(i).getDuration().getText();
ShowDistanceDuration.setText("Distance:" + distance + ", Duration:" + time);
String encodedString = response.body().getRoutes().get(0).getOverviewPolyline().getPoints();
List<LatLng> list = decodePoly(encodedString);
line = mMap.addPolyline(new PolylineOptions()
.addAll(list)
.width(20)
.color(Color.RED)
.geodesic(true)
);
}
} catch (Exception e) {
Log.d("onResponse", "There is an error");
e.printStackTrace();
}
}
#Override
public void onFailure(Throwable t) {
Log.d("onFailure", t.toString());
}
});
}
Above is the code of function build_retrofit_and_get_response for calculating distance. Below is corresponding Retrofit Interface:
package com.androidtutorialpoint.googlemapsdistancecalculator;
import com.androidtutorialpoint.googlemapsdistancecalculator.POJO.Example;
import retrofit.Call;
import retrofit.http.GET;
import retrofit.http.Query;
public interface RetrofitMaps {
/*
* Retrofit get annotation with our URL
* And our method that will return us details of student.
*/
#GET("api/directions/json?key=AIzaSyC22GfkHu9FdgT9SwdCWMwKX1a4aohGifM")
Call<Example> getDistanceDuration(#Query("units") String units, #Query("origin") String origin, #Query("destination") String destination, #Query("mode") String mode);
}
I hope this explains your query. All the best :)
Source: Google Maps Distance Calculator
First, are you referring to distance as in length of the entire path or you want to know only the displacement (straight line distance)? I see no one is pointing the difference between distance and displacement here. For distance calculate each route point given by JSON/XML data, as for displacement there is a built-in solution using Spherical class
//calculates distance between two points in km's
function calcDistance(p1, p2) {
return (google.maps.geometry.spherical.computeDistanceBetween(p1, p2) / 1000).toFixed(2);
}
In PHP, with Google Map Distance Matrix API:
//Get the Driving(Mode) distance between two Geo-location points(Latitude, Longitude) pair.
function get_distance($lat1, $lat2, $long1, $long2)
{
$url = "https://maps.googleapis.com/maps/api/distancematrix/json?origins=".$lat1.",".$long1."&destinations=".$lat2.",".$long2."&mode=driving"."&units=imperial";
//You can request distance data for different travel modes, request distance data in different units such as kilometers or miles, and estimate travel time in traffic.
try{
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_PROXYPORT, 3128);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
$response = curl_exec($ch);
curl_close($ch);
$response_a = json_decode($response, true);
//Invalid request OR Empty response
if(isset($response_a['error_message']) || empty($response_a['rows']))
throw new Exception($response_a['error_message']);
} catch(Exception $e){
//Handle error here.
return [];
}
//The unit parameter in the request URL only affects the text displayed within distance fields. The distance fields in response also contain values that are always expressed in meters.
$dist = $response_a['rows'][0]['elements'][0]['distance']['text'];
$time = $response_a['rows'][0]['elements'][0]['duration']['text'];
return ['distance' => $dist, 'time' => $time];
}
Reference: Distance Matrix API request and response
I am working on a sort of itinerary mapper for packaged vacations, and I'm really happy with what I've done so far; I have the directions api implemented with a custom renderer, so I can take driving directions, and plot my own polyline complete with directional arrows that aren't google's awful ones spaced along the path. I am not exactly a math expert, and I am trying to figure out how I could make a path parallel to another path. For example, the itinerary goes from city 1 to city 2, and then back to city 1.
I want to offset the trip back to city 1's polyline, so that it mirrors the path, but travels parallel to it. Ideally, I would like to when I create the path, check for intersecting points in other paths, and if any are found, offset the path at those points only. This would be a better implementation, because you could for instance parallel the path only where it happens to intersect another one, like when it meets another path only for a short time.
I found this code for API2 from bill chadwick
The link is here: http://wtp2.appspot.com/ParallelLines.htm
Update: Somehow managed to convert this old v2 script to get it working in v3, but I'm experiencing some troubles...
It is more than doubling the original number of points, and following the path, but really throwing them in randomly. Screenshot here:
The class I converted is here:
function BDCCParallelLines(points, color, weight, opacity, opts, gapPx) {
console.log('Pllel COnstructor Initialized');
this.gapPx = gapPx;
this.points = points;
this.color = color;
this.weight = weight;
this.opacity = opacity;
this.opts = opts;
this.line1 = null;
this.line2 = null;
this.lstnZoom = null;
}
BDCCParallelLines.prototype = new google.maps.OverlayView();
BDCCParallelLines.prototype.onAdd = function() {
console.log('Pllel Initialized');
this.prj = map.getProjection();
var self = this;
this.lstnZoom = google.maps.event.addListener(map, "zoom_changed", function() {
self.recalc();
});
this.recalc();//first draw
}
BDCCParallelLines.prototype.onRemove = function() {
if(this.line2)
this.line2.setMap(null);
if(this.line1)
this.line1.setMap(null);
if(this.lstnZoom != null)
google.maps.event.removeListener(this.lstnZoom);
}
BDCCParallelLines.prototype.copy = function() {
return new BDCCParallelLines(this.points,this.color,this.weight,this.opacity,this.opts,this.gapPx);
}
BDCCParallelLines.prototype.draw = function(force) {
return; //do nothing
}
/**
* #param {google.maps.Map} map
* #param {google.maps.LatLng} latlng
* #param {int} z
* #return {google.maps.Point}
*/
BDCCParallelLines.prototype.latLngToPoint = function(latlng, z){
var normalizedPoint = map.getProjection().fromLatLngToPoint(latlng); // returns x,y normalized to 0~255
var scale = Math.pow(2, z);
var pixelCoordinate = new google.maps.Point(normalizedPoint.x * scale, normalizedPoint.y * scale);
return pixelCoordinate;
};
/**
* #param {google.maps.Map} map
* #param {google.maps.Point} point
* #param {int} z
* #return {google.maps.LatLng}
*/
BDCCParallelLines.prototype.pointToLatlng = function(point, z){
var scale = Math.pow(2, z);
var normalizedPoint = new google.maps.Point(point.x / scale, point.y / scale);
var latlng = map.getProjection().fromPointToLatLng(normalizedPoint);
return latlng;
};
BDCCParallelLines.prototype.recalc = function() {
var distallowance;
console.log('recalc called');
var zoom = map.getZoom();
distallowance = 1.6;
if(zoom > 6){
distallowance = 1.3;
if(zoom > 9){
distallowance = .7;
if( zoom > 13){
distallowance = .2;
if( zoom > 15){
distallowance = .0001;
}
}
}
}
console.log('Zoom Level: ' + zoom);
console.log('Allowance = ' + distallowance);
var pts1 = new Array();//left side of center
//shift the pts array away from the centre-line by half the gap + half the line width
var o = (this.gapPx + this.weight)/2;
var p2l,p2r;
for (var i=1; i<this.points.length; i++){
var p1lm1;
var p1rm1;
var p2lm1;
var p2rm1;
var thetam1;
var p1 = this.latLngToPoint(this.points[i-1], zoom)
var p2 = this.latLngToPoint(this.points[i], zoom)
var theta = Math.atan2(p1.x-p2.x,p1.y-p2.y);
theta = theta + (Math.PI/2);
var dl = Math.sqrt(((p1.x-p2.x)*(p1.x-p2.x))+((p1.y-p2.y)*(p1.y-p2.y)));
if(theta > Math.PI)
theta -= Math.PI*2;
var dx = Math.round(o * Math.sin(theta));
var dy = Math.round(o * Math.cos(theta));
var p1l = new google.maps.Point(p1.x+dx,p1.y+dy);
var p1r = new google.maps.Point(p1.x-dx,p1.y-dy);
p2l = new google.maps.Point(p2.x+dx,p2.y+dy);
p2r = new google.maps.Point(p2.x-dx,p2.y-dy);
if(i==1){ //first point
pts1.push(this.pointToLatlng(p1l,zoom));
}
else{ // mid this.points
if(distbetweentwo(this.points[i-1], this.points[i]) > distallowance){
if(theta == thetam1){
// adjacent segments in a straight line
pts1.push(this.pointToLatlng(p1l,zoom));
}
else{
var pli = this.intersect(p1lm1,p2lm1,p1l,p2l);
var pri = this.intersect(p1rm1,p2rm1,p1r,p2r);
var dlxi = (pli.x-p1.x);
var dlyi = (pli.y-p1.y);
var drxi = (pri.x-p1.x);
var dryi = (pri.y-p1.y);
var di = Math.sqrt((drxi*drxi)+(dryi*dryi));
var s = o / di;
var dTheta = theta - thetam1;
if(dTheta < (Math.PI*2))
dTheta += Math.PI*2;
if(dTheta > (Math.PI*2))
dTheta -= Math.PI*2;
if(dTheta < Math.PI){
//intersect point on outside bend
pts1.push(this.pointToLatlng(p2lm1,zoom));
pts1.push(this.pointToLatlng(new google.maps.Point(p1.x+(s*dlxi),p1.y+(s*dlyi)),zoom));
pts1.push(this.pointToLatlng(p1l,zoom));
}
else if (di < dl){
pts1.push(this.pointToLatlng(pli,zoom));
}
else{
pts1.push(this.pointToLatlng(p2lm1,zoom));
pts1.push(this.pointToLatlng(p1l,zoom));
}
}
}
else{
//console.log(distbetweentwo(this.points[i-1], this.points[i]));
}
}
p1lm1 = p1l;
p1rm1 = p1r;
p2lm1 = p2l;
p2rm1 = p2r;
thetam1 = theta;
//end loop
}
pts1.push(this.pointToLatlng(p2l,zoom));//final point
// console.log(pts1);
if(this.line1)
this.line1.setMap(null);
this.line1 = new google.maps.Polyline({
strokeColor: this.color,
strokeOpacity: this.opacity,
strokeWeight: this.weight,
map: map,
path: pts1 });
this.line1.setMap(map);
}
BDCCParallelLines.prototype.intersect = function(p0,p1,p2,p3)
{
// this function computes the intersection of the sent lines p0-p1 and p2-p3
// and returns the intersection point,
var a1,b1,c1, // constants of linear equations
a2,b2,c2,
det_inv, // the inverse of the determinant of the coefficient matrix
m1,m2; // the slopes of each line
var x0 = p0.x;
var y0 = p0.y;
var x1 = p1.x;
var y1 = p1.y;
var x2 = p2.x;
var y2 = p2.y;
var x3 = p3.x;
var y3 = p3.y;
// compute slopes, note the cludge for infinity, however, this will
// be close enough
if ((x1-x0)!=0)
m1 = (y1-y0)/(x1-x0);
else
m1 = 1e+10; // close enough to infinity
if ((x3-x2)!=0)
m2 = (y3-y2)/(x3-x2);
else
m2 = 1e+10; // close enough to infinity
// compute constants
a1 = m1;
a2 = m2;
b1 = -1;
b2 = -1;
c1 = (y0-m1*x0);
c2 = (y2-m2*x2);
// compute the inverse of the determinate
det_inv = 1/(a1*b2 - a2*b1);
// use Kramers rule to compute xi and yi
var xi=((b1*c2 - b2*c1)*det_inv);
var yi=((a2*c1 - a1*c2)*det_inv);
return new google.maps.Point(Math.round(xi),Math.round(yi));
}
This is working to a point... It is working as well as the original implementation. The entire path is recalculated on a zoom basis, and I kind of hacked the function to skip very short paths(weird angles) at higher zoom levels, it more closely follows the path the more you zoom in.
I would rather just have a fixed distance offset that is not recalculated, as it is pretty intensive... There are many programs which accomplish this feat, rhino3d, autocad, illustrator... I feel like it would be great for driving directions for google maps itself, an offsetting of the path so you can distinguish the return trip and the original trip.
If anybody has done anything similar to this in JS even if its not for google maps specifically, I would love to see it. Links I am investigating:
http://processingjs.nihongoresources.com/bezierinfo/
http://www.groupsrv.com/computers/about21532.html
Offsetting paths in general is a pretty tricky buisness. This paper (scientific paper alert) gives a good description of the steps taken for 'professional' offset algorithms.
http://cgcad.thss.tsinghua.edu.cn/~yongjh/papers/CiI2007V58N03P0240.pdf
You don't seem to want anything as fancy as in the demo. From what I gather you just want the same polyline, only shifted some pixels to the right and maybe some to the top so it doesn't overlap.
The code you posted has a latLngToPoint function and pointToLatLng function. I think the directions you get from Google are LatLng, so you can convert those to Points, increase the x and y property, and convert it back to a LatLng and draw your Polyline.
This should get you a line that exactly follows the original line. But, it wont look as fancy as the one in the demo. Since it wont be adding any points to smooth the line.