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}"; } }