在处理地理信息系统(GIS)数据时,经常会遇到难以导航的问题,尤其是当没有明显的地标时。一个明显的解决方案是添加一个透明的地图作为叠加层,该叠加层与相同的坐标系相关联。Open Street Map(开放街道地图)数据可以免费获取,以渲染瓦片的形式提供多种分辨率,几乎覆盖了整个地球。MapWinGIS支持将图像文件叠加到地图上,只要它们是地理参考的,就可以相对简单地添加一个动态地图叠加层,该叠加层会随着MapWinGIS窗口的缩放而缩放,以保持在所有分辨率下的OpenStreetMap叠加层。
关于Open Street Map瓦片(滑动地图)的详细信息可以在找到。关于用于地理参考图像文件的世界文件的详细信息可以在找到。
下面两个函数,来自滑动瓦片维基,用于在滑动地图瓦片引用和WGS-84纬度和经度之间进行转换。这些用于计算覆盖地图区域所需的瓦片,然后为每个瓦片进行地理参考,再将其添加到地图中。
Private Function CalcTileXY(ByVal LatDeg As Single, ByVal LonDeg As Single, ByVal ZoomLevel As Long) As PointF
CalcTileXY.X = CLng(Math.Floor((LonDeg + 180) / 360 * 2 ^ ZoomLevel))
CalcTileXY.Y = CLng(Math.Floor((1 - Math.Log(Math.Tan(LatDeg * Math.PI / 180) + 1 / Math.Cos(LatDeg * Math.PI / 180)) / Math.PI) / 2 * 2 ^ ZoomLevel))
End Function
Private Function CalcTileTLCoord(ByVal TileCoord As PointF, ByVal ZoomLevel As Long) As PointF
Dim n As Double = Math.PI - ((2.0 * Math.PI * TileCoord.Y) / Math.Pow(2.0, ZoomLevel))
CalcTileTLCoord.X = (TileCoord.X / Math.Pow(2.0, ZoomLevel) * 360) - 180
CalcTileTLCoord.Y = 180 / Math.PI * Math.Atan(Math.Sinh(n))
End Function
为了创建一个地图叠加层,需要确定要覆盖的区域。这可以通过查看AxMapWinGIS地图的范围来找到。
Dim MapExtents As MapWinGIS.Extents = MapMain.Extents
Dim LonMin As Double = MapExtents.xMin
Dim LonMax As Double = MapExtents.xMax
Dim LatMin As Double = MapExtents.yMin
Dim LatMax As Double = MapExtents.yMax
' 此方法仅在AxMapWinGIS地图使用与OSM滑动瓦片相同的坐标系统时有效,即WGS-84。
' 如果不是,则需要将WGS-84转换为地图的坐标系统,反之亦然。
Once we have the area define by Min and Max Lat and Lon, we can use one of the Slippy Map functions to convert from the coordinates to Tile references for the Top Left corner and Bottom right corner of the Map:
TLTile = CalcTileXY(LatMax, LonMin, ZoomLevel)
BRTile = CalcTileXY(LatMin, LonMax, ZoomLevel)
Now add each tile in turn to the map
Dim H As Integer, V As Integer
Dim TileRef As Point
For H = TLTile.X To BRTile.X
For V = TLTile.Y To BRTile.Y
TileRef.X = H
TileRef.Y = V
Call LoadOSMTile(MapMain, TileRef, ZoomLevel)
Next
Next
每个瓦片都存储在滑动瓦片服务器上的目录结构中。
Const ServerName As String = "http://a.tile.openstreetmap.org/"
Dim URL As String = ServerName & ZoomLevel & "/" & TileRef.X & "/" & TileRef.Y & ".png"
' Get the image from the web server
Dim request As Net.HttpWebRequest = DirectCast(Net.HttpWebRequest.Create(URL), Net.HttpWebRequest)
Dim response As Net.HttpWebResponse = DirectCast(request.GetResponse, Net.HttpWebResponse)
Dim Image As System.Drawing.Image = Image.FromStream(response.GetResponseStream())
response.Close()
下载瓦片后,将其保存在本地缓存中,并为其创建一个世界文件(使用与.png文件关联的.pgw扩展名)。
Dim TileTLCoord As PointF = CalcTileTLCoord(TileRef, ZoomLevel)
Dim Point2 As PointF
Point2.X = TileRef.X + 1
Point2.Y = TileRef.Y + 1
Dim TileWidthDeg As Double = CalcTileTLCoord(Point2, ZoomLevel).X - CalcTileTLCoord(TileRef, ZoomLevel).X
Dim TileHeightDeg As Double = CalcTileTLCoord(TileRef, ZoomLevel).Y - CalcTileTLCoord(Point2, ZoomLevel).Y
' Create World file to geo-reference the PNG. See: http://en.wikipedia.org/wiki/World_file
Dim oWrite As System.IO.StreamWriter = IO.File.CreateText(CacheTileDirectory & "\" & Left(CacheFileName, CacheFileName.Length - 4) & ".pgw")
oWrite.WriteLine(FormatNumber(TileWidthDeg / 256, 10))
oWrite.WriteLine("0.0")
oWrite.WriteLine("0.0")
oWrite.WriteLine(FormatNumber(-1 * TileHeightDeg / 256, 10))
oWrite.WriteLine(FormatNumber(TileTLCoord.X, 10))
oWrite.WriteLine(FormatNumber(TileTLCoord.Y, 10))
oWrite.Close()
注意,高度是负数,表示像素从左上角垂直向下。一旦将世界文件保存到与PNG图像相同的目录中,就可以将PNG文件添加到地图中。只要世界文件在同一个目录中,MapWinGIS就会自动检测到它。
完整的Visual Studio 2010项目包括上述代码和Windows表单包装器,允许用户导航Shape文件,进行缩放。鼠标位置显示在屏幕底部的文本窗口中,因此可以通过定位已知特征等来检查叠加层是否正确。
所需的唯一外部引用是一个Shape文件,代码当前使用的是MapWindow示例项目文件之一,该文件随MapWindow一起安装。
"C:\Program Files\MapWindow\Sample Projects\World\Shapefiles\WORLD30.shp"