如何将WGS84经纬度转换为UWP MapControl的瓦片XY坐标
UWP MapControl自定义瓦片WGS84坐标转瓦片相对坐标方案
问题背景
我正在实现CustomMapTileDataSource功能,目前已可动态绘制带自定义图形的瓦片:
现在需要在UWP MapControl提供的每个瓦片上绘制线条,所有线条坐标均采用WGS84坐标系预计算且经过充分验证。通过以下代码获取当前瓦片对应的WGS84矩形范围,筛选需要绘制的线条:
private async void customDataSource_BitmapRequestedAsync(CustomMapTileDataSource sender, MapTileBitmapRequestedEventArgs args) { var deferral = args.Request.GetDeferral(); const int tileSide = 256; TileSystem.TileXYToPixelXY(args.X, args.Y, out int pixelX, out int pixelY); var rect = new List<BasicGeoposition>(); // 添加上左地理点 TileSystem.PixelXYToLatLong(pixelX, pixelY, args.ZoomLevel, out double latTopLeft, out double lngTopLeft); rect.Add(new BasicGeoposition() { Latitude = latTopLeft, Longitude = lngTopLeft }); // 添加上右地理点 TileSystem.PixelXYToLatLong(pixelX + tileSide, pixelY, args.ZoomLevel, out double latTopRight, out double lngTopRight); rect.Add(new BasicGeoposition() { Latitude = latTopRight, Longitude = lngTopRight }); // 添加下右地理点 TileSystem.PixelXYToLatLong(pixelX + tileSide, pixelY + tileSide, args.ZoomLevel, out double latBottomRight, out double lngBottomRight); rect.Add(new BasicGeoposition() { Latitude = latBottomRight, Longitude = lngBottomRight }); // 添加下左地理点 TileSystem.PixelXYToLatLong(pixelX, pixelY + tileSide, args.ZoomLevel, out double latBottomLeft, out double lngBottomLeft); rect.Add(new BasicGeoposition() { Latitude = latBottomLeft, Longitude = lngBottomLeft }); var filterdLines = GetLinesByGeoRect(rect); args.Request.PixelData = await CreateBitmapAsStreamAsync(filterdLines, args.ZoomLevel); deferral.Complete(); }
该事件适配单个瓦片的绘制需求,已通过ds.DrawCircle完成测试绘制,初始瓦片绘制逻辑代码如下:
private async Task<RandomAccessStreamReference> CreateBitmapAsStreamAsync(List<MyLine> lines, int zoom) { int pixelHeight = 256; int pixelWidth = 256; var randomAccessStream = new InMemoryRandomAccessStream(); var outputStream = randomAccessStream.GetOutputStreamAt(0); var softwareBitmap = new SoftwareBitmap(BitmapPixelFormat.Bgra8, pixelHeight, pixelWidth, BitmapAlphaMode.Premultiplied); var resourceCreator = CanvasDevice.GetSharedDevice(); var canvasBitmap = CanvasBitmap.CreateFromSoftwareBitmap(resourceCreator, softwareBitmap); var canvasRenderTarget = new CanvasRenderTarget(resourceCreator, softwareBitmap.PixelWidth, softwareBitmap.PixelHeight, 96); using (var ds = canvasRenderTarget.CreateDrawingSession()) { ds.Antialiasing = CanvasAntialiasing.Antialiased; foreach (var line in lines) { // 尝试将WGS84经纬度转换为当前瓦片的屏幕坐标 TileSystem.LatLongToPixelXY(line.latt, line.longt, zoom, out int startX, out int startY); TileSystem.LatLongToPixelXY(line.latt, line.longt, zoom, out int endX, out int endY); /* 50.016952, 8.772860 缩放等级1 X: 268 Y: 174 50.016952, 8.772860 缩放等级11 X: 274920 Y: 177771 */ ds.DrawLine(startX, startY, endX, endY, Colors.Black, 1); } // ds.DrawCircle(new Vector2(100, 100), 100, Colors.Blue); // 仅用于测试瓦片绘制 // ds.DrawRectangle(1, 1, 255, 255, Colors.Black, 2); // 仅用于测试瓦片绘制 } await canvasRenderTarget.SaveAsync(randomAccessStream, CanvasBitmapFileFormat.Png); await randomAccessStream.FlushAsync(); return RandomAccessStreamReference.CreateFromStream(randomAccessStream); }
遇到的问题
调用TileSystem.LatLongToPixelXY转换坐标时,相同经纬度在不同缩放等级下返回的全局像素坐标数值过大,比如坐标50.016952, 8.772860在缩放等级11下返回的Y坐标为177771,无法直接在256*256尺寸的瓦片上绘制,需要将WGS84经纬度转换为当前正在绘制的瓦片的相对坐标。
已验证解决方案
将瓦片左上角的全局像素坐标作为偏移量传入绘制方法,将转换得到的全局像素坐标减去该偏移量即可得到瓦片内的相对坐标。
实现步骤:
- 先获取当前瓦片左上角的全局像素坐标:
TileSystem.TileXYToPixelXY(args.X, args.Y, out int pixelX, out int pixelY);
- 将偏移量作为参数传入绘制方法,计算相对坐标后绘制:
private async Task<RandomAccessStreamReference> CreateBitmapAsStreamAsync(List<MyLine> lines, int zoom, int pixelX, int pixelY) { ds.Antialiasing = CanvasAntialiasing.Antialiased; foreach (var line in lines) { // 转换WGS84经纬度为全局像素坐标 TileSystem.LatLongToPixelXY(line.latt, line.longt, zoom, out int startX, out int startY); TileSystem.LatLongToPixelXY(line.latt, line.longt, zoom, out int endX, out int endY); // 计算瓦片内相对坐标 float rX0 = startX - pixelX; float rY0 = startY - pixelY; float rX1 = endX - pixelX; float rY1 = endY - pixelY; ds.DrawLine(rX0, rY0, rX1, rY1, Colors.Black, 1); } }
内容的提问来源于stack exchange,提问作者NoWar
相关产品推荐
相关产品推荐

