namespace GMap.NET.MapProviders
{
using System;
using GMap.NET.Projections;
using System.Security.Cryptography;
using System.Diagnostics;
using System.Net;
using System.IO;
using System.Text.RegularExpressions;
using System.Threading;
using GMap.NET.Internals;
using System.Collections.Generic;
using System.Globalization;
using System.Xml;
using System.Text;
public abstract class GoogleMapProviderBase : GMapProvider, RoutingProvider, GeocodingProvider, DirectionsProvider
{
public GoogleMapProviderBase()
{
MaxZoom = null;
RefererUrl = string.Format("http://maps.{0}/", Server);
Copyright = string.Format("©{0} Google - Map data ©{0} Tele Atlas, Imagery ©{0} TerraMetrics", DateTime.Today.Year);
}
public readonly string Server = ThisIsLegalString("zOl/KnHzebJUqs6JWROaCQ==");
public readonly string ServerChina = ThisIsLegalString("zOl/KnHzebLqgdc2FRlQHg==");
public readonly string ServerKorea = ThisIsLegalString("ecw6OdJzJ/zgnFTB90qgtw==");
public readonly string ServerKoreaKr = ThisIsLegalString("zOl/KnHzebIhmuu+tK5lbw==");
public string SecureWord = "Galileo";
///
/// API generated using http://greatmaps.codeplex.com/
/// from http://tinyurl.com/3q6zhcw <- http://code.server.com/intl/en-us/apis/maps/signup.html
///
public string APIKey = @"ABQIAAAAWaQgWiEBF3lW97ifKnAczhRAzBk5Igf8Z5n2W3hNnMT0j2TikxTLtVIGU7hCLLHMAuAMt-BO5UrEWA";
#region GMapProvider Members
public override Guid Id
{
get
{
throw new NotImplementedException();
}
}
public override string Name
{
get
{
throw new NotImplementedException();
}
}
public override PureProjection Projection
{
get
{
return MercatorProjection.Instance;
}
}
GMapProvider[] overlays;
public override GMapProvider[] Overlays
{
get
{
if(overlays == null)
{
overlays = new GMapProvider[] { this };
}
return overlays;
}
}
public override PureImage GetTileImage(GPoint pos, int zoom)
{
throw new NotImplementedException();
}
#endregion
public bool TryCorrectVersion = true;
static bool init = false;
public override void OnInitialized()
{
if(!init && TryCorrectVersion)
{
string url = string.Format("http://maps.{0}", Server);
try
{
string html = GMaps.Instance.UseUrlCache ? Cache.Instance.GetContent(url, CacheType.UrlCache, TimeSpan.FromHours(8)) : string.Empty;
if(string.IsNullOrEmpty(html))
{
html = GetContentUsingHttp(url);
if(!string.IsNullOrEmpty(html))
{
if(GMaps.Instance.UseUrlCache)
{
Cache.Instance.SaveContent(url, CacheType.UrlCache, html);
}
}
}
if(!string.IsNullOrEmpty(html))
{
#region -- match versions --
Regex reg = new Regex(string.Format("\"*http://mt0.{0}/vt/lyrs=m@(\\d*)", Server), RegexOptions.IgnoreCase);
Match mat = reg.Match(html);
if(mat.Success)
{
GroupCollection gc = mat.Groups;
int count = gc.Count;
if(count > 0)
{
string ver = string.Format("m@{0}", gc[1].Value);
string old = GMapProviders.GoogleMap.Version;
GMapProviders.GoogleMap.Version = ver;
GMapProviders.GoogleChinaMap.Version = ver;
#if DEBUG
Debug.WriteLine("GMapProviders.GoogleMap.Version: " + ver + ", " + (ver == old ? "OK" : "old: " + old + ", consider updating source"));
if(Debugger.IsAttached && ver != old)
{
Thread.Sleep(5555);
}
#endif
}
}
reg = new Regex(string.Format("\"*http://mt0.{0}/vt/lyrs=h@(\\d*)", Server), RegexOptions.IgnoreCase);
mat = reg.Match(html);
if(mat.Success)
{
GroupCollection gc = mat.Groups;
int count = gc.Count;
if(count > 0)
{
string ver = string.Format("h@{0}", gc[1].Value);
string old = GMapProviders.GoogleHybridMap.Version;
GMapProviders.GoogleHybridMap.Version = ver;
GMapProviders.GoogleChinaHybridMap.Version = ver;
#if DEBUG
Debug.WriteLine("GMapProviders.GoogleHybridMap.Version: " + ver + ", " + (ver == old ? "OK" : "old: " + old + ", consider updating source"));
if(Debugger.IsAttached && ver != old)
{
Thread.Sleep(5555);
}
#endif
}
}
reg = new Regex(string.Format("\"*http://khm0.{0}/kh/v=(\\d*)", Server), RegexOptions.IgnoreCase);
mat = reg.Match(html);
if(mat.Success)
{
GroupCollection gc = mat.Groups;
int count = gc.Count;
if(count > 0)
{
string ver = gc[1].Value;
string old = GMapProviders.GoogleSatelliteMap.Version;
GMapProviders.GoogleSatelliteMap.Version = ver;
GMapProviders.GoogleKoreaSatelliteMap.Version = ver;
GMapProviders.GoogleChinaSatelliteMap.Version = "s@" + ver;
#if DEBUG
Debug.WriteLine("GMapProviders.GoogleSatelliteMap.Version: " + ver + ", " + (ver == old ? "OK" : "old: " + old + ", consider updating source"));
if(Debugger.IsAttached && ver != old)
{
Thread.Sleep(5555);
}
#endif
}
}
reg = new Regex(string.Format("\"*http://mt0.{0}/vt/lyrs=t@(\\d*),r@(\\d*)", Server), RegexOptions.IgnoreCase);
mat = reg.Match(html);
if(mat.Success)
{
GroupCollection gc = mat.Groups;
int count = gc.Count;
if(count > 1)
{
string ver = string.Format("t@{0},r@{1}", gc[1].Value, gc[2].Value);
string old = GMapProviders.GoogleTerrainMap.Version;
GMapProviders.GoogleTerrainMap.Version = ver;
GMapProviders.GoogleChinaTerrainMap.Version = ver;
#if DEBUG
Debug.WriteLine("GMapProviders.GoogleTerrainMap.Version: " + ver + ", " + (ver == old ? "OK" : "old: " + old + ", consider updating source"));
if(Debugger.IsAttached && ver != old)
{
Thread.Sleep(5555);
}
#endif
}
}
#endregion
}
init = true; // try it only once
}
catch(Exception ex)
{
Debug.WriteLine("TryCorrectGoogleVersions failed: " + ex.ToString());
}
}
}
internal void GetSecureWords(GPoint pos, out string sec1, out string sec2)
{
sec1 = string.Empty; // after &x=...
sec2 = string.Empty; // after &zoom=...
int seclen = (int)((pos.X * 3) + pos.Y) % 8;
sec2 = SecureWord.Substring(0, seclen);
if(pos.Y >= 10000 && pos.Y < 100000)
{
sec1 = Sec1;
}
}
static readonly string Sec1 = "&s=";
#region -- encryption --
static string EncryptString(string Message, string Passphrase)
{
byte[] Results;
System.Text.UTF8Encoding UTF8 = new System.Text.UTF8Encoding();
// Step 1. We hash the passphrase using MD5
// We use the MD5 hash generator as the result is a 128 bit byte array
// which is a valid length for the TripleDES encoder we use below
using(MD5CryptoServiceProvider HashProvider = new MD5CryptoServiceProvider())
{
byte[] TDESKey = HashProvider.ComputeHash(UTF8.GetBytes(Passphrase));
// Step 2. Create a new TripleDESCryptoServiceProvider object
using(TripleDESCryptoServiceProvider TDESAlgorithm = new TripleDESCryptoServiceProvider())
{
// Step 3. Setup the encoder
TDESAlgorithm.Key = TDESKey;
TDESAlgorithm.Mode = CipherMode.ECB;
TDESAlgorithm.Padding = PaddingMode.PKCS7;
// Step 4. Convert the input string to a byte[]
byte[] DataToEncrypt = UTF8.GetBytes(Message);
// Step 5. Attempt to encrypt the string
try
{
using(ICryptoTransform Encryptor = TDESAlgorithm.CreateEncryptor())
{
Results = Encryptor.TransformFinalBlock(DataToEncrypt, 0, DataToEncrypt.Length);
}
}
finally
{
// Clear the TripleDes and Hashprovider services of any sensitive information
TDESAlgorithm.Clear();
HashProvider.Clear();
}
}
}
// Step 6. Return the encrypted string as a base64 encoded string
return Convert.ToBase64String(Results);
}
static string DecryptString(string Message, string Passphrase)
{
byte[] Results;
System.Text.UTF8Encoding UTF8 = new System.Text.UTF8Encoding();
// Step 1. We hash the passphrase using MD5
// We use the MD5 hash generator as the result is a 128 bit byte array
// which is a valid length for the TripleDES encoder we use below
using(MD5CryptoServiceProvider HashProvider = new MD5CryptoServiceProvider())
{
byte[] TDESKey = HashProvider.ComputeHash(UTF8.GetBytes(Passphrase));
// Step 2. Create a new TripleDESCryptoServiceProvider object
using(TripleDESCryptoServiceProvider TDESAlgorithm = new TripleDESCryptoServiceProvider())
{
// Step 3. Setup the decoder
TDESAlgorithm.Key = TDESKey;
TDESAlgorithm.Mode = CipherMode.ECB;
TDESAlgorithm.Padding = PaddingMode.PKCS7;
// Step 4. Convert the input string to a byte[]
byte[] DataToDecrypt = Convert.FromBase64String(Message);
// Step 5. Attempt to decrypt the string
try
{
using(ICryptoTransform Decryptor = TDESAlgorithm.CreateDecryptor())
{
Results = Decryptor.TransformFinalBlock(DataToDecrypt, 0, DataToDecrypt.Length);
}
}
finally
{
// Clear the TripleDes and Hashprovider services of any sensitive information
TDESAlgorithm.Clear();
HashProvider.Clear();
}
}
}
// Step 6. Return the decrypted string in UTF8 format
return UTF8.GetString(Results, 0, Results.Length);
}
public static string EncryptString(string Message)
{
return EncryptString(Message, manifesto);
}
public static string ThisIsLegalString(string Message)
{
return DecryptString(Message, manifesto);
}
static readonly string manifesto = "GMap.NET is great and Powerful, Free, cross platform, open source .NET control.";
#endregion
#region RoutingProvider Members
public MapRoute GetRoute(PointLatLng start, PointLatLng end, bool avoidHighways, bool walkingMode, int Zoom)
{
string tooltip;
int numLevels;
int zoomFactor;
MapRoute ret = null;
List points = GetRoutePoints(MakeRouteUrl(start, end, LanguageStr, avoidHighways, walkingMode), Zoom, out tooltip, out numLevels, out zoomFactor);
if(points != null)
{
ret = new MapRoute(points, tooltip);
}
return ret;
}
public MapRoute GetRoute(string start, string end, bool avoidHighways, bool walkingMode, int Zoom)
{
string tooltip;
int numLevels;
int zoomFactor;
MapRoute ret = null;
List points = GetRoutePoints(MakeRouteUrl(start, end, LanguageStr, avoidHighways, walkingMode), Zoom, out tooltip, out numLevels, out zoomFactor);
if(points != null)
{
ret = new MapRoute(points, tooltip);
}
return ret;
}
#region -- internals --
string MakeRouteUrl(PointLatLng start, PointLatLng end, string language, bool avoidHighways, bool walkingMode)
{
string opt = walkingMode ? WalkingStr : (avoidHighways ? RouteWithoutHighwaysStr : RouteStr);
return string.Format(CultureInfo.InvariantCulture, RouteUrlFormatPointLatLng, language, opt, start.Lat, start.Lng, end.Lat, end.Lng, Server);
}
string MakeRouteUrl(string start, string end, string language, bool avoidHighways, bool walkingMode)
{
string opt = walkingMode ? WalkingStr : (avoidHighways ? RouteWithoutHighwaysStr : RouteStr);
return string.Format(RouteUrlFormatStr, language, opt, start.Replace(' ', '+'), end.Replace(' ', '+'), Server);
}
List GetRoutePoints(string url, int zoom, out string tooltipHtml, out int numLevel, out int zoomFactor)
{
List points = null;
tooltipHtml = string.Empty;
numLevel = -1;
zoomFactor = -1;
try
{
string urlEnd = url.Substring(url.IndexOf("&hl="));
string route = GMaps.Instance.UseRouteCache ? Cache.Instance.GetContent(urlEnd, CacheType.RouteCache) : string.Empty;
if(string.IsNullOrEmpty(route))
{
route = GetContentUsingHttp(url);
if(!string.IsNullOrEmpty(route))
{
if(GMaps.Instance.UseRouteCache)
{
Cache.Instance.SaveContent(urlEnd, CacheType.RouteCache, route);
}
}
}
// parse values
if(!string.IsNullOrEmpty(route))
{
//{
//tooltipHtml:" (300\x26#160;km / 2 valandos 59 min.)",
//polylines:
//[{
// id:"route0",
// points:"cy~rIcvp`ClJ~v@jHpu@N|BB~A?tA_@`J@nAJrB|AhEf@h@~@^pANh@Mr@a@`@_@x@cBPk@ZiBHeDQ{C]wAc@mAqCeEoA_C{@_Cy@iDoEaW}AsJcJ}t@iWowB{C_Vyw@gvGyTyjBu@gHwDoZ{W_zBsX}~BiA_MmAyOcAwOs@yNy@eTk@mVUmTE}PJ_W`@cVd@cQ`@}KjA_V`AeOn@oItAkOdAaKfBaOhDiVbD}RpBuKtEkTtP}q@fr@ypCfCmK|CmNvEqVvCuQ`BgLnAmJ`CgTpA_N~@sLlBwYh@yLp@cSj@e]zFkzKHaVViSf@wZjFwqBt@{Wr@qS`AaUjAgStBkYrEwe@xIuw@`Gmj@rFok@~BkYtCy_@|KccBvBgZjC}[tD__@pDaYjB_MpBuLhGi[fC}KfFcSnEkObFgOrFkOzEoLt[ys@tJeUlIsSbKqXtFiPfKi]rG_W|CiNhDkPfDuQlDoShEuXrEy[nOgiAxF{`@|DoVzFk[fDwPlXupA~CoPfDuQxGcd@l@yEdH{r@xDam@`AiWz@mYtAq~@p@uqAfAqx@|@kZxA}^lBq\\|Be\\lAaO~Dm`@|Gsj@tS_~AhCyUrCeZrByWv@uLlUiyDpA}NdHkn@pGmb@LkAtAoIjDqR`I{`@`BcH|I_b@zJcd@lKig@\\_CbBaIlJ}g@lIoj@pAuJtFoh@~Eqs@hDmv@h@qOfF{jBn@gSxCio@dAuQn@gIVoBjAiOlCqWbCiT`PekAzKiu@~EgYfIya@fA{ExGwWnDkMdHiU|G}R`HgQhRsa@hW}g@jVsg@|a@cbAbJkUxKoYxLa_@`IiZzHu[`DoOXsBhBuJbCwNdBaL`EkYvAwM`CeVtEwj@nDqj@BkAnB{YpGgeAn@eJ`CmYvEid@tBkQpGkd@rE}UxB}JdJo_@nDcNfSan@nS}j@lCeIvDsMbC{J|CyNbAwFfCgPz@uGvBiSdD}`@rFon@nKaqAxDmc@xBuT|Fqc@nC_PrEcUtC_MpFcT`GqQxJmXfXwq@jQgh@hBeGhG_U|BaK|G}[nRikAzIam@tDsYfE}^v@_MbAwKn@oIr@yLrBub@jAoa@b@sRdDmjBx@aZdA}XnAqVpAgTlAqPn@oGvFye@dCeRzGwb@xT_}A`BcPrAoOvCad@jAmXv@eV`BieA~@a[fBg_@`CiZ~A_OhHqk@hHcn@tEwe@rDub@nBoW~@sN|BeZnAgMvDm\\hFs^hSigArFaY`Gc\\`C}OhD}YfByQdAaNbAkOtOu~Cn@wKz@uLfCeY|CkW~B}OhCmO|AcI~A_IvDoPpEyPdImWrDuKnL_YjI{Ptl@qfAle@u|@xI}PbImQvFwMbGgOxFkOpdAosCdD_KxGsU|E}RxFcXhCwNjDwTvBiPfBqOrAyMfBcTxAaVhAwVrCy_Al@iPt@_OtA}Q`AuJ`AgIzAkK`EoUtBsJhCaKxCaKdDaKhQeg@jGiRfGaSrFyR`HsWvL}f@xp@grC`Sq|@pEsVdAoGjF{XlkAgwHxHgj@|Jex@fg@qlEjQs{AdHwh@zDkVhEkVzI_e@v}AgzHpK_l@tE}YtEy[rC}TpFme@jg@cpEbF{d@~BoXfBqUbAyOx@yN|Ao]bAo[tIazC`@iLb@aJ~AkWbBgRdBgPjA{IdCePlAmHfBmJdCiL~CuM|DoNxhDezKdDkLvBoInFqVbCuMxBqNnAeJ~CwXdBoSb^crElFsl@`Dy[zDu^xBiRzc@aaE|Fsd@vCkShDmTpG}^lD}QzDoR|zAcdHvIob@dKoj@jDmSlKiq@xVacBhEqXnBqL|Ga^zJke@`y@ktD~Mop@tP}_AdOg`AtCiQxCyOlDkPfDoN`GiTfGkRjEwLvEsL|HkQtEkJdE{HrwAkaCrT{a@rpDiuHtE_KvLuV|{AwaDzAqCb@mAf{Ac`D~FqL~y@_fBlNmZbGaNtF}Mpn@s~AlYss@dFgK|DoGhBoCrDuE~AcBtGaGnByAnDwBnCwAfDwAnFaBjGkA~[{E`iEkn@pQaDvIwBnIiCl\\qLn}J{pDhMcGrFcDhGeEvoDehC|AsArCwChBaC`C_EzC_HbBcFd@uB`@qAn@gDdB}Kz@}Hn@iPjByx@jDcvAj@}RDsEn@yTv@a]VcPtEamFBcHT_LNkEdAiShDsi@`GudAbFgx@`@iKdP}yFhBgs@p@yRjCo_AJwCXeEb@uEz@_H|@yEnBqHrCiIpAmE`o@qhBxC_IjIuVdIcXh{AgmG`i@_{BfCuLrhAssGfFeXxbBklInCsN|_AoiGpGs_@pl@w}Czy@_kEvG{]h}@ieFbQehAdHye@lPagA|Eu\\tAmI|CwWjn@mwGj@eH|]azFl@kPjAqd@jJe|DlD}vAxAeh@@eBvVk}JzIkqDfE_aBfA{YbBk[zp@e}LhAaObCeUlAuIzAeJrb@q`CjCcOnAaIpBwOtBkTjDsg@~AiPvBwOlAcH|AkIlCkLlYudApDoN`BgHhBaJvAeIvAqJbAuHrBqQbAsLx@oL`MwrCXkFr@uJh@{FhBsOvXwoB|EqVdBmHxC}KtCcJtDgKjDoIxE}JdHcMdCuDdIoKlmB}|BjJuMfFgIlE{HlEyIdEeJ~FaOvCgInCuI`EmN`J}]rEsP`EuMzCoIxGwPpi@cnAhGgPzCiJvFmRrEwQbDyOtCoPbDwTxDq\\rAsK`BgLhB{KxBoLfCgLjDqKdBqEfEkJtSy^`EcJnDuJjAwDrCeK\\}AjCaNr@qEjAaJtNaqAdCqQ`BsItS}bAbQs{@|Kor@xBmKz}@}uDze@{zAjk@}fBjTsq@r@uCd@aDFyCIwCWcCY}Aq_@w|A{AwF_DyHgHwOgu@m_BSb@nFhL",
// levels:"B?@?????@?@???A???@?@????@??@????????@????@???A????@????@??@???@??@???A???@??@???A??@???@????A??@???@??@????@??@???@????@???@??A@?@???@????A????@??@?@???@???????@??@?@????@????@?A??@???@????@??@?A??????@???????@??A???@??@???@??@????@??@?@?????@?@?A?@????@???@??@??@????@?@??@?@??@??????@???@?@????@???B???@??@??????@??@???A?????@????@???A??@??????@??@??A?@???@???@??A????@???@???@????A????@@??A???@???@??@??A????@??????@??@???@???B????@?@????????@????@????A?????@????@??A???@???@???B???@?????@???@????@????@???A???????@??A@??@?@??@@?????A?@@????????@??@?A????@?????@???@???@???@???@?@?A???@??@?@??@???@?????@???A??@???????@????@???@????@????@@???A????@?@??@?B",
// numLevels:4,
// zoomFactor:16
//}]
//}
#region -- title --
int tooltipEnd = 0;
{
int x = route.IndexOf("tooltipHtml:") + 13;
if(x >= 13)
{
tooltipEnd = route.IndexOf("\"", x + 1);
if(tooltipEnd > 0)
{
int l = tooltipEnd - x;
if(l > 0)
{
tooltipHtml = route.Substring(x, l).Replace(@"\x26#160;", " ");
}
}
}
}
#endregion
#region -- points --
int pointsEnd = 0;
{
int x = route.IndexOf("points:", tooltipEnd >= 0 ? tooltipEnd : 0) + 8;
if(x >= 8)
{
pointsEnd = route.IndexOf("\"", x + 1);
if(pointsEnd > 0)
{
int l = pointsEnd - x;
if(l > 0)
{
/*
while(l % 5 != 0)
{
l--;
}
*/
points = new List();
DecodePointsInto(points, route.Substring(x, l));
}
}
}
}
#endregion
#region -- levels --
string levels = string.Empty;
int levelsEnd = 0;
{
int x = route.IndexOf("levels:", pointsEnd >= 0 ? pointsEnd : 0) + 8;
if(x >= 8)
{
levelsEnd = route.IndexOf("\"", x + 1);
if(levelsEnd > 0)
{
int l = levelsEnd - x;
if(l > 0)
{
levels = route.Substring(x, l);
}
}
}
}
#endregion
#region -- numLevel --
int numLevelsEnd = 0;
{
int x = route.IndexOf("numLevels:", levelsEnd >= 0 ? levelsEnd : 0) + 10;
if(x >= 10)
{
numLevelsEnd = route.IndexOf(",", x);
if(numLevelsEnd > 0)
{
int l = numLevelsEnd - x;
if(l > 0)
{
numLevel = int.Parse(route.Substring(x, l));
}
}
}
}
#endregion
#region -- zoomFactor --
{
int x = route.IndexOf("zoomFactor:", numLevelsEnd >= 0 ? numLevelsEnd : 0) + 11;
if(x >= 11)
{
int end = route.IndexOf("}", x);
if(end > 0)
{
int l = end - x;
if(l > 0)
{
zoomFactor = int.Parse(route.Substring(x, l));
}
}
}
}
#endregion
#region -- trim point overload --
if(points != null && numLevel > 0 && !string.IsNullOrEmpty(levels))
{
if(points.Count - levels.Length > 0)
{
points.RemoveRange(levels.Length, points.Count - levels.Length);
}
//http://facstaff.unca.edu/mcmcclur/GoogleMaps/EncodePolyline/description.html
//
string allZlevels = "TSRPONMLKJIHGFEDCBA@?";
if(numLevel > allZlevels.Length)
{
numLevel = allZlevels.Length;
}
// used letters in levels string
string pLevels = allZlevels.Substring(allZlevels.Length - numLevel);
// remove useless points at zoom
{
List removedPoints = new List();
for(int i = 0; i < levels.Length; i++)
{
int zi = pLevels.IndexOf(levels[i]);
if(zi > 0)
{
if(zi * numLevel > zoom)
{
removedPoints.Add(points[i]);
}
}
}
foreach(var v in removedPoints)
{
points.Remove(v);
}
removedPoints.Clear();
removedPoints = null;
}
}
#endregion
}
}
catch(Exception ex)
{
points = null;
Debug.WriteLine("GetRoutePoints: " + ex);
}
return points;
}
static readonly string RouteUrlFormatPointLatLng = "http://maps.{6}/maps?f=q&output=dragdir&doflg=p&hl={0}{1}&q=&saddr=@{2},{3}&daddr=@{4},{5}";
static readonly string RouteUrlFormatStr = "http://maps.{4}/maps?f=q&output=dragdir&doflg=p&hl={0}{1}&q=&saddr=@{2}&daddr=@{3}";
static readonly string WalkingStr = "&mra=ls&dirflg=w";
static readonly string RouteWithoutHighwaysStr = "&mra=ls&dirflg=dh";
static readonly string RouteStr = "&mra=ls&dirflg=d";
#endregion
#endregion
#region GeocodingProvider Members
public GeoCoderStatusCode GetPoints(string keywords, out List pointList)
{
return GetLatLngFromGeocoderUrl(MakeGeocoderUrl(keywords, LanguageStr), out pointList);
}
public PointLatLng? GetPoint(string keywords, out GeoCoderStatusCode status)
{
List pointList;
status = GetPoints(keywords, out pointList);
return pointList != null && pointList.Count > 0 ? pointList[0] : (PointLatLng?)null;
}
public GeoCoderStatusCode GetPoints(Placemark placemark, out List pointList)
{
throw new NotImplementedException("use GetPoints(string keywords...");
}
public PointLatLng? GetPoint(Placemark placemark, out GeoCoderStatusCode status)
{
throw new NotImplementedException("use GetPoint(string keywords...");
}
public GeoCoderStatusCode GetPlacemarks(PointLatLng location, out List placemarkList)
{
return GetPlacemarkFromReverseGeocoderUrl(MakeReverseGeocoderUrl(location, LanguageStr), out placemarkList);
}
public Placemark? GetPlacemark(PointLatLng location, out GeoCoderStatusCode status)
{
List pointList;
status = GetPlacemarks(location, out pointList);
return pointList != null && pointList.Count > 0 ? pointList[0] : (Placemark?)null;
}
#region -- internals --
// TODO: switch to Geocoding API
// The Google Geocoding API: http://code.google.com/apis/maps/documentation/geocoding/
string MakeGeocoderUrl(string keywords, string language)
{
return string.Format(GeocoderUrlFormat, keywords.Replace(' ', '+'), language, APIKey, Server);
}
string MakeReverseGeocoderUrl(PointLatLng pt, string language)
{
return string.Format(CultureInfo.InvariantCulture, ReverseGeocoderUrlFormat, language, pt.Lat, pt.Lng, APIKey, Server);
}
GeoCoderStatusCode GetLatLngFromGeocoderUrl(string url, out List pointList)
{
var status = GeoCoderStatusCode.Unknow;
pointList = null;
try
{
string urlEnd = url.Substring(url.IndexOf("geo?q="));
string geo = GMaps.Instance.UseGeocoderCache ? Cache.Instance.GetContent(urlEnd, CacheType.GeocoderCache) : string.Empty;
bool cache = false;
if(string.IsNullOrEmpty(geo))
{
geo = GetContentUsingHttp(url);
if(!string.IsNullOrEmpty(geo))
{
cache = true;
}
}
if(!string.IsNullOrEmpty(geo))
{
if(geo.StartsWith("200"))
{
// true : 200,4,56.1451640,22.0681787
// false: 602,0,0,0
string[] values = geo.Split(',');
if(values.Length == 4)
{
status = (GeoCoderStatusCode)int.Parse(values[0]);
if(status == GeoCoderStatusCode.G_GEO_SUCCESS)
{
if(cache && GMaps.Instance.UseGeocoderCache)
{
Cache.Instance.SaveContent(urlEnd, CacheType.GeocoderCache, geo);
}
double lat = double.Parse(values[2], CultureInfo.InvariantCulture);
double lng = double.Parse(values[3], CultureInfo.InvariantCulture);
pointList = new List();
pointList.Add(new PointLatLng(lat, lng));
}
}
}
else if(geo.StartsWith("
//
//
// Lithuania, Vilnius
//
// 200
// geocode
//
//
// Vilnius, Lithuania
//
//
// LT
// Lithuania
//
// Vilnius Region
//
// Vilnius
//
//
//
//
//
//
//
// 25.2800243,54.6893865,0
//
//
//
#endregion
XmlDocument doc = new XmlDocument();
doc.LoadXml(geo);
XmlNamespaceManager nsMgr = new XmlNamespaceManager(doc.NameTable);
nsMgr.AddNamespace("sm", string.Format("http://earth.{0}/kml/2.0", Server));
nsMgr.AddNamespace("sn", "urn:oasis:names:tc:ciq:xsdschema:xAL:2.0");
XmlNode nn = doc.SelectSingleNode("//sm:Status/sm:code", nsMgr);
if(nn != null)
{
status = (GeoCoderStatusCode)int.Parse(nn.InnerText);
if(status == GeoCoderStatusCode.G_GEO_SUCCESS)
{
if(cache && GMaps.Instance.UseGeocoderCache)
{
Cache.Instance.SaveContent(urlEnd, CacheType.GeocoderCache, geo);
}
pointList = new List();
XmlNodeList l = doc.SelectNodes("/sm:kml/sm:Response/sm:Placemark", nsMgr);
if(l != null)
{
foreach(XmlNode n in l)
{
nn = n.SelectSingleNode("sm:Point/sm:coordinates", nsMgr);
if(nn != null)
{
string[] values = nn.InnerText.Split(',');
if(values.Length >= 2)
{
double lat = double.Parse(values[1], CultureInfo.InvariantCulture);
double lng = double.Parse(values[0], CultureInfo.InvariantCulture);
pointList.Add(new PointLatLng(lat, lng));
}
}
}
}
}
}
}
}
}
catch(Exception ex)
{
status = GeoCoderStatusCode.ExceptionInCode;
Debug.WriteLine("GetLatLngFromGeocoderUrl: " + ex);
}
return status;
}
GeoCoderStatusCode GetPlacemarkFromReverseGeocoderUrl(string url, out List placemarkList)
{
GeoCoderStatusCode status = GeoCoderStatusCode.Unknow;
placemarkList = null;
try
{
string urlEnd = url.Substring(url.IndexOf("geo?hl="));
string reverse = GMaps.Instance.UsePlacemarkCache ? Cache.Instance.GetContent(urlEnd, CacheType.PlacemarkCache) : string.Empty;
bool cache = false;
if(string.IsNullOrEmpty(reverse))
{
reverse = GetContentUsingHttp(url);
if(!string.IsNullOrEmpty(reverse))
{
cache = true;
}
}
if(!string.IsNullOrEmpty(reverse))
{
if(reverse.StartsWith("200"))
{
if(cache && GMaps.Instance.UsePlacemarkCache)
{
Cache.Instance.SaveContent(urlEnd, CacheType.PlacemarkCache, reverse);
}
string acc = reverse.Substring(0, reverse.IndexOf('\"'));
var ret = new Placemark(reverse.Substring(reverse.IndexOf('\"')));
ret.Accuracy = int.Parse(acc.Split(',').GetValue(1) as string);
placemarkList = new List();
placemarkList.Add(ret);
status = GeoCoderStatusCode.G_GEO_SUCCESS;
}
else if(reverse.StartsWith("
//
//
// 55.023322,24.668408
//
// 200
// geocode
//
//
// 4313, Širvintos 19023, Lithuania
// LTLithuaniaVilnius RegionŠirvintos431319023
//
//
//
// 24.6642677,55.0239187,0
//
//
// Širvintos 19023, Lithuania
// LTLithuaniaVilnius RegionŠirvintos19023
//
//
//
// 24.6778290,55.0561428,0
//
//
// Širvintos, Lithuania
// LTLithuaniaVilnius RegionŠirvintos
//
//
//
// 24.9447696,55.0482439,0
//
//
// Vilnius Region, Lithuania
// LTLithuaniaVilnius Region
//
//
//
// 25.2182138,54.8086502,0
//
//
// Lithuania
// LTLithuania
//
//
//
// 23.8812750,55.1694380,0
//
//
//
#endregion
XmlDocument doc = new XmlDocument();
doc.LoadXml(reverse);
XmlNamespaceManager nsMgr = new XmlNamespaceManager(doc.NameTable);
nsMgr.AddNamespace("sm", string.Format("http://earth.{0}/kml/2.0", Server));
nsMgr.AddNamespace("sn", "urn:oasis:names:tc:ciq:xsdschema:xAL:2.0");
var codeNode = doc.SelectSingleNode("//sm:Status/sm:code", nsMgr);
if(codeNode != null)
{
status = (GeoCoderStatusCode)int.Parse(codeNode.InnerText);
if(status == GeoCoderStatusCode.G_GEO_SUCCESS)
{
if(cache && GMaps.Instance.UsePlacemarkCache)
{
Cache.Instance.SaveContent(urlEnd, CacheType.PlacemarkCache, reverse);
}
placemarkList = new List();
#region -- placemarks --
XmlNodeList l = doc.SelectNodes("/sm:kml/sm:Response/sm:Placemark", nsMgr);
if(l != null)
{
foreach(XmlNode n in l)
{
XmlNode nnd, nnl, nn;
{
nn = n.SelectSingleNode("sm:address", nsMgr);
if(nn != null)
{
var ret = new Placemark(nn.InnerText);
nnd = n.SelectSingleNode("sn:AddressDetails", nsMgr);
if(nnd != null)
{
nn = nnd.SelectSingleNode("@Accuracy", nsMgr);
if(nn != null)
{
ret.Accuracy = int.Parse(nn.InnerText);
}
nn = nnd.SelectSingleNode("sn:Country/sn:CountryNameCode", nsMgr);
if(nn != null)
{
ret.CountryNameCode = nn.InnerText;
}
nn = nnd.SelectSingleNode("sn:Country/sn:CountryName", nsMgr);
if(nn != null)
{
ret.CountryName = nn.InnerText;
}
nn = nnd.SelectSingleNode("descendant::sn:AdministrativeArea/sn:AdministrativeAreaName", nsMgr);
if(nn != null)
{
ret.AdministrativeAreaName = nn.InnerText;
}
nn = nnd.SelectSingleNode("descendant::sn:SubAdministrativeArea/sn:SubAdministrativeAreaName", nsMgr);
if(nn != null)
{
ret.SubAdministrativeAreaName = nn.InnerText;
}
// Locality or DependentLocality tag ?
nnl = nnd.SelectSingleNode("descendant::sn:Locality", nsMgr) ?? nnd.SelectSingleNode("descendant::sn:DependentLocality", nsMgr);
if(nnl != null)
{
nn = nnl.SelectSingleNode(string.Format("sn:{0}Name", nnl.Name), nsMgr);
if(nn != null)
{
ret.LocalityName = nn.InnerText;
}
nn = nnl.SelectSingleNode("sn:Thoroughfare/sn:ThoroughfareName", nsMgr);
if(nn != null)
{
ret.ThoroughfareName = nn.InnerText;
}
nn = nnl.SelectSingleNode("sn:PostalCode/sn:PostalCodeNumber", nsMgr);
if(nn != null)
{
ret.PostalCodeNumber = nn.InnerText;
}
}
}
placemarkList.Add(ret);
}
}
}
}
#endregion
}
}
#endregion
}
}
}
catch(Exception ex)
{
status = GeoCoderStatusCode.ExceptionInCode;
placemarkList = null;
Debug.WriteLine("GetPlacemarkReverseGeocoderUrl: " + ex.ToString());
}
return status;
}
static readonly string ReverseGeocoderUrlFormat = "http://maps.{4}/maps/geo?hl={0}&ll={1},{2}&output=xml&key={3}";
static readonly string GeocoderUrlFormat = "http://maps.{3}/maps/geo?q={0}&hl={1}&output=kml&key={2}";
#endregion
#endregion
#region DirectionsProvider Members
public DirectionsStatusCode GetDirections(out GDirections direction, PointLatLng start, PointLatLng end, bool avoidHighways, bool avoidTolls, bool walkingMode, bool sensor, bool metric)
{
return GetDirectionsUrl(MakeDirectionsUrl(start, end, LanguageStr, avoidHighways, avoidTolls, walkingMode, sensor, metric), out direction);
}
public DirectionsStatusCode GetDirections(out GDirections direction, string start, string end, bool avoidHighways, bool avoidTolls, bool walkingMode, bool sensor, bool metric)
{
return GetDirectionsUrl(MakeDirectionsUrl(start, end, LanguageStr, avoidHighways, avoidTolls, walkingMode, sensor, metric), out direction);
}
///
/// NotImplemented
///
///
///
///
///
///
///
///
///
///
public IEnumerable GetDirections(out DirectionsStatusCode status, string start, string end, bool avoidHighways, bool avoidTolls, bool walkingMode, bool sensor, bool metric)
{
// TODO: add alternative directions
throw new NotImplementedException();
}
///
/// NotImplemented
///
///
///
///
///
///
///
///
///
///
public IEnumerable GetDirections(out DirectionsStatusCode status, PointLatLng start, PointLatLng end, bool avoidHighways, bool avoidTolls, bool walkingMode, bool sensor, bool metric)
{
// TODO: add alternative directions
throw new NotImplementedException();
}
public DirectionsStatusCode GetDirections(out GDirections direction, PointLatLng start, IEnumerable wayPoints, bool avoidHighways, bool avoidTolls, bool walkingMode, bool sensor, bool metric)
{
return GetDirectionsUrl(MakeDirectionsUrl(start, wayPoints, LanguageStr, avoidHighways, avoidTolls, walkingMode, sensor, metric), out direction);
}
public DirectionsStatusCode GetDirections(out GDirections direction, string start, IEnumerable wayPoints, bool avoidHighways, bool avoidTolls, bool walkingMode, bool sensor, bool metric)
{
return GetDirectionsUrl(MakeDirectionsUrl(start, wayPoints, LanguageStr, avoidHighways, avoidTolls, walkingMode, sensor, metric), out direction);
}
#region -- internals --
// The Google Directions API: http://code.google.com/apis/maps/documentation/directions/
string MakeDirectionsUrl(PointLatLng start, PointLatLng end, string language, bool avoidHighways, bool avoidTolls, bool walkingMode, bool sensor, bool metric)
{
string av = (avoidHighways ? "&avoid=highways" : string.Empty) + (avoidTolls ? "&avoid=tolls" : string.Empty); // 6
string mt = "&units=" + (metric ? "metric" : "imperial"); // 7
string wk = "&mode=" + (walkingMode ? "walking" : "driving"); // 8
return string.Format(CultureInfo.InvariantCulture, DirectionUrlFormatPoint, start.Lat, start.Lng, end.Lat, end.Lng, sensor.ToString().ToLower(), language, av, mt, wk);
}
string MakeDirectionsUrl(string start, string end, string language, bool avoidHighways, bool walkingMode, bool avoidTolls, bool sensor, bool metric)
{
string av = (avoidHighways ? "&avoid=highways" : string.Empty) + (avoidTolls ? "&avoid=tolls" : string.Empty); // 4
string mt = "&units=" + (metric ? "metric" : "imperial"); // 5
string wk = "&mode=" + (walkingMode ? "walking" : "driving"); // 6
return string.Format(DirectionUrlFormatStr, start.Replace(' ', '+'), end.Replace(' ', '+'), sensor.ToString().ToLower(), language, av, mt, wk);
}
string MakeDirectionsUrl(PointLatLng start, IEnumerable wayPoints, string language, bool avoidHighways, bool avoidTolls, bool walkingMode, bool sensor, bool metric)
{
string av = (avoidHighways ? "&avoid=highways" : string.Empty) + (avoidTolls ? "&avoid=tolls" : string.Empty); // 6
string mt = "&units=" + (metric ? "metric" : "imperial"); // 7
string wk = "&mode=" + (walkingMode ? "walking" : "driving"); // 8
string wpLatLng = string.Empty;
int i = 0;
foreach(var wp in wayPoints)
{
wpLatLng += string.Format(CultureInfo.InvariantCulture, i++ == 0 ? "{0},{1}" : "|{0},{1}", wp.Lat, wp.Lng);
}
return string.Format(CultureInfo.InvariantCulture, DirectionUrlFormatWaypoint, start.Lat, start.Lng, wpLatLng, sensor.ToString().ToLower(), language, av, mt, wk);
}
string MakeDirectionsUrl(string start, IEnumerable wayPoints, string language, bool avoidHighways, bool avoidTolls, bool walkingMode, bool sensor, bool metric)
{
string av = (avoidHighways ? "&avoid=highways" : string.Empty) + (avoidTolls ? "&avoid=tolls" : string.Empty); // 6
string mt = "&units=" + (metric ? "metric" : "imperial"); // 7
string wk = "&mode=" + (walkingMode ? "walking" : "driving"); // 8
string wpLatLng = string.Empty;
int i = 0;
foreach(var wp in wayPoints)
{
wpLatLng += string.Format(CultureInfo.InvariantCulture, i++ == 0 ? "{0}" : "|{0}", wp.Replace(' ', '+'));
}
return string.Format(CultureInfo.InvariantCulture, DirectionUrlFormatWaypointStr, start.Replace(' ', '+'), wpLatLng, sensor.ToString().ToLower(), language, av, mt, wk);
}
DirectionsStatusCode GetDirectionsUrl(string url, out GDirections direction)
{
DirectionsStatusCode ret = DirectionsStatusCode.UNKNOWN_ERROR;
direction = null;
try
{
string urlEnd = url.Substring(url.IndexOf("xml?"));
string kml = GMaps.Instance.UseDirectionsCache ? Cache.Instance.GetContent(urlEnd, CacheType.DirectionsCache) : string.Empty;
bool cache = false;
if(string.IsNullOrEmpty(kml))
{
kml = GetContentUsingHttp(url);
if(!string.IsNullOrEmpty(kml))
{
cache = true;
}
}
if(!string.IsNullOrEmpty(kml))
{
#region -- kml response --
//
//
// OK
//
// A1/E85
//
//
// DRIVING
//
// 54.6893800
// 25.2800500
//
//
// 54.6907800
// 25.2798000
//
//
// soxlIiohyCYLkCJ}@Vs@?
//
//
// 32
// 1 min
//
// Head <b>north</b> on <b>Vilniaus gatvė</b> toward <b>Tilto gatvė</b>
//
// 157
// 0.2 km
//
//
//
// DRIVING
//
// 54.6907800
// 25.2798000
//
//
// 54.6942500
// 25.2621300
//
//
// kxxlIwmhyCmApUF`@GvAYpD{@dGcCjIoIvOuAhDwAtEa@vBUnDAhB?~AThDRxAh@hBtAdC
//
//
// 133
// 2 mins
//
// Turn <b>left</b> onto <b>A. Goštauto gatvė</b>
//
// 1326
// 1.3 km
//
//
//
// DRIVING
//
// 54.6942500
// 25.2621300
//
//
// 54.6681200
// 25.2377500
//
//
// anylIi_eyC`AwD~@oBLKr@K`U|FdF|@`J^~E[j@Lh@\hB~Bn@tBZhBLrC?zIJ~DzA~OVrELlG^lDdAtDh@hAfApA`EzCvAp@jUpIpAl@bBpAdBpBxA|BdLpV`BxClAbBhBlBbChBpBhAdAXjBHlE_@t@?|@Lt@X
//
//
// 277
// 5 mins
//
// Turn <b>left</b> to merge onto <b>Geležinio Vilko gatvė</b>
//
// 3806
// 3.8 km
//
//
//
// DRIVING
//
// 54.6681200
// 25.2377500
//
//
// 54.6584100
// 25.1411300
//
//
// wjtlI}f`yC~FhBlFr@jD|A~EbC~VjNxBbBdA`BnvA|zCba@l`Bt@tDTbBJpBBfBMvDaAzF}bBjiF{HnXiHxZ
//
//
// 539
// 9 mins
//
// Continue onto <b>Savanorių prospektas</b>
//
// 8465
// 8.5 km
//
//
//
// DRIVING
//
// 54.6584100
// 25.1411300
//
//
// 54.9358200
// 23.9260000
//
//
// anrlIakmxCiq@|qCuBbLcK~n@wUrkAcPnw@gCnPoQt}AoB`MuAdHmAdFoCtJqClImBxE{DrIkQ|ZcEvIkDzIcDhKyBxJ{EdXuCtS_G`g@mF|\eF`WyDhOiE~NiErMaGpOoj@ppAoE|K_EzKeDtKkEnOsLnd@mDzLgI~U{FrNsEvJoEtI_FpI{J`O_EjFooBf_C{GdJ_FjIsH`OoFhMwH`UcDtL{CzMeDlQmAzHuU~bBiArIwApNaBfWaLfiCoBpYsDf\qChR_FlVqEpQ_ZbfA}CfN{A~HwCtRiAfKmBlVwBx[gBfRcBxMaLdp@sXrzAaE~UqCzRyC`[_q@z|LgC|e@m@vNqp@b}WuLraFo@jPaS~bDmJryAeo@v|G}CnWsm@~`EoKvo@kv@lkEkqBrlKwBvLkNj|@cu@`~EgCnNuiBpcJakAx|GyB`KqdC~fKoIfYicAxtCiDrLu@hDyBjQm@xKoGdxBmQhoGuUn|Dc@nJ[`OW|VaEn|Ee@`X
//
//
// 3506
// 58 mins
//
// Continue onto <b>A1/E85</b>
//
// 85824
// 85.8 km
//
//
//
// DRIVING
//
// 54.9358200
// 23.9260000
//
//
// 54.9376500
// 23.9195600
//
//
// {shnIo``qCQ^MnD[lBgA`DqBdEu@xB}@zJCjB
//
//
// 39
// 1 min
//
// Take the exit toward <b>Senamiestis/Aleksotas</b>
//
// 476
// 0.5 km
//
//
//
// DRIVING
//
// 54.9376500
// 23.9195600
//
//
// 54.9361300
// 23.9189700
//
//
// i_inIgx~pCnHtB
//
//
// 28
// 1 min
//
// Turn <b>left</b> onto <b>Kleboniškio gatvė</b>
//
// 173
// 0.2 km
//
//
//
// DRIVING
//
// 54.9361300
// 23.9189700
//
//
// 54.9018900
// 23.8937000
//
//
// yuhnIqt~pCvAb@JLrOvExSdHvDdAv`@pIpHnAdl@hLdB`@nDvAtEjDdCvCjLzOvAzBhC`GpHfRbQd^`JpMPt@ClA
//
//
// 412
// 7 mins
//
// Continue onto <b>Jonavos gatvė</b>
//
// 4302
// 4.3 km
//
//
//
// DRIVING
//
// 54.9018900
// 23.8937000
//
//
// 54.8985600
// 23.8933400
//
//
// y_bnIsvypCMf@FnARlAf@zAl@^v@EZ_@pAe@x@k@xBPpA@pAQNSf@oB
//
//
// 69
// 1 min
//
// At the roundabout, take the <b>3rd</b> exit and stay on <b>Jonavos gatvė</b>
//
// 478
// 0.5 km
//
//
//
// DRIVING
//
// 54.8985600
// 23.8933400
//
//
// 54.8968500
// 23.8930000
//
//
// _kanIktypCbEx@pCH
//
//
// 38
// 1 min
//
// Turn <b>right</b> onto <b>A. Mapu gatvė</b><div style="font-size:0.9em">Destination will be on the right</div>
//
// 192
// 0.2 km
//
//
//
// 5073
// 1 hour 25 mins
//
//
// 105199
// 105 km
//
//
// 54.6893800
// 25.2800500
//
//
// 54.8968500
// 23.8930000
//
// Vilnius, Lithuania
// Kaunas, Lithuania
//
// Map data ©2011 Tele Atlas
//
// soxlIiohyCYL}Fb@mApUF`@GvAYpD{@dGcCjIoIvOwBpFy@xC]jBSxCC~E^~Er@lCtAdC`AwD~@oB`AW`U|FdF|@`J^~E[tAj@hB~BjA~ELrCJzOzA~Od@`N^lDdAtDt@xAjAnApDlCbXbKpAl@bBpAdBpBxA|BdLpV`BxCvDpEbChBpBhAdAXjBHbG_@|@LtHbClFr@jK`F~VjNxBbB`@h@rwAt|Cba@l`BjAxGNxEMvDaAzF}bBjiFcFbQ_y@|gD{CxMeBnJcK~n@wh@dkCkAlIoQt}AeEfV}EzQqClImBxE{DrIkQ|ZcEvIkDzIcDhKyBxJ{EdXuCtS_G`g@mF|\eF`WyDhOiE~NiErMaGpOoj@ppAoE|K_EzKeDtKmXzbAgI~U{FrNsEvJoLfT{J`O_EjFooBf_C{GdJkLtSwI`SyClI}CrJcDtL{CzMeDlQcXzlBiArIwApNaBfWaLfiCoBpYsDf\qChR_FlVqEpQ_ZbfAyFfXwCtRiAfKeFfs@gBfRcBxMaLdp@sXrzAaE~UqCzRyC`[_q@z|LuDtu@qp@b}WuLraFo@jPo^r}Faq@pfHaBtMsm@~`EoKvo@kv@lkEcuBjzKkNj|@cu@`~EgCnNuiBpcJakAx|GyB`KqdC~fKoIfYidAbwCoD|MeAbHcA|Im@xK}YnhKyV~gEs@~f@aEn|Ee@`XQ^MnD[lBoF`N}@zJCjBfKxCJLdj@bQv`@pIpHnAdl@hLdB`@nDvAtEjDdCvCbOvSzLhZbQd^`JpMPt@QtBFnAz@hDl@^j@?f@e@pAe@x@k@xBPfCEf@Uj@wBbEx@pCH
//
//
//
// 54.6389500
// 23.8920900
//
//
// 54.9376500
// 25.2800500
//
//
//
//
#endregion
XmlDocument doc = new XmlDocument();
doc.LoadXml(kml);
XmlNode nn = doc.SelectSingleNode("/DirectionsResponse/status");
if(nn != null)
{
ret = (DirectionsStatusCode)Enum.Parse(typeof(DirectionsStatusCode), nn.InnerText, false);
if(ret == DirectionsStatusCode.OK)
{
if(cache && GMaps.Instance.UseDirectionsCache)
{
Cache.Instance.SaveContent(urlEnd, CacheType.DirectionsCache, kml);
}
direction = new GDirections();
nn = doc.SelectSingleNode("/DirectionsResponse/route/summary");
if(nn != null)
{
direction.Summary = nn.InnerText;
Debug.WriteLine("summary: " + direction.Summary);
}
nn = doc.SelectSingleNode("/DirectionsResponse/route/leg/duration");
if(nn != null)
{
var t = nn.SelectSingleNode("text");
if(t != null)
{
direction.Duration = t.InnerText;
Debug.WriteLine("duration: " + direction.Duration);
}
t = nn.SelectSingleNode("value");
if(t != null)
{
if(!string.IsNullOrEmpty(t.InnerText))
{
direction.DistanceValue = uint.Parse(t.InnerText);
Debug.WriteLine("value: " + direction.DistanceValue);
}
}
}
nn = doc.SelectSingleNode("/DirectionsResponse/route/leg/distance");
if(nn != null)
{
var t = nn.SelectSingleNode("text");
if(t != null)
{
direction.Distance = t.InnerText;
Debug.WriteLine("distance: " + direction.Distance);
}
t = nn.SelectSingleNode("value");
if(t != null)
{
if(!string.IsNullOrEmpty(t.InnerText))
{
direction.DurationValue = uint.Parse(t.InnerText);
Debug.WriteLine("value: " + direction.DurationValue);
}
}
}
nn = doc.SelectSingleNode("/DirectionsResponse/route/leg/start_location");
if(nn != null)
{
var pt = nn.SelectSingleNode("lat");
if(pt != null)
{
direction.StartLocation.Lat = double.Parse(pt.InnerText, CultureInfo.InvariantCulture);
}
pt = nn.SelectSingleNode("lng");
if(pt != null)
{
direction.StartLocation.Lng = double.Parse(pt.InnerText, CultureInfo.InvariantCulture);
}
}
nn = doc.SelectSingleNode("/DirectionsResponse/route/leg/end_location");
if(nn != null)
{
var pt = nn.SelectSingleNode("lat");
if(pt != null)
{
direction.EndLocation.Lat = double.Parse(pt.InnerText, CultureInfo.InvariantCulture);
}
pt = nn.SelectSingleNode("lng");
if(pt != null)
{
direction.EndLocation.Lng = double.Parse(pt.InnerText, CultureInfo.InvariantCulture);
}
}
nn = doc.SelectSingleNode("/DirectionsResponse/route/leg/start_address");
if(nn != null)
{
direction.StartAddress = nn.InnerText;
Debug.WriteLine("start_address: " + direction.StartAddress);
}
nn = doc.SelectSingleNode("/DirectionsResponse/route/leg/end_address");
if(nn != null)
{
direction.EndAddress = nn.InnerText;
Debug.WriteLine("end_address: " + direction.EndAddress);
}
nn = doc.SelectSingleNode("/DirectionsResponse/route/copyrights");
if(nn != null)
{
direction.Copyrights = nn.InnerText;
Debug.WriteLine("copyrights: " + direction.Copyrights);
}
nn = doc.SelectSingleNode("/DirectionsResponse/route/overview_polyline/points");
if(nn != null)
{
direction.Route = new List();
DecodePointsInto(direction.Route, nn.InnerText);
}
XmlNodeList steps = doc.SelectNodes("/DirectionsResponse/route/leg/step");
if(steps != null)
{
if(steps.Count > 0)
{
direction.Steps = new List();
}
foreach(XmlNode s in steps)
{
GDirectionStep step = new GDirectionStep();
Debug.WriteLine("----------------------");
nn = s.SelectSingleNode("travel_mode");
if(nn != null)
{
step.TravelMode = nn.InnerText;
Debug.WriteLine("travel_mode: " + step.TravelMode);
}
nn = s.SelectSingleNode("start_location");
if(nn != null)
{
var pt = nn.SelectSingleNode("lat");
if(pt != null)
{
step.StartLocation.Lat = double.Parse(pt.InnerText, CultureInfo.InvariantCulture);
}
pt = nn.SelectSingleNode("lng");
if(pt != null)
{
step.StartLocation.Lng = double.Parse(pt.InnerText, CultureInfo.InvariantCulture);
}
}
nn = s.SelectSingleNode("end_location");
if(nn != null)
{
var pt = nn.SelectSingleNode("lat");
if(pt != null)
{
step.EndLocation.Lat = double.Parse(pt.InnerText, CultureInfo.InvariantCulture);
}
pt = nn.SelectSingleNode("lng");
if(pt != null)
{
step.EndLocation.Lng = double.Parse(pt.InnerText, CultureInfo.InvariantCulture);
}
}
nn = s.SelectSingleNode("duration");
if(nn != null)
{
nn = nn.SelectSingleNode("text");
if(nn != null)
{
step.Duration = nn.InnerText;
Debug.WriteLine("duration: " + step.Duration);
}
}
nn = s.SelectSingleNode("distance");
if(nn != null)
{
nn = nn.SelectSingleNode("text");
if(nn != null)
{
step.Distance = nn.InnerText;
Debug.WriteLine("distance: " + step.Distance);
}
}
nn = s.SelectSingleNode("html_instructions");
if(nn != null)
{
step.HtmlInstructions = nn.InnerText;
Debug.WriteLine("html_instructions: " + step.HtmlInstructions);
}
nn = s.SelectSingleNode("polyline");
if(nn != null)
{
nn = nn.SelectSingleNode("points");
if(nn != null)
{
step.Points = new List();
DecodePointsInto(step.Points, nn.InnerText);
}
}
direction.Steps.Add(step);
}
}
}
}
}
}
catch(Exception ex)
{
direction = null;
ret = DirectionsStatusCode.ExceptionInCode;
Debug.WriteLine("GetDirectionsUrl: " + ex);
}
return ret;
}
static void DecodePointsInto(List list, string encodedPoints)
{
// http://tinyurl.com/3ds3scr
// http://code.server.com/apis/maps/documentation/polylinealgorithm.html
//
string encoded = encodedPoints.Replace("\\\\", "\\");
{
int len = encoded.Length;
int index = 0;
double dlat = 0;
double dlng = 0;
while(index < len)
{
int b;
int shift = 0;
int result = 0;
do
{
b = encoded[index++] - 63;
result |= (b & 0x1f) << shift;
shift += 5;
} while(b >= 0x20 && index < len);
dlat += ((result & 1) == 1 ? ~(result >> 1) : (result >> 1));
shift = 0;
result = 0;
if(index < len)
{
do
{
b = encoded[index++] - 63;
result |= (b & 0x1f) << shift;
shift += 5;
}
while(b >= 0x20 && index < len);
dlng += ((result & 1) == 1 ? ~(result >> 1) : (result >> 1));
list.Add(new PointLatLng(dlat * 1e-5, dlng * 1e-5));
}
}
}
}
static readonly string DirectionUrlFormatStr = "http://maps.googleapis.com/maps/api/directions/xml?origin={0}&destination={1}&sensor={2}&language={3}{4}{5}{6}";
static readonly string DirectionUrlFormatPoint = "http://maps.googleapis.com/maps/api/directions/xml?origin={0},{1}&destination={2},{3}&sensor={4}&language={5}{6}{7}{8}";
static readonly string DirectionUrlFormatWaypoint = "http://maps.googleapis.com/maps/api/directions/xml?origin={0},{1}&waypoints={2}&sensor={3}&language={4}{5}{6}{7}";
static readonly string DirectionUrlFormatWaypointStr = "http://maps.googleapis.com/maps/api/directions/xml?origin={0}&waypoints={1}&sensor={2}&language={3}{4}{5}{6}";
#endregion
#endregion
}
///
/// GoogleMap provider
///
public class GoogleMapProvider : GoogleMapProviderBase
{
public static readonly GoogleMapProvider Instance;
GoogleMapProvider()
{
}
static GoogleMapProvider()
{
Instance = new GoogleMapProvider();
}
public string Version = "m@182000000";
#region GMapProvider Members
readonly Guid id = new Guid("D7287DA0-A7FF-405F-8166-B6BAF26D066C");
public override Guid Id
{
get
{
return id;
}
}
readonly string name = "GoogleMap";
public override string Name
{
get
{
return name;
}
}
public override PureImage GetTileImage(GPoint pos, int zoom)
{
string url = MakeTileImageUrl(pos, zoom, LanguageStr);
return GetTileImageUsingHttp(url);
}
#endregion
string MakeTileImageUrl(GPoint pos, int zoom, string language)
{
string sec1 = string.Empty; // after &x=...
string sec2 = string.Empty; // after &zoom=...
GetSecureWords(pos, out sec1, out sec2);
return string.Format(UrlFormat, UrlFormatServer, GetServerNum(pos, 4), UrlFormatRequest, Version, language, pos.X, sec1, pos.Y, zoom, sec2, Server);
}
static readonly string UrlFormatServer = "mt";
static readonly string UrlFormatRequest = "vt";
static readonly string UrlFormat = "http://{0}{1}.{10}/{2}/lyrs={3}&hl={4}&x={5}{6}&y={7}&z={8}&s={9}";
}
}