Ahead of the Curve – Drawing Quadratic Curves using Bing Maps

In recent months at True Clarity we have been working on a complex project, involving the integration of Bing Maps and Sitecore. One challenge we had to overcome as part of this required drawing nicely curved lines between two points, which sadly is not an “out-of-the-box” feature of Bing Maps.  So, with a little judicious research into how others in the development community had approached it, this is what we came up with:

The core code used to produce these curves is a simple method that returns an array of Location objects (which is available as a default Bing Maps Datatype); these location objects are then used to create a Polyline (again a Bing Maps Datatype); this can then be added to a layer and after that Bing maps will handle all the rendering.

This method allows you to specify the number of segments you wish the Polyline to be made up from (as ever, there is a trade-off where more segments gives a smoother curve, but more processing is required in the browser), as well as a factor that is used to adjust the curvature of the line.  The latter allows control over how “curvy” or “straight” the line looks, which can vary by your project’s requirements.  You must also specify the start and end points of the line as Location Objects.

// Creates Quadratic Curve approximation of the lines drawn between an array
// of points, by dividing each line into a number of segments.
function ToQuadratic(lineStart, lineEnd, n, factor)
{
if (!n) { n = 32 }; // The number of line segments to use
var locs = new Array();
with (Math)
{
var startLat = lineStart.latitude;
var startLong = lineStart.longitude;
var endLat = lineEnd.latitude;
var endLong = lineEnd.longitude;

if (!factor) { factor = 5 }; //potentially factor this inversely based on distance covered as amount of curve will increase exponentially as is

for (var k = 0; k <= n; k++)
{
var percent = (k / n);
var zeroOffset = (endLong - startLong) / factor;
var peakOffset = zeroOffset / 2;
var dist = (zeroOffset * percent) - zeroOffset;

// calc segments of straight line
var latitude = ((endLat - startLat) * percent) + startLat;
var longitude = ((endLong - startLong) * percent) + startLong;

//transform the line to add the curve, based on a quadratic -(X+(b))^2+b^2
//transform x and y sep
var latitudeDifference = -pow(dist + peakOffset, 2) + pow(peakOffset, 2);
latitude = latitudeDifference + latitude;

zeroOffset = (endLat - startLat) / factor;
peakOffset = zeroOffset / 2;
dist = (zeroOffset * percent) - zeroOffset;

//we transform x and y sep
var longitudeDifference = -pow(dist + peakOffset, 2) + pow(peakOffset, 2);

//ensure Curves correct way if going left or right the map
if (startLong < endLong)
{
longitude = longitudeDifference + longitude;
}
else
{
longitude = longitude - longitudeDifference;
}

var p = new Microsoft.Maps.Location(latitude, longitude);
// Add this to the array
locs.push(p);
}

}
return locs;
}

To use this code, you would simply call the method above and create a Polyline from the results, then push this to a layer of your map, as follows:

var geodesicLocs = ToQuadratic(new Microsoft.Maps.Location(origin.lat,origin.long), new Microsoft.Maps.Location(destination.lat,destination.long), 16, 5);
var geodesicShape = new Microsoft.Maps.Polyline(geodesicLocs);
mapContext.geodesicLayer.push(geodesicShape);

And the results are beautiful curves across the map.  Of course, if there are a large number of such curves to draw, or you choose to use a large number of intermediate points, then this will bring performance issues into the equation, but the basic mechanics of producing the curves is now done.

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