namespace GMap.NET.MapProviders { using System; using GMap.NET.Projections; using System.Globalization; using GMap.NET.Internals; using System.Collections.Generic; using System.Xml; using System.Diagnostics; public abstract class CloudMadeMapProviderBase : GMapProvider, RoutingProvider, DirectionsProvider { public readonly string ServerLetters = "abc"; public readonly string DoubleResolutionString = "@2x"; public bool DoubleResolution = true; public string Key; public int StyleID; public string Version = "0.3"; public CloudMadeMapProviderBase() { MaxZoom = null; } #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 #region RoutingProvider Members public MapRoute GetRoute(PointLatLng start, PointLatLng end, bool avoidHighways, bool walkingMode, int Zoom) { List points = GetRoutePoints(MakeRoutingUrl(start, end, walkingMode ? TravelTypeFoot : TravelTypeMotorCar, LanguageStr, "km")); MapRoute route = points != null ? new MapRoute(points, walkingMode ? WalkingStr : DrivingStr) : null; return route; } /// /// NotImplemented /// /// /// /// /// /// /// public MapRoute GetRoute(string start, string end, bool avoidHighways, bool walkingMode, int Zoom) { throw new NotImplementedException(); } #region -- internals -- string MakeRoutingUrl(PointLatLng start, PointLatLng end, string travelType, string language, string units) { // http://developers.cloudmade.com/projects/routing-http-api/examples/ // http://routes.cloudmade.com/YOUR-API-KEY-GOES-HERE/api/0.3/start_point,[[transit_point1,...,transit_pointN]],end_point/route_type[/route_type_modifier].output_format[?lang=(en|de)][&units=(km|miles)] return string.Format(CultureInfo.InvariantCulture, UrlFormat, Key, Version, start.Lat, start.Lng, end.Lat, end.Lng, travelType, language, units); } List GetRoutePoints(string url) { List points = null; try { string route = GMaps.Instance.UseRouteCache ? Cache.Instance.GetContent(url, CacheType.RouteCache) : string.Empty; if(string.IsNullOrEmpty(route)) { route = GetContentUsingHttp(url); if(!string.IsNullOrEmpty(route)) { if(GMaps.Instance.UseRouteCache) { Cache.Instance.SaveContent(url, CacheType.RouteCache, route); } } } #region -- gpx response -- // // // // 293 // // Perckhoevelaan // Goudenregenlaan // // // // // // // // // // // // Head south on Perckhoevelaan, 0.1 km // // 111 // // 0 // 0.1 km // S // 160.6 // // // // Turn left at Laarstraat, 0.1 km // // 112 // // 3 // 0.1 km // NE // 58.1 // TL // 269.0 // // // // Turn right at Goudenregenlaan, 70 m // // 70 // // 5 // 70 m // SE // 143.4 // TR // 89.8 // // // // #endregion if(!string.IsNullOrEmpty(route)) { XmlDocument xmldoc = new XmlDocument(); xmldoc.LoadXml(route); System.Xml.XmlNamespaceManager xmlnsManager = new System.Xml.XmlNamespaceManager(xmldoc.NameTable); xmlnsManager.AddNamespace("sm", "http://www.topografix.com/GPX/1/1"); XmlNodeList wpts = xmldoc.SelectNodes("/sm:gpx/sm:wpt", xmlnsManager); if(wpts != null && wpts.Count > 0) { points = new List(); foreach(XmlNode w in wpts) { double lat = double.Parse(w.Attributes["lat"].InnerText, CultureInfo.InvariantCulture); double lng = double.Parse(w.Attributes["lon"].InnerText, CultureInfo.InvariantCulture); points.Add(new PointLatLng(lat, lng)); } } } } catch(Exception ex) { Debug.WriteLine("GetRoutePoints: " + ex); } return points; } static readonly string UrlFormat = "http://routes.cloudmade.com/{0}/api/{1}/{2},{3},{4},{5}/{6}.gpx?lang={7}&units={8}"; static readonly string TravelTypeFoot = "foot"; static readonly string TravelTypeMotorCar = "car"; static readonly string WalkingStr = "Walking"; static readonly string DrivingStr = "Driving"; #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(MakeRoutingUrl(start, end, walkingMode ? TravelTypeFoot : TravelTypeMotorCar, LanguageStr, metric ? "km" : "miles"), out direction); } /// /// NotImplemented /// /// /// /// /// /// /// /// /// /// public DirectionsStatusCode GetDirections(out GDirections direction, string start, string end, bool avoidHighways, bool avoidTolls, bool walkingMode, bool sensor, bool metric) { throw new NotImplementedException(); } /// /// NotImplemented /// /// /// /// /// /// /// /// /// /// public IEnumerable GetDirections(out DirectionsStatusCode status, string start, string end, bool avoidHighways, bool avoidTolls, bool walkingMode, bool sensor, bool metric) { throw new NotImplementedException(); } /// /// NotImplemented /// /// /// /// /// /// /// /// /// /// public IEnumerable GetDirections(out DirectionsStatusCode status, PointLatLng start, PointLatLng end, bool avoidHighways, bool avoidTolls, bool walkingMode, bool sensor, bool metric) { throw new NotImplementedException(); } #region -- internals -- DirectionsStatusCode GetDirectionsUrl(string url, out GDirections direction) { DirectionsStatusCode ret = DirectionsStatusCode.UNKNOWN_ERROR; direction = null; try { string route = GMaps.Instance.UseRouteCache ? Cache.Instance.GetContent(url, CacheType.DirectionsCache) : string.Empty; if(string.IsNullOrEmpty(route)) { route = GetContentUsingHttp(url); if(!string.IsNullOrEmpty(route)) { if(GMaps.Instance.UseRouteCache) { Cache.Instance.SaveContent(url, CacheType.DirectionsCache, route); } } } #region -- gpx response -- // // // // 293 // // Perckhoevelaan // Goudenregenlaan // // // // // // // // // // // // Head south on Perckhoevelaan, 0.1 km // // 111 // // 0 // 0.1 km // S // 160.6 // // // // Turn left at Laarstraat, 0.1 km // // 112 // // 3 // 0.1 km // NE // 58.1 // TL // 269.0 // // // // Turn right at Goudenregenlaan, 70 m // // 70 // // 5 // 70 m // SE // 143.4 // TR // 89.8 // // // // #endregion if(!string.IsNullOrEmpty(route)) { XmlDocument xmldoc = new XmlDocument(); xmldoc.LoadXml(route); System.Xml.XmlNamespaceManager xmlnsManager = new System.Xml.XmlNamespaceManager(xmldoc.NameTable); xmlnsManager.AddNamespace("sm", "http://www.topografix.com/GPX/1/1"); XmlNodeList wpts = xmldoc.SelectNodes("/sm:gpx/sm:wpt", xmlnsManager); if(wpts != null && wpts.Count > 0) { ret = DirectionsStatusCode.OK; direction = new GDirections(); direction.Route = new List(); foreach(XmlNode w in wpts) { double lat = double.Parse(w.Attributes["lat"].InnerText, CultureInfo.InvariantCulture); double lng = double.Parse(w.Attributes["lon"].InnerText, CultureInfo.InvariantCulture); direction.Route.Add(new PointLatLng(lat, lng)); } if(direction.Route.Count > 0) { direction.StartLocation = direction.Route[0]; direction.EndLocation = direction.Route[direction.Route.Count - 1]; } XmlNode n = xmldoc.SelectSingleNode("/sm:gpx/sm:metadata/sm:copyright/sm:license", xmlnsManager); if(n != null) { direction.Copyrights = n.InnerText; } n = xmldoc.SelectSingleNode("/sm:gpx/sm:extensions/sm:distance", xmlnsManager); if(n != null) { direction.Distance = n.InnerText + "m"; } n = xmldoc.SelectSingleNode("/sm:gpx/sm:extensions/sm:time", xmlnsManager); if(n != null) { direction.Duration = n.InnerText + "s"; } n = xmldoc.SelectSingleNode("/sm:gpx/sm:extensions/sm:start", xmlnsManager); if(n != null) { direction.StartAddress = n.InnerText; } n = xmldoc.SelectSingleNode("/sm:gpx/sm:extensions/sm:end", xmlnsManager); if(n != null) { direction.EndAddress = n.InnerText; } wpts = xmldoc.SelectNodes("/sm:gpx/sm:rte/sm:rtept", xmlnsManager); if(wpts != null && wpts.Count > 0) { direction.Steps = new List(); foreach(XmlNode w in wpts) { GDirectionStep step = new GDirectionStep(); double lat = double.Parse(w.Attributes["lat"].InnerText, CultureInfo.InvariantCulture); double lng = double.Parse(w.Attributes["lon"].InnerText, CultureInfo.InvariantCulture); step.StartLocation = new PointLatLng(lat, lng); XmlNode nn = w.SelectSingleNode("sm:desc", xmlnsManager); if(nn != null) { step.HtmlInstructions = nn.InnerText; } nn = w.SelectSingleNode("sm:extensions/sm:distance-text", xmlnsManager); if(nn != null) { step.Distance = nn.InnerText; } nn = w.SelectSingleNode("sm:extensions/sm:time", xmlnsManager); if(nn != null) { step.Duration = nn.InnerText + "s"; } direction.Steps.Add(step); } } } } } catch(Exception ex) { ret = DirectionsStatusCode.ExceptionInCode; direction = null; Debug.WriteLine("GetDirectionsUrl: " + ex); } return ret; } #endregion #endregion } /// /// CloudMadeMap demo provider, http://maps.cloudmade.com/ /// public class CloudMadeMapProvider : CloudMadeMapProviderBase { public static readonly CloudMadeMapProvider Instance; CloudMadeMapProvider() { Key = "5937c2bd907f4f4a92d8980a7c666ac0"; // demo key of CloudMade StyleID = 45363; // grab your style here http://maps.cloudmade.com/?styleId=45363 } static CloudMadeMapProvider() { Instance = new CloudMadeMapProvider(); } #region GMapProvider Members readonly Guid id = new Guid("00403A36-725F-4BC4-934F-BFC1C164D003"); public override Guid Id { get { return id; } } readonly string name = "CloudMade, Demo"; 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) { return string.Format(UrlFormat, ServerLetters[GetServerNum(pos, 3)], Key, StyleID, (DoubleResolution ? DoubleResolutionString : string.Empty), zoom, pos.X, pos.Y); } static readonly string UrlFormat = "http://{0}.tile.cloudmade.com/{1}/{2}{3}/256/{4}/{5}/{6}.png"; } }