I have spent some time adding the ability to go to and from web
map URLs in my program for viewing tiled maps.

The source code is available at:

http://code.google.com/p/vataviamap/source/browse/trunk/VataviaMap/Shared/clsServer.vb

The part that parses web map URLs is:

Private Const OSMshortlinkPrefix As String = "http://osm.org/go/";
Private Const OSMshortlinkEncoding As String = 
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_~"

''' <summary>
''' Given a web map URL, look for the center latitude/longitude, zoom, and 
bounding box
''' </summary>
''' <param name="aURL">Web map URL to examine</param>
''' <param name="aCenterLatitude">returns latitude at center of area</param>
''' <param name="aCenterLongitude">returns longitude at center of area</param>
''' <param name="aZoom">returns zoom level</param>
''' <param name="aNorth">returns north latitude of bounding box</param>
''' <param name="aWest">returns west longitude of bounding box</param>
''' <param name="aSouth">returns south latitude of bounding box</param>
''' <param name="aEast">returns east longitude of bounding box</param>
''' <returns>
''' True if link was parsed and reasonable values for the center latitude and 
longitude were found
''' </returns>
Function ParseWebmapURL(ByVal aURL As String, _
                        ByRef aCenterLatitude As Double,
                        ByRef aCenterLongitude As Double, _
                        ByRef aZoom As Integer, _
                        ByRef aNorth As Double, ByRef aWest As Double, _
                        ByRef aSouth As Double, ByRef aEast As Double) As 
Boolean
        Try
            Dim lBounds As Boolean = False
            Dim lURL As String = aURL.ToLower
            Dim lArgs() As String
            If lURL.StartsWith(OSMshortlinkPrefix) Then
                Return 
ParseOSMshortlink(aURL.Substring(OSMshortlinkPrefix.Length), aCenterLatitude, 
aCenterLongitude, aZoom)
            ElseIf lURL.StartsWith("http://maps.stamen.com/m2i/";) Then
                lArgs = lURL.Split("/")
                If lArgs.Length > 3 AndAlso IsNumeric(lArgs(lArgs.Length - 3)) _
                                    AndAlso IsNumeric(lArgs(lArgs.Length - 2)) _
                                    AndAlso IsNumeric(lArgs(lArgs.Length - 1)) 
Then
                    aZoom = Double.Parse(lArgs(lArgs.Length - 3))
                    aCenterLatitude = Double.Parse(lArgs(lArgs.Length - 2))
                    aCenterLongitude = Double.Parse(lArgs(lArgs.Length - 1))
                End If
            ElseIf lURL.StartsWith("geo:") Then
                lArgs = lURL.Substring(4).Split(",")
                If lArgs.Length > 1 AndAlso IsNumeric(lArgs(0)) AndAlso 
IsNumeric(lArgs(1)) Then
                    aCenterLatitude = Double.Parse(lArgs(0))
                    aCenterLongitude = Double.Parse(lArgs(1))
                End If
            Else
                lArgs = lURL.Split("&"c, "?"c)
                For Each lArg As String In lArgs
                    Dim lArgPart() As String = lArg.Split("=")
                    If lArgPart.Length = 2 Then
                        Select Case lArgPart(0)
                            Case "latitude", "lat", "mlat"
                                aCenterLatitude = Double.Parse(lArgPart(1))
                            Case "longitude", "lon", "mlon", "lng", "mlng"
                                aCenterLongitude = Double.Parse(lArgPart(1))
                            Case "zoom", "z"
                                aZoom = Integer.Parse(lArgPart(1))
                            Case "ll", "q"
                                Dim ll() As String = lArgPart(1).Split(",")
                                If ll.Length = 2 AndAlso IsNumeric(ll(0)) Then
                                    'GoogleMaps
                                    DoubleTryParse(ll(0), aCenterLatitude)
                                    DoubleTryParse(ll(1), aCenterLongitude)
                                End If
                            Case "spn"
                                'TODO: parse Google's height,width into zoom
                            Case "cp"
                                'Bing
                                Dim ll() As String = lArgPart(1).Split("~")
                                If ll.Length = 2 AndAlso IsNumeric(ll(0)) 
