Skip to content

Instantly share code, notes, and snippets.

@yutopio
Created May 12, 2015 05:42
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save yutopio/b1a273893399668b418e to your computer and use it in GitHub Desktop.
Save yutopio/b1a273893399668b418e to your computer and use it in GitHub Desktop.
Google Maps Polyline encoder / decoder.
using System;
public partial struct Location
{
public static readonly Location Empty;
static Location()
{
Empty = new Location { Latitude = 0, Longitude = 0 };
}
public double Latitude { get; set; }
public double Longitude { get; set; }
public static bool operator ==(Location l1, Location l2)
{
return l1.Latitude == l2.Latitude && l1.Longitude == l2.Longitude;
}
public static bool operator !=(Location l1, Location l2)
{
return l1.Latitude != l2.Latitude || l1.Longitude != l2.Longitude;
}
public override bool Equals(object obj)
{
return obj is Location && this == (Location)obj;
}
}
// https://developers.google.com/maps/documentation/utilities/polylinealgorithm
using System;
using System.Collections.Generic;
using System.Text;
public static class Polyline
{
public static string Encode(IEnumerable<Location> points)
{
var sb = new StringBuilder();
var prev = Location.Empty;
foreach (var pt in points)
{
sb.Append(Encode(pt.Latitude - prev.Latitude));
sb.Append(Encode(pt.Longitude - prev.Longitude));
prev = pt;
}
return sb.ToString();
}
public static string Encode(double value)
{
if (value < -180 || value > 180) throw new ArgumentOutOfRangeException();
var val = (int)Math.Round(value * 1e5);
val = val >= 0 ? val * 2 : (-val) * 2 - 1;
byte[] buf = new byte[5];
for (var i = 0; i < 5; i++)
buf[i] = (byte)((val >> (i * 5)) & 0x1f);
for (byte i = 5, j = 0; i-- > 0;)
if ((buf[i] |= j) != 0) j = 0x20;
var sb = new StringBuilder(5);
for (var i = 0; i < 5 && buf[i] != 0; i++)
sb.Append((char)(buf[i] + 63));
return sb.ToString();
}
public static IEnumerable<Location> Decode(string value)
{
var loc = Location.Empty;
var latFlag = true;
foreach (var t in DecodeInternal(value))
{
if (latFlag)
loc.Latitude += t;
else
{
loc.Longitude += t;
yield return loc;
}
latFlag = !latFlag;
}
if (!latFlag)
throw new ArgumentException("Unexpected end of data.");
}
static IEnumerable<double> DecodeInternal(string value)
{
int i = 0, j = 0;
foreach (var t in value)
{
var c = (byte)(t - 63);
j |= (c & 0x1F) << (5 * i++);
if ((c & 0x20) == 0)
{
var n = (j & 1) == 1;
j >>= 1;
if (n) j = -(j + 1);
yield return j / 1e5d;
i = j = 0;
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment