Plotting Geography LineStrings on Google Maps and Virtual Earth

One problem of passing geography representations from SQL Server to web-mapping services such as Virtual Earth or Google Maps is that they treat the data as lying on a flat plane. This is fine for the geometry datatype, but presents a problem when trying to present geography data.

To demonstrate, consider the route taken by an aeroplane flying from Los Angeles (Latitude 34N, Longitude 118W) to London (Latitude 51.5N, Longitude 0), using the geography datatype.

SELECT
geography::STLineFromText('LINESTRING(-118 34, 0 51.5)', 4326)

Visualising this LineString using the spatial results tab in SQL Server Management Studio gives the correct result that, when projected onto a Mercator projection map, appears as shown below:

The problem is, when creating the equivalent Polyline constructor in Google Maps or Virtual Earth from this WKT, the default behaviour is to create a straight line between the points (34,-118) and (51.5,0) along the flat map plane, in which case you end up with the following route:

var polyline = new VEShape(VEShapeType.Polyline, [new VELatLong(34,-118), new VELatLong(51.5,0)]);
map.AddShape(polyline);

The solution

To get the map to correctly plot a linestring representing the great circle route between two points rather than simply a straight line on the map requires a different approach for Google Maps than for Virtual Earth.

Google Maps

The Google Maps Polyline constructor allows you to specify an option of geodesic: true, which will accurately portray the great circle route, as follows:

var polyline = new google.maps.Polyline(
  [new google.maps.LatLng(34,-118), new google.maps.LatLng(51.5,0)],
  "#ff0000",
  3,
  1,
  {geodesic:true});
map.addOverlay(polyline);

This results in the following map:

Virtual Earth

For Virtual Earth it's a little bit more complicated, because there is no inbuilt ability to draw geodesic shapes - you have to create your own function that calculates a number of waypoints along the length of the LineString, and then plots the segments between each waypoint to approximate the great cirlce route. That technique is demonstrated in the following code:
function AddGeodesicPolyline(start, end) {
  var segments = 32; // The number of line segments used to approximate the true curved route 
  var latLongs = new Array();
  with (Math) {
    // Convert all coordinates to Radians
    var lat1 = start.Latitude * (PI / 180);
    var lon1 = start.Longitude * (PI / 180);
    var lat2 = end.Latitude * (PI / 180);
    var lon2 = end.Longitude * (PI / 180);
    // Calculate the total extent of the route
    var d = 2 * asin(sqrt(pow((sin((lat1 - lat2) / 2)), 2) + cos(lat1) * cos(lat2) * pow((sin((lon1 - lon2) / 2)), 2)));
    // Calculate the position at fixed intervals along the route
    for (var n = 0; n < segments + 1; n++) {
      var f = (1 / segments) * n;
      f = f.toFixed(6);
      var A = sin((1 - f) * d) / sin(d)
      var B = sin(f * d) / sin(d)
      // Calculate 3D Cartesian coordinates of the point
      var x = A * cos(lat1) * cos(lon1) + B * cos(lat2) * cos(lon2)
      var y = A * cos(lat1) * sin(lon1) + B * cos(lat2) * sin(lon2)
      var z = A * sin(lat1) + B * sin(lat2)
      // Convert these to latitude/longitude
      var lat = atan2(z, sqrt(pow(x, 2) + pow(y, 2)))
      var lon = atan2(y, x)
      // Create a VELatLong representing this location (remember to convert back to degrees)
      var p = new VELatLong(lat / (PI / 180), lon / (PI / 180));
      // Add this to the array
      latLongs.push(p);
    }
  }
  // Create a new linestring from the LatLong array and add it to the map
  var linestring = new VEShape(VEShapeType.Polyline, latLongs);
  map.AddShape(linestring);
}

This is shown in the following map:

Comments

Post new comment

The content of this field is kept private and will not be shown publicly.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Allowed HTML tags: <a> <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd>
  • Lines and paragraphs break automatically.

More information about formatting options