One of the new features in the Advanced Sitecore Google Maps (WCAG edition) is the ability to draw polylines. Polylines in Google Maps can be drawn using 2 methods: By creating a new GPolyline with the array of coordinates to draw, or by using the GPolyline.fromEncoded function which takes an encoded string of coordinates and renders this as a line.
The encoded polyline function has the advantage of being faster and more compressed compared with feeding the GPolyline with an array of coordinates. However, some of the precision is lost, as the encoding algorithm only uses 5 digit coordinates. 5 digits is still a pretty good precision, so I decided to go with the encoded string.
I was looking for a method of encoded my coordinates in C# when i stumbled upon a solution on the SoulSolutions webpage, where the developer demonstrates a Javascript and C# method to encode and decode polyline coordinates.
This is the C# method re-written. SoulSolutions should be credited for the code. However, his code examples are incomplete, so I rewrote them. First I need a Coordinate class, which contains the latitude and longitude of a coordinate set (I have removed comments and other stuff to compress the code):
public class Coordinate
{
public double Latitude { get; set; }
public double Longitude { get; set; }
}
The following function EncodeCoordinates encodes a list of coordinates into an encoded string:
/// <summary>
/// Encodes the list of coordinates to a Google Maps encoded coordinate string.
/// </summary>
/// <param name="coordinates">The coordinates.</param>
/// <returns>Encoded coordinate string</returns>
public static string EncodeCoordinates(List<Coordinate> coordinates)
{
int plat = 0;
int plng = 0;
StringBuilder encodedCoordinates = new StringBuilder();
foreach (Coordinate coordinate in coordinates)
{
// Round to 5 decimal places and drop the decimal
int late5 = (int)(coordinate.Latitude * 1e5);
int lnge5 = (int)(coordinate.Longitude * 1e5);
// Encode the differences between the coordinates
encodedCoordinates.Append(EncodeSignedNumber(late5 - plat));
encodedCoordinates.Append(EncodeSignedNumber(lnge5 - plng));
// Store the current coordinates
plat = late5;
plng = lnge5;
}
return encodedCoordinates.ToString();
}
/// <summary>
/// Encode a signed number in the encode format.
/// </summary>
/// <param name="num">The signed number</param>
/// <returns>The encoded string</returns>
private static string EncodeSignedNumber(int num)
{
int sgn_num = num << 1; //shift the binary value
if (num < 0) //if negative invert
{
sgn_num = ~(sgn_num);
}
return (EncodeNumber(sgn_num));
}
/// <summary>
/// Encode an unsigned number in the encode format.
/// </summary>
/// <param name="num">The unsigned number</param>
/// <returns>The encoded string</returns>
private static string EncodeNumber(int num)
{
StringBuilder encodeString = new StringBuilder();
while (num >= 0x20)
{
encodeString.Append((char)((0x20 | (num & 0x1f)) + 63));
num >>= 5;
}
encodeString.Append((char)(num + 63));
// All backslashes needs to be replaced with double backslashes
// before being used in a Javascript string.
return encodeString.ToString().Replace(@"\", @"\\");
}
Using the encoded string, I can draw a line surrounding Denmark like this:
var line = new GPolyline.fromEncoded({
color: "#0000FF",
weight: 5,
opacity: 0.5,
points: "kpgiI}{wt@{xeDfxv@ylqC|flAyfyDidPiioBoabD_fkAyjfDooZ{nyCtw_BihCnzlBzbyAl}XehjBfp`B_se@vdgAhdPya_BoabDipHoabDngiAsen@jz}@htcAzqt@itcAnha@|~eBdzh@qqnBf~w@zrlCjkx@fppAy{u@zflA{zRpeuC`zWh`]bmx@}byAlwn@ny{DncNn}nDsxd@uqG",
levels: "BBBBBBBBBBBBBBBBBBBBBBBBBBBB",
zoomFactor: 32,
numLevels: 4 });
The line looks like this using 28 coordinates:
