While Randy (see previous blog) showed how to use GeoWebCache to display tiles in the Silverlight map control, we needed to display WMS tiles that are not cached. The reason was that GWC doesn't play nice with GeoServer password secured layers. This would also be useful for layers that change frequently and cannot be cached.
I put together this TileSource class in VB.NET to do this:
'Normal WMS (non GWC)
'Translated from http://www.maptiler.org/google-maps-coordinates-tile-bounds-projection/
'
Public Class NormalWMSTileSource
Inherits Microsoft.VirtualEarth.MapControl.TileSource
Sub New()
MyBase.UriFormat = "http://ogi.state.ok.us/geoserver/wms?LAYERS=ogi:okcounties&FORMAT=image%2Fpng&SERVICE=WMS&VERSION=1.1.1&REQUEST=GetMap&STYLES=&EXCEPTIONS=application%2Fvnd.ogc.se_inimage&SRS=EPSG%3A900913&BBOX={0},{1},{2},{3}&WIDTH=256&HEIGHT=256&TRANSPARENT=TRUE"
End Sub
Sub New(ByVal WMSLayerName As String)
MyBase.UriFormat = "http://ogi.state.ok.us/geoserver/wms?LAYERS=" & WMSLayerName & "&FORMAT=image%2Fpng&SERVICE=WMS&VERSION=1.1.1&REQUEST=GetMap&STYLES=&EXCEPTIONS=application%2Fvnd.ogc.se_inimage&SRS=EPSG%3A900913&BBOX={0},{1},{2},{3}&WIDTH=256&HEIGHT=256&TRANSPARENT=TRUE"
End Sub
Public Overrides Function GetUri(ByVal x As Integer, ByVal y As Integer, ByVal zoomLevel As Integer) As System.Uri
'Example:
'http://ogi.state.ok.us/geoserver/wms?LAYERS=ogi%3Aokcounties&FORMAT=image%2Fpng&SERVICE=WMS&VERSION=1.1.1&REQUEST=GetMap&STYLES=&EXCEPTIONS=application%2Fvnd.ogc.se_inimage&SRS=EPSG%3A900913&BBOX=-11271098.44125,4070118.8815625,-10958012.373437,4383204.949375&WIDTH=256&HEIGHT=256
'Convert x,y,zoom to 900913 coords and return a wms URI
Dim R As Rect = TileBounds(x, y, zoomLevel)
Return New Uri(String.Format(Me.UriFormat, R.Left, R.Top, R.Right, R.Bottom))
End Function
'def(__init__(self, tileSize = 256))
'"Initialize the TMS Global Mercator pyramid"
'self.tileSize = tileSize
'self.initialResolution = 2 * Math.PI * 6378137 / self.tileSize
'# 156543.03392804062 for tileSize 256 pixels
'self.originShift = 2 * Math.PI * 6378137 / 2.0
'# 20037508.342789244
Dim tileSize = 256
'"Initialize the TMS Global Mercator pyramid"
Dim initialResolution = 2 * Math.PI * 6378137 / tileSize
'# 156543.03392804062 for tileSize 256 pixels
Dim originShift = 2 * Math.PI * 6378137 / 2.0
'# 20037508.342789244
'def(TileBounds(self, tx, ty, zoom))
'"Returns bounds of the given tile in EPSG:900913 coordinates"
'minx, miny = self.PixelsToMeters(tx * self.tileSize, ty * self.tileSize, zoom)
'maxx, maxy = self.PixelsToMeters((tx + 1) * self.tileSize, (ty + 1) * self.tileSize, zoom)
'return ( minx, miny, maxx, maxy )
Private Function TileBounds(ByVal tx, ByVal ty, ByVal zoom) As Rect
'"Returns bounds of the given tile in EPSG:900913 coordinates"
Dim MinP As Point = PixelsToMeters(tx * tileSize, ty * tileSize, zoom)
Dim MaxP As Point = PixelsToMeters((tx + 1) * tileSize, (ty + 1) * tileSize, zoom)
Dim R As New Rect(MinP, MaxP)
Return R
End Function
'def(PixelsToMeters(self, px, py, zoom))
'"Converts pixel coordinates in given zoom level of pyramid to EPSG:900913"
'res = self.Resolution(zoom)
'mx = px * res - self.originShift
'my = py * res - self.originShift
'return mx, my
Private Function PixelsToMeters(ByVal px, ByVal py, ByVal zoom) As Point
Dim P As New Point
Dim res = Resolution(zoom)
P.X = px * res - originShift
'Strange, this come out negative? Should be positive.
P.Y = -(py * res - originShift)
Return P
End Function
'def(Resolution(self, zoom))
'"Resolution (meters/pixel) for given zoom level (measured at Equator)"
'# return (2 * math.pi * 6378137) / (self.tileSize * 2**zoom)
'return self.initialResolution / (2**zoom)
Private Function Resolution(ByVal zoom)
'"Resolution (meters/pixel) for given zoom level (measured at Equator)"
'# return (2 * math.pi * 6378137) / (self.tileSize * 2**zoom)
Return initialResolution / (Math.Pow(2, zoom))
End Function
End Class
Sunday, July 5, 2009
Subscribe to:
Posts (Atom)