Draw polyline across international dateline

By default Virtual Earth does not draw polylines across the international dateline (-180/180 degrees longitude) in 2D mode. The following code is an example of how to over come this issue. This code draws a polyline from Sydney Australia to Los Angeles California, which is a common airplane route. What this code does is determine the point of intersection of the path with the international date line. It then creates two polylines to represent this path. The algorithms use din this code are documented in the VE Math section of this blog.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html> <head> <title></title> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <script src="http://dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=6.2"></script> <script> var earthRadius = 6367; //radius in km var map;
var start = new VELatLong(-33.93979,151.17625);
var end = new VELatLong(33.94051,-118.40738);
var correctedPolyline1;
var correctedPolyline2;
var standardPolyline;

function GetMap()
{
map = new VEMap('mymap');
map.LoadMap(new VELatLong(0,0),1);

var pin1 = new VEShape(VEShapeType.Pushpin,start);
pin1.SetTitle("start");

var pin2 = new VEShape(VEShapeType.Pushpin,end);
pin2.SetTitle("end");

standardPolyline = new VEShape(VEShapeType.Polyline,[start,end]);
standardPolyline.HideIcon();

var points = crossDateLine(start,end);

correctedPolyline1 = new VEShape(VEShapeType.Polyline,[points[0],points[1]]);
correctedPolyline2 = new VEShape(VEShapeType.Polyline,[points[2],points[3]]);

correctedPolyline1.HideIcon();
correctedPolyline2.HideIcon();

map.AddShape([pin1,pin2,standardPolyline,correctedPolyline1,correctedPolyline2]);
showLines();
map.AttachEvent("onchangeview",mapModeChanged);
}

function mapModeChanged(e)
{
if(e!=null)
{
showLines();
}
}

function showLines()
{
if(map.GetMapMode()==VEMapMode.Mode2D)
{
correctedPolyline1.Show();
correctedPolyline2.Show();
standardPolyline.Hide();
}
else { correctedPolyline1.Hide(); correctedPolyline2.Hide(); standardPolyline.Show(); } } function DegtoRad(x)
{
return x*Math.PI/180;
}

function RadtoDeg(x)
{
return x*180/Math.PI;
}

function Cartesian(x,y,z)
{
this.X = x;
this.Y = y;
this.Z = z;
}

function convertSphericalToCartesian(latlong)
{
var lat = DegtoRad (latlong.Latitude);
var lon = DegtoRad (latlong.Longitude);
var x = earthRadius * Math.cos(lat)*Math.cos(lon);
var y = earthRadius * Math.cos(lat)*Math.sin(lon);
var z = earthRadius * Math.sin(lat);

return new Cartesian(x,y,z);
}

function convertCartesianToSpherical(cartesian)
{
var r = Math.sqrt(cartesian.X*cartesian.X + cartesian.Y*cartesian.Y+ cartesian.Z*cartesian.Z);
var lat = RadtoDeg(Math.asin(cartesian.Z/r));
var lon = lon = RadtoDeg(Math.atan2(cartesian.Y, cartesian.X));

return new VELatLong(lat,lon);
}

function crossProduct(p1,p2)
{
var x = p1.Y*p2.Z - p1.Z*p2.Y;
var y = p1.Z*p2.X - p1.X*p2.Z;
var z = p1.X*p2.Y - p1.Y*p2.X;

return new Cartesian(x,y,z);
}

function vectorLength(p1)
{
return Math.sqrt(p1.X*p1.X+p1.Y*p1.Y+p1.Z*p1.Z);
}

function unitVector(p1)
{
var length = vectorLength(p1);

return new Cartesian(p1.X/length,p1.Y/length,p1.Z/length);
}

function intersectionOfPlanes(latlong1,latlong2,latlong3,latlong4)
{
var point1 = convertSphericalToCartesian(latlong1);
var point2 = convertSphericalToCartesian(latlong2);
var point3 = convertSphericalToCartesian(latlong3);
var point4 = convertSphericalToCartesian(latlong4);

var vector1 = crossProduct(point1,point2);
var vector2 = crossProduct(point3,point4);

var unitVector1 = unitVector(vector1);
var unitVector2 = unitVector(vector2);

if((unitVector1.X != unitVector2.X )&& (unitVector1.Y != unitVector2.Y) && (unitVector1.Z != unitVector2.Z))
{
var vectorDirector = crossProduct(unitVector1,unitVector2);

var intersection1 = unitVector(vectorDirector);
var intersection2 = inverseCartesian(intersection1);

return new Array(convertCartesianToSpherical(intersection1),convertCartesianToSpherical(intersection2));
}

return -1;
}

function inverseCartesian(p1)
{
return new Cartesian(-1*p1.X,-1*p1.Y,-1*p1.Z);
}

function crossDateLine(startLatLong,endLatLong)
{
var points = intersectionOfPlanes(startLatLong,endLatLong,new VELatLong(90,-180),new VELatLong(-90,-180));

var intersection1;

if(points[0].Longitude==-180)
intersection1 = points[0];
else intersection1 = points[1]; return [startLatLong,new VELatLong(intersection1.Latitude,180),intersection1,endLatLong];

}
</script> </head> <body onload="GetMap();"> <div id='mymap' style="position:relative; height:600px; width:800px;"></div> </body> </html>
Advertisements

2 thoughts on “Draw polyline across international dateline

  1. Thanks. Translated this to C#; double.NaN got me on the flipside. Played a little more and the SDK doesn’t allow a smooth transition over the international date line.

    • This blog post would not likely work with the newer Bing Maps controls. The map control used when I wrote that post only handled a single “world” and did not allow you to pan continuously left/right.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s