AndAlso IsNumeric(ll(1)) Then
                                    aCenterLatitude = Double.Parse(ll(0))
                                    aCenterLongitude = Double.Parse(ll(1))
                                End If
                            Case "lvl" : aZoom = lArgPart(1)
                            Case "starttop" : aNorth = 
Double.Parse(lArgPart(1)) : lBounds = True
                            Case "startbottom" : aSouth = 
Double.Parse(lArgPart(1))
                            Case "startleft" : aWest = 
Integer.Parse(lArgPart(1))
                            Case "startright" : aEast = 
Integer.Parse(lArgPart(1))
                            Case "bbox"
                                Dim bbox() As String = lArgPart(1).Split(",")
                                If bbox.Length = 4 Then
                                    lBounds = DoubleTryParse(bbox(0), aWest) _
                                      AndAlso DoubleTryParse(bbox(1), aSouth) _
                                      AndAlso DoubleTryParse(bbox(2), aEast) _
                                      AndAlso DoubleTryParse(bbox(3), aNorth)
                                End If
                        End Select
                    End If
                Next
            End If
            If lBounds Then
                aCenterLatitude = (aNorth + aSouth) / 2
                aCenterLongitude = (aWest + aEast) / 2
                'TODO: compute zoom from (aNorth - aSouth) and/or (aWest - 
aEast)                    
            End If
            If aZoom > ZoomMax Then aZoom = ZoomMax
            If aZoom < ZoomMin Then aZoom = ZoomMin
            Return aCenterLatitude <> 0 AndAlso aCenterLongitude <> 0
        Catch
            Return False
        End Try
    End Function

    ''' <summary>
    ''' Parse an OpenStreetMap shortlink code into Latitude, Longitude and Zoom
    ''' </summary>
    ''' <param name="aCode">OpenStreetMap shortlink code</param>
    ''' <param name="aCenterLatitude">returns latitude at center of area</param>
    ''' <param name="aCenterLongitude">returns longitude at center of 
area</param>
    ''' <param name="aZoom">returns zoom level</param>
    ''' <returns>True if link was parsed and reasonable values for the ByRef 
arguments were found</returns>
    ''' <remarks>Based on 
http://git.openstreetmap.org/?p=rails.git;a=blob_plain;f=lib/short_link.rb;hb=HEAD
    ''' see also 
https://help.openstreetmap.org/questions/9566/shortlink-class-in-c</remarks>
    Private Function ParseOSMshortlink(ByVal aCode As String, _
                                       ByRef aCenterLatitude As Double, _
                                       ByRef aCenterLongitude As Double, _
                                       ByRef aZoom As Integer) As Boolean
        'http://osm.org/go/0MbEUuTq = 
http://www.openstreetmap.org/?lat=52.50547&lon=13.36932&zoom=16
        Dim x As Long = 0
        Dim y As Long = 0
        Dim z As Long = 0
        Dim z_offset As Long = 0

        Try
            ' replace @ in old shortlinks with ~
            aCode = aCode.Replace("@", "~")

            For Each ch As Char In aCode.ToCharArray
                Dim t As Integer = OSMshortlinkEncoding.IndexOf(ch)
                If t < 0 Then
                    z_offset -= 1
                Else
                    For index As Integer = 1 To 3
                        x <<= 1
                        If t And 32 Then x += 1
                        t <<= 1
                        y <<= 1
                        If t And 32 Then y += 1
                        t <<= 1
                    Next
                    z += 3
                End If
            Next
            ' pack the coordinates out to their original 32 bits.
            x <<= (32 - z)
            y <<= (32 - z)

            ' project the parameters back to their coordinate ranges.
            aCenterLongitude = (x * 360.0 / 2 ^ 32) - 180.0
            aCenterLatitude = (y * 180.0 / 2 ^ 32) - 90.0
            aZoom = z - 8 - (z_offset Mod 3)
            Return aCenterLatitude > -90 AndAlso aCenterLatitude < 90 AndAlso _
                aCenterLongitude >= -180 AndAlso aCenterLongitude <= 180
        Catch
            Return False
        End Try
    End Function

_______________________________________________
Talk-us mailing list
Talk-us@openstreetmap.org
http://lists.openstreetmap.org/listinfo/talk-us

Reply via email to