arcgis for silverlight 加载GoogleMap 或 BingMap 可以使用重载 TiledMapServiceLayer
对于silverlight内的地图进行截屏操作时,会出现跨域问题,目前我的解决方式就是,将加载切片
数据交给本地服务端,本地服务端加载后的图片再给silverlight,这样就不会出现跨域问题,而无法截屏了
GoogleMap:
/// <summary> /// Google Title System layer (Google 地图切片系统图层) /// </summary> public class GoogleMapTileLayer : TiledMapServiceLayer { /// <summary> /// 初始化 /// </summary> public override void Initialize() { //全图范围 this.FullExtent = new Envelope(-20037508.342787, -20037508.342787, 20037508.342787, 20037508.342787); { SpatialReference = new SpatialReference(102113); }; //空间投影 this.SpatialReference = new SpatialReference(102113); //切片信息 this.TileInfo = new TileInfo() { Height = 256, Width = 256, Origin = new MapPoint(-20037508.342787, 20037508.342787) { SpatialReference = new SpatialReference(102113) }, Lods = new Lod[20] }; double resolution = 156543.033928; for (int i = 0; i < TileInfo.Lods.Length; i++) { TileInfo.Lods[i] = new Lod() { Resolution = resolution }; resolution /= 2; } //加载 base.Initialize(); } /// <summary> /// Google 切片地址 /// </summary> private static string basicGoogleTitleUrl = "http://mt{0}.google.cn/vt/lyrs=m@156000000&hl=zh-CN&x="; /// <summary> /// 服务器随机数 /// </summary> private static Random RandomTitle = new Random(DateTime.Now.Second); /// <summary> /// 获取切片地址 /// </summary> /// <param name="level"></param> /// <param name="row"></param> /// <param name="col"></param> /// <returns></returns> public override string GetTileUrl(int level, int row, int col) { int Server = RandomTitle.Next(0, 4); string url = string.Format(basicGoogleTitleUrl, Server); url = url + col.ToString() + "&y=" + row.ToString() + "&z=" + level.ToString() + "&s="; return url; } }
BingMap:
/// <summary> /// BingMap Title System layer (Google 地图切片系统图层) /// </summary> public class BingMapTileLayer : TiledMapServiceLayer { /// <summary> /// 经纬度转墨卡托 /// </summary> /// <param name="lonLat"></param> /// <returns></returns> public MapPoint lonLat2Mercator(MapPoint lonLat) { MapPoint mercator = new MapPoint(); double x = lonLat.X * 20037508.34 / 180; double y = Math.Log(Math.Tan((90 + lonLat.Y) * Math.PI / 360)) / (Math.PI / 180); y = y * 20037508.34 / 180; mercator.X = x; mercator.Y = y; return mercator; } /// <summary> /// 初始化 /// </summary> public override void Initialize() { MapPoint minPoint = new MapPoint(TileSystem.MinLongitude, TileSystem.MinLatitude); minPoint = lonLat2Mercator(minPoint); minPoint.SpatialReference = new ESRI.ArcGIS.Client.Geometry.SpatialReference(102113); MapPoint maxPoint = new MapPoint(TileSystem.MaxLongitude, TileSystem.MaxLatitude); maxPoint = lonLat2Mercator(maxPoint); maxPoint.SpatialReference = new ESRI.ArcGIS.Client.Geometry.SpatialReference(102113); //全图范围 this.FullExtent = new Envelope(minPoint, maxPoint); { SpatialReference = new SpatialReference(102113); }; //空间投影 this.SpatialReference = new SpatialReference(102113); //切片信息 this.TileInfo = new TileInfo() { Height = 256, Width = 256, Origin = new MapPoint(-20037508.342787, 20037508.342787) { SpatialReference = new SpatialReference(102113) }, Lods = new Lod[23] }; double resolution = 39135.7585 * 4; for (int i = 0; i < TileInfo.Lods.Length; i++) { TileInfo.Lods[i] = new Lod() { Resolution = resolution }; resolution /= 2; } //加载 base.Initialize(); } /// <summary> /// BingMap 切片地址(由本地页面加载切片,可以使用silverlight的截屏功能,而不会出现权限错误) /// </summary> private static string basicbingTitleUrl = "http://localhost:18839/BingMapUrl.aspx?r{1}.png?g=94&mkt=zh-cn&b={0}"; /// <summary> /// 服务器随机数 /// </summary> private static Random RandomTitle = new Random(DateTime.Now.Second); /// <summary> /// 获取切片地址 /// </summary> /// <param name="level"></param> /// <param name="row"></param> /// <param name="col"></param> /// <returns></returns> public override string GetTileUrl(int level, int row, int col) { return GetUri(level, col, row); } public string GetUri(int tileLevel, int tilePositionX, int tilePositionY) { var quadKey = TileSystem.TileXYToQuadKey(tilePositionX, tilePositionY, tileLevel); if (string.IsNullOrEmpty(quadKey)) quadKey = "0"; return string.Format(basicbingTitleUrl, RandomTitle.Next(0, 3), quadKey); } }
TileSystem:
/// <summary> /// 切片系统 /// </summary> static class TileSystem { public const double EarthRadius = 6378137; public const double MinLatitude = -85.05112878; public const double MaxLatitude = 85.05112878; public const double MinLongitude = -180; public const double MaxLongitude = 180; /// <summary> /// Clips a number to the specified minimum and maximum values. /// </summary> /// <param name="n">The number to clip.</param> /// <param name="minValue">Minimum allowable value.</param> /// <param name="maxValue">Maximum allowable value.</param> /// <returns>The clipped value.</returns> private static double Clip(double n, double minValue, double maxValue) { return Math.Min(Math.Max(n, minValue), maxValue); } /// <summary> /// Determines the map width and height (in pixels) at a specified level /// of detail. /// </summary> /// <param name="levelOfDetail">Level of detail, from 1 (lowest detail) /// to 23 (highest detail).</param> /// <returns>The map width and height in pixels.</returns> public static uint MapSize(int levelOfDetail) { return (uint)256 << levelOfDetail; } /// <summary> /// Determines the ground resolution (in meters per pixel) at a specified /// latitude and level of detail. /// </summary> /// <param name="latitude">Latitude (in degrees) at which to measure the ground resolution.</param> /// <param name="levelOfDetail">Level of detail, from 1 (lowest detail) to 23 (highest detail).</param> /// <returns>The ground resolution, in meters per pixel.</returns> public static double GroundResolution(double latitude, int levelOfDetail) { latitude = Clip(latitude, MinLatitude, MaxLatitude); return Math.Cos(latitude * Math.PI / 180) * 2 * Math.PI * EarthRadius / MapSize(levelOfDetail); } /// <summary> /// Determines the map scale at a specified latitude, level of detail, /// and screen resolution. /// </summary> /// <param name="latitude">Latitude (in degrees) at which to measure the /// map scale.</param> /// <param name="levelOfDetail">Level of detail, from 1 (lowest detail) /// to 23 (highest detail).</param> /// <param name="screenDpi">Resolution of the screen, in dots per inch.</param> /// <returns>The map scale, expressed as the denominator N of the ratio 1 : N.</returns> public static double MapScale(double latitude, int levelOfDetail, int screenDpi) { return GroundResolution(latitude, levelOfDetail) * screenDpi / 0.0254; } /// <summary> /// Converts a point from latitude/longitude WGS-84 coordinates (in degrees) /// into pixel XY coordinates at a specified level of detail. /// </summary> /// <param name="latitude">Latitude of the point, in degrees.</param> /// <param name="longitude">Longitude of the point, in degrees.</param> /// <param name="levelOfDetail">Level of detail, from 1 (lowest detail) /// to 23 (highest detail).</param> /// <param name="pixelX">Output parameter receiving the X coordinate in pixels.</param> /// <param name="pixelY">Output parameter receiving the Y coordinate in pixels.</param> public static void LatLongToPixelXY(double latitude, double longitude, int levelOfDetail, out int pixelX, out int pixelY) { latitude = Clip(latitude, MinLatitude, MaxLatitude); longitude = Clip(longitude, MinLongitude, MaxLongitude); double x = (longitude + 180) / 360; double sinLatitude = Math.Sin(latitude * Math.PI / 180); double y = 0.5 - Math.Log((1 + sinLatitude) / (1 - sinLatitude)) / (4 * Math.PI); uint mapSize = MapSize(levelOfDetail); pixelX = (int)Clip(x * mapSize + 0.5, 0, mapSize - 1); pixelY = (int)Clip(y * mapSize + 0.5, 0, mapSize - 1); } /// <summary> /// Converts a pixel from pixel XY coordinates at a specified level of detail /// into latitude/longitude WGS-84 coordinates (in degrees). /// </summary> /// <param name="pixelX">X coordinate of the point, in pixels.</param> /// <param name="pixelY">Y coordinates of the point, in pixels.</param> /// <param name="levelOfDetail">Level of detail, from 1 (lowest detail) /// to 23 (highest detail).</param> /// <param name="latitude">Output parameter receiving the latitude in degrees.</param> /// <param name="longitude">Output parameter receiving the longitude in degrees.</param> public static void PixelXYToLatLong(int pixelX, int pixelY, int levelOfDetail, out double latitude, out double longitude) { double mapSize = MapSize(levelOfDetail); double x = (Clip(pixelX, 0, mapSize - 1) / mapSize) - 0.5; double y = 0.5 - (Clip(pixelY, 0, mapSize - 1) / mapSize); latitude = 90 - 360 * Math.Atan(Math.Exp(-y * 2 * Math.PI)) / Math.PI; longitude = 360 * x; } /// <summary> /// Converts pixel XY coordinates into tile XY coordinates of the tile containing /// the specified pixel. /// </summary> /// <param name="pixelX">Pixel X coordinate.</param> /// <param name="pixelY">Pixel Y coordinate.</param> /// <param name="tileX">Output parameter receiving the tile X coordinate.</param> /// <param name="tileY">Output parameter receiving the tile Y coordinate.</param> public static void PixelXYToTileXY(int pixelX, int pixelY, out int tileX, out int tileY) { tileX = pixelX / 256; tileY = pixelY / 256; } /// <summary> /// Converts tile XY coordinates into pixel XY coordinates of the upper-left pixel /// of the specified tile. /// </summary> /// <param name="tileX">Tile X coordinate.</param> /// <param name="tileY">Tile Y coordinate.</param> /// <param name="pixelX">Output parameter receiving the pixel X coordinate.</param> /// <param name="pixelY">Output parameter receiving the pixel Y coordinate.</param> public static void TileXYToPixelXY(int tileX, int tileY, out int pixelX, out int pixelY) { pixelX = tileX * 256; pixelY = tileY * 256; } /// <summary> /// Converts tile XY coordinates into a QuadKey at a specified level of detail. /// </summary> /// <param name="tileX">Tile X coordinate.</param> /// <param name="tileY">Tile Y coordinate.</param> /// <param name="levelOfDetail">Level of detail, from 1 (lowest detail) /// to 23 (highest detail).</param> /// <returns>A string containing the QuadKey.</returns> public static string TileXYToQuadKey(int tileX, int tileY, int levelOfDetail) { StringBuilder quadKey = new StringBuilder(); for (int i = levelOfDetail; i > 0; i--) { char digit = '0'; int mask = 1 << (i - 1); if ((tileX & mask) != 0) { digit++; } if ((tileY & mask) != 0) { digit++; digit++; } quadKey.Append(digit); } return quadKey.ToString(); } /// <summary> /// Converts a QuadKey into tile XY coordinates. /// </summary> /// <param name="quadKey">QuadKey of the tile.</param> /// <param name="tileX">Output parameter receiving the tile X coordinate.</param> /// <param name="tileY">Output parameter receiving the tile Y coordinate.</param> /// <param name="levelOfDetail">Output parameter receiving the level of detail.</param> public static void QuadKeyToTileXY(string quadKey, out int tileX, out int tileY, out int levelOfDetail) { tileX = tileY = 0; levelOfDetail = quadKey.Length; for (int i = levelOfDetail; i > 0; i--) { int mask = 1 << (i - 1); switch (quadKey[levelOfDetail - i]) { case '0': break; case '1': tileX |= mask; break; case '2': tileY |= mask; break; case '3': tileX |= mask; tileY |= mask; break; default: throw new ArgumentException("Invalid QuadKey digit sequence."); } } } }
BingMapUrl.aspx.cs:
public partial class BingMapUrl : System.Web.UI.Page { public Random random = new Random(DateTime.Now.Second); private const string BingMapHostUrl = "http://r{0}.tiles.ditu.live.com/tiles/"; private const int BUFFERSIZE = 1048576; /// <summary> /// 页面加载 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> protected void Page_Load(object sender, EventArgs e) { if (!IsPostBack) { try { this.HandleMapPic(); } catch (Exception ex) { Response.Write(ex.Message); } } } /// <summary> /// 加载图片 /// </summary> private void HandleMapPic() { string queryParams = Request.Url.Query; if (string.IsNullOrWhiteSpace(queryParams)) return; queryParams = queryParams.Substring(1, queryParams.Length - 1); string bingMapUrl = string.Format(BingMapHostUrl, random.Next(0, 3)); string requestUrl = string.Concat(bingMapUrl, queryParams); HttpWebRequest webRequest = null; #region Prepare the request object webRequest = (HttpWebRequest)WebRequest.Create(Server.UrlDecode(requestUrl)); webRequest.Method = Request.HttpMethod; webRequest.ContentType = Request.ContentType; #endregion Prepare the request object #region Cycle through and return output HttpWebResponse webResponse = (HttpWebResponse)webRequest.GetResponse(); System.IO.Stream fileStream = webResponse.GetResponseStream(); Byte[] buffer = new byte[1048576]; int bytesRead = 1; while (bytesRead > 0) { bytesRead = fileStream.Read(buffer, 0, BUFFERSIZE); if (bytesRead == BUFFERSIZE) Response.BinaryWrite(buffer); else if (bytesRead > 0) { byte[] endBuffer = new byte[bytesRead]; Array.Copy(buffer, endBuffer, bytesRead); Response.BinaryWrite(endBuffer); } } fileStream.Dispose(); webResponse.Close(); #endregion Cycle through and return output } }