' Gambas module file

Fast
Export
'Private halfPixelGlobeSize As Integer
  
  Private $TileSize As Integer = 256
  Private $initialResolution As Float = 2 * Pi * 6378137 / $tileSize
  Private $OriginShift As Float = 2 * Pi * 6378137 / 2.0


Public Function MapPointToTile(hMapPoint As MapPoint, Zoom As Integer) As Point

  Dim n As Float = 2 ^ Zoom
  Dim hPoint As New Point

  hPoint.X = Int((hMapPoint.Lon + 180.0) / 360.0 * n)
  hPoint.y = Int((1.0 - Log(Tan(Rad(hMapPoint.Lat)) + (1 / Cos(Rad(hMapPoint.Lat)))) / Pi) / 2.0 * n)
  Return hPoint
End

Public Function MapPointToPixel(hMapPoint As MapPoint, Zoom As Integer) As Point

  Dim fRes As Float = $initialResolution / (2 ^ Zoom)
  Dim fX, fY As Float

  'Convert in Meters
  fX = hMapPoint.lon * $OriginShift / 180.0
  fY = -(Log(Tan((90 + hMapPoint.lat) * Pi / 360.0)) / (Pi / 180.0)) * $OriginShift / 180.0
  'Convert in Pixels
  fX = (fX + $originShift) / fRes
  fY = (fY + $originShift) / fRes
  Return Point(fX, fY)

End


 Public Function PixelToMapPoint(hPoint As Point, Zoom As Integer) As MapPoint
  Dim fX, fY As Float
  Dim fRes As Float = $initialResolution / (2 ^ Zoom)
  Dim mpPoint As New MapPoint

  'Convert in Meters
  fX = hPoint.x * fRes - $originShift
  fY = hPoint.y * fRes - $originShift

  'Convert in Latlon mappoint
  mpPoint.Lon = (fX / $originShift) * 180.0
  mpPoint.Lat = (fY / $originShift) * 180.0

  mpPoint.Lat = -(180 / Pi * (2 * ATan(Exp(mpPoint.Lat * Pi / 180.0)) - Pi / 2.0))
  Return mpPoint

 End
 
 Public Function PixelToTile(hPoint As Point) As Point

    Return Point(Int(Ceil(hPoint.X / $tileSize) - 1), Int(Ceil(hPoint.Y / $tileSize) - 1))

End


'' Convert a value in sexagesimal degree to decimal
'' ex: 45°53'36" -> 45,893333
Public Function SexToDec(Value As String) As Float

  Dim fRet As Float
  Dim ars As String[]
  'Lat
  ars = Scan(Value, "*°*'*''*")
  fRet = Val(ars[0]) + Val(ars[1]) / 60 + CFloat(ars[2]) / 3600
  If ars.Count = 4 Then
    Select Case UCase(ars[3])
      Case "N", "E"
        Return fRet
      Case "S", "W", "O"
        Return -fRet
    End Select
  Endif
  Return fRet

End

'' Convert from Decimal to Sexagesimal degrees
'' ex:45,893333 -> 45°53'36"
'' Type 0=None 1=Lat 2=Lon
Public Function DecToSex(Value As Float, Type As Integer) As String

  Dim iDeg As Integer
  Dim iMin As Integer
  Dim fSec As Float
  Dim sRet As String

  Select Case Type
    Case 0

    Case 1
      sret = IIf(Value > 0, "N", "S")
    Case 2
      sret = IIf(Value > 0, "E", "W")
  End Select
  Value = Abs(Value)
  iDeg = Int(Value)
  fSec = Frac(Value) * 60
  iMin = Int(fSec)
  fSec = Frac(fSec) * 60

  sret = Subst("&1°&2'&3''", iDeg, iMin, Format(fSec, "0.##")) & sRet
  Return sRet

End

Public Function TileBounds(X As Integer, Y As Integer, Zoom As Integer) As MapBounds
  Dim hPointTL, hPointBR As Point
  Dim mp, mp2 As MapPoint

  hPointTL = Point(X * $tileSize, Y * $tileSize)
  hPointBR = Point(hPointTL.X + $tileSize, hPointTL.Y + $tileSize)
  mp = PixelToMapPoint(hPointTL, zoom)
  mp2 = PixelToMapPoint(hPointBR, zoom)

  Return MapBounds(PixelToMapPoint(hPointTL, zoom), PixelToMapPoint(hPointBR, zoom))
End

Public Function TileToMapPoint(X As Integer, Y As Integer, Zoom As Integer) As MapPoint
  
  Return PixelToMapPoint(x * $tileSize, y * $tileSize, zoom)
  
End


