Re: OpenStreetMap dans un Canvas
Publié : ven. 08/juil./2016 11:45
Je ne sais pas pourquoi il y avait un zoom + 1, ce qui m'a causé bien des tracas. Cela ne servait à rien, il n'y a pas d'histoire de 512, les tuiles font bien 256 pixels, et elles sont servies sur ce principe. Maintenant, il faut travailler sur le centrage de la carte sur les coordonnées du point voulu, et pas sur le coin de la tuile. Je suis dessus, voici le code pour l'instant
Code : Tout sélectionner
InitNetwork()
DeclareModule OSM
Declare InitOSM()
Declare OSMGadget(Gadget.i, X.i, Y.i, Width.i, Height.i)
Declare Event(Event.l)
Declare SetLocation(latitude.d, longitude.d, zoom = 15)
Declare GetSquareTile()
Declare DrawMap()
Declare SetZoom(Zoom.i, mode.i = #PB_Relative)
EndDeclareModule
Module OSM
#USEPROXY = #False
UsePNGImageDecoder()
UsePNGImageEncoder()
CompilerIf #USEPROXY = #True
IncludeFile("C : \Users\lebrun_y_413\Documents\Developpement\Purebasic\includes Share\http.pbi")
CompilerEndIf
Structure Location
Longitude.d
Latitude.d
EndStructure
Structure Tile
X.i
Y.i
EndStructure
Structure Pixel
X.i
Y.i
EndStructure
Structure OSM
Gadget.i
TargetLocation.Location
TargetTile.tile
ServerURL.s
ZoomMin.i
ZoomMax.i
Zoom.i
CachePath.S
StartCursor.Pixel
DeltaCursor.Pixel
Shift.Pixel
EndStructure
Global OSM.OSM
Procedure InitOSM()
OSM\CachePath = GetTemporaryDirectory()
OSM\ServerURL = "http://tile.openstreetmap.org/"
OSM\ZoomMin = 0
OSM\ZoomMax = 18
OSM\StartCursor\X = - 1
EndProcedure
Procedure OSMGadget(Gadget.i, X.i, Y.i, Width.i, Height.i)
If Gadget = #PB_Any
OSM\Gadget = CanvasGadget(OSM\Gadget, X, Y, Width, Height)
Else
OSM\Gadget = Gadget
CanvasGadget(OSM\Gadget, X, Y, Width, Height)
EndIf
EndProcedure
Procedure LatLon2XY(*Location.Location, *Tile.Tile)
Protected n.d = Pow(2.0, OSM\Zoom)
Protected LatRad.d = Radian(*Location\Latitude)
*Tile\X = n * ( (*Location\Longitude + 180.0) / 360.0)
*Tile\Y = n * ( 1.0 - Log(Tan(LatRad) + 1.0/Cos(LatRad)) / #PI ) / 2.0
Debug "Latitude : " + StrD(*Location\Latitude) + " ; Longitude : " + StrD(*Location\Longitude)
Debug "Tile X : " + Str(*Tile\X) + " ; Tile Y : " + Str(*Tile\Y)
EndProcedure
Procedure XY2LatLon(*Tile.Tile, *Location.Location)
Protected n.d = Pow(2.0, OSM\Zoom)
Protected LatitudeRad.d
*Location\Longitude = *Tile\X / n * 360.0 - 180.0
LatitudeRad = ATan(SinH(#PI * (1.0 - 2.0 * *Tile\Y / n)))
*Location\Latitude = Degree(LatitudeRad)
EndProcedure
Procedure LoadMapTile(Image.i, Zoom.i, XTile.i, YTile.i)
Protected *Buffer
Protected TileURL.s = OSM\ServerURL + Str(Zoom) + "/" + Str(XTile) + "/" + Str(YTile) + ".png"
; Test if in cache else download it
Protected CacheFile.s = "OSM_" + Str(Zoom) + "_" + Str(XTile) + "_" + Str(YTile) + ".png"
If FileSize(osm\cachePath + cacheFile) > 0
Debug "Use Cache : " + cacheFile
LoadImage(Image, OSM\CachePath + CacheFile)
Else
;Debug "DOWNLOAD : " + psURL
CompilerIf #USEPROXY = #True
Protected http.HTTP_Query
HTTP_proxy(@http, "spxy.bpi.fr", 3128)
HTTP_DownloadToMem(@http, TileURL)
If IsImage(Image)
FreeImage(Image)
EndIf
If CatchImage(Image, http\data, MemorySize(http\data))
SaveImage(Image, OSM\CachePath + CacheFile, #PB_ImagePlugin_PNG)
EndIf
CompilerElse
*Buffer = ReceiveHTTPMemory(TileURL) ;TODO to thread by using #PB_HTTP_Asynchronous
If IsImage(Image)
FreeImage(Image)
EndIf
If *Buffer
If CatchImage(Image, *Buffer, MemorySize(*Buffer))
Debug "Loaded :" + TileURL
SaveImage(image, OSM\CachePath + CacheFile, #PB_ImagePlugin_PNG)
FreeMemory(*Buffer)
Else
Debug "Can't catch image :" + TileURL
EndIf
Else
Debug "Problem loading :" + TileURL
EndIf
CompilerEndIf
EndIf
EndProcedure
Procedure GetSquareTile()
Protected x.i, y.i, nx.i, ny.i, n.i = 0, tx.i, ty.i
mx = GadgetWidth(OSM\Gadget)
my = GadgetHeight(OSM\Gadget)
nx = mx/256 ;How many tiles
ny = my/256
mx/2 : my/2 ;Gadget center
tx = OSM\TargetTile\X
ty = OSM\TargetTile\Y
For y = ty - ny To ty + ny + ny - 1
For x = tx - nx To tx + nx + nx - 1
LoadMapTile(n, OSM\Zoom, x, y)
n = n + 1
Next
Next
Debug Str(n) + " Images Chargées";
EndProcedure
Procedure DrawMap()
Protected x.i, y.i, nx.i, ny.i, mx.i, my.i, n.i = 0
Protected deltaX.i, deltaY.i
;Protected tx.i, ty.i
Protected x2.i, y2.i
;deltaX = 512*(OSM\TargetTile\X - Int(OSM\TargetTile\X)) - 256 ;TODO Why - 256 ?????
;deltaY = 512*(OSM\TargetTile\Y - Int(OSM\TargetTile\Y)) - 512 ;TODO Why - 512 ?????
;tx = 2 * OSM\TargetTile\X
;ty = 2 * OSM\TargetTile\Y
mx = GadgetWidth(OSM\Gadget)
my = GadgetHeight(OSM\Gadget)
nx = mx/256 ;How many tiles
ny = my/256
mx/2 : my/2 ;Gadget center
StartDrawing(CanvasOutput(OSM\Gadget))
Box(0, 0, GadgetWidth(OSM\Gadget), GadgetHeight(OSM\Gadget), RGB(255, 255, 255))
For y = - ny To ny + ny - 1
For x = - nx To nx + nx - 1
x2 = x*256 + OSM\DeltaCursor\X
y2 = y*256 + OSM\DeltaCursor\Y
If IsImage(n) And (x2 + 256) > 0 And (y2 + 256) > 0 And x2 < GadgetWidth(OSM\Gadget) And y2 < GadgetHeight(OSM\Gadget)
DrawImage(ImageID(n), mx + x2 - 128, my + y2 - 128, 254, 254)
DrawText( x2, y2, Str(x) + ", " + Str(y))
EndIf
n = n + 1
Next
Next
Circle(GadgetWidth(OSM\Gadget)/2, GadgetHeight(OSM\Gadget)/2, 5, #Red)
;DrawText(0, 0, "DeltaCursorX : " + Str(OSM\DeltaCursor\X) + " deltaX : " + Str(deltaX) + " Tile X : " + StrD(OSM\TargetTile\X))
DrawText(0, 16, Str(OSM\TargetTile\X + OSM\DeltaCursor\X) + " " + Str(OSM\TargetTile\Y + OSM\DeltaCursor\Y))
StopDrawing()
EndProcedure
Procedure SetLocation(latitude.d, longitude.d, zoom = 15)
If zoom > OSM\ZoomMax : zoom = OSM\ZoomMax : EndIf
If zoom < OSM\ZoomMin : zoom = OSM\ZoomMin : EndIf
OSM\Zoom = zoom
OSM\TargetLocation\Latitude = latitude
OSM\TargetLocation\Longitude = longitude
LatLon2XY(@OSM\TargetLocation, @OSM\TargetTile)
EndProcedure
Procedure TileTranslate(*Tile.Tile, tx.d, ty.d)
Debug " - move - "
Protected pfValue.d
If tx <> 0
pfValue = *Tile\X - tx
If pfValue > Pow(2, OSM\Zoom) - 1
*Tile\X = Pow(2, OSM\Zoom) - 2
ElseIf pfValue < 0
*Tile\X = Pow(2, OSM\Zoom) - 2
Else
*Tile\X = pfValue
EndIf
EndIf
If ty <> 0
pfValue = *Tile\Y - ty
If pfValue > Pow(2, OSM\Zoom) - 1
*Tile\Y = Pow(2, OSM\Zoom) - 2
ElseIf pfValue < 0
*Tile\Y = Pow(2, OSM\Zoom) - 2
Else
*Tile\Y = pfValue
EndIf
EndIf
EndProcedure
Procedure SetZoom(Zoom.i, mode.i = #PB_Relative)
Select mode
Case #PB_Relative
OSM\Zoom = OSM\Zoom + zoom
Case #PB_Absolute
OSM\Zoom = zoom
EndSelect
If OSM\Zoom > OSM\ZoomMax : OSM\Zoom = OSM\ZoomMax : EndIf
If OSM\Zoom < OSM\ZoomMin : OSM\Zoom = OSM\ZoomMin : EndIf
LatLon2XY(@OSM\TargetLocation, @OSM\TargetTile)
GetSquareTile()
DrawMap()
EndProcedure
Procedure Event(Event.l)
Protected Gadget.i
Protected tx.i, ty.i
If IsGadget(OSM\Gadget) And GadgetType(OSM\Gadget) = #PB_GadgetType_Canvas
Select Event
Case #PB_Event_Gadget ;{
Gadget = EventGadget()
Select Gadget
Case OSM\Gadget
Select EventType()
Case #PB_EventType_LeftButtonDown
;Mem cursor Coord
OSM\StartCursor\X = GetGadgetAttribute(OSM\Gadget, #PB_Canvas_MouseX)
OSM\StartCursor\Y = GetGadgetAttribute(OSM\Gadget, #PB_Canvas_MouseY)
Case #PB_EventType_MouseMove
If OSM\StartCursor\X <> - 1
tx = GetGadgetAttribute(OSM\Gadget, #PB_Canvas_MouseX) - OSM\StartCursor\X + OSM\Shift\X
ty = GetGadgetAttribute(OSM\Gadget, #PB_Canvas_MouseY) - OSM\StartCursor\Y + OSM\Shift\Y
;TileTranslate(@OSM\TargetTile, tx/256, ty/256)
OSM\DeltaCursor\X = tx%256
OSM\DeltaCursor\Y = ty%256
If tx/256 <> 0 Or ty/256 <> 0
OSM\TargetTile\X - tx/256
OSM\TargetTile\Y - ty/256
OSM\Shift\X = OSM\DeltaCursor\X
OSM\Shift\Y = OSM\DeltaCursor\Y
OSM\StartCursor\X = GetGadgetAttribute(OSM\Gadget, #PB_Canvas_MouseX)
OSM\StartCursor\Y = GetGadgetAttribute(OSM\Gadget, #PB_Canvas_MouseY)
XY2LatLon(@OSM\TargetTile, @OSM\TargetLocation)
;SetLocation(OSM\TargetLocation\Latitude, OSM\TargetLocation\Longitude, OSM\Zoom)
GetSquareTile()
EndIf
DrawMap()
EndIf
Case #PB_EventType_LeftButtonUp
OSM\Shift\X = OSM\DeltaCursor\X
OSM\Shift\Y = OSM\DeltaCursor\Y
OSM\DeltaCursor\X = 0
OSM\DeltaCursor\Y = 0
OSM\StartCursor\X = - 1
;move(tx, ty)
;SetGadgetText(#String_1, StrD(OSM\TargetLocation\Latitude))
;SetGadgetText(#String_0, StrD(OSM\TargetLocation\Longitude))
EndSelect
EndSelect
EndSelect
Else
MessageRequester("Module OSM", "You must use OSMGadget before", #PB_MessageRequester_Ok )
End
EndIf
EndProcedure
EndModule
Enumeration
#Window_0
#Map
#Button_0
#Button_1
#Button_2
#Button_3
#Button_4
#Button_5
#Combo_0
#Text_0
#Text_1
#Text_2
#Text_3
#Text_4
#String_0
#String_1
EndEnumeration
;- Main
If OpenWindow(#Window_0, 260, 225, 700, 571, "OpenStreetMap", #PB_Window_SystemMenu | #PB_Window_MinimizeGadget | #PB_Window_TitleBar | #PB_Window_ScreenCentered )
OSM::InitOSM()
LoadFont(0, "Wingdings", 12)
LoadFont(1, "Arial", 12, #PB_Font_Bold)
OSM::OSMGadget(#Map, 10, 10, 512, 512)
TextGadget(#Text_1, 530, 50, 60, 15, "Movements : ")
ButtonGadget(#Button_0, 550, 100, 30, 30, Chr($E7)) : SetGadgetFont(#Button_0, FontID(0))
ButtonGadget(#Button_1, 610, 100, 30, 30, Chr($E8)) : SetGadgetFont(#Button_1, FontID(0))
ButtonGadget(#Button_2, 580, 070, 30, 30, Chr($E9)) : SetGadgetFont(#Button_2, FontID(0))
ButtonGadget(#Button_3, 580, 130, 30, 30, Chr($EA)) : SetGadgetFont(#Button_3, FontID(0))
TextGadget(#Text_2, 530, 160, 60, 15, "Zoom : ")
ButtonGadget(#Button_4, 550, 180, 50, 30, " + ") : SetGadgetFont(#Button_4, FontID(1))
ButtonGadget(#Button_5, 600, 180, 50, 30, " - ") : SetGadgetFont(#Button_5, FontID(1))
TextGadget(#Text_3, 530, 230, 60, 15, "Latitude : ")
StringGadget(#String_0, 600, 230, 90, 20, "")
TextGadget(#Text_4, 530, 250, 60, 15, "Longitude : ")
StringGadget(#String_1, 600, 250, 90, 20, "")
Define Event.i, Gadget.i, Quit.b = #False
Define pfValue.d
OSM::SetLocation(49.04599, 2.03347, 15)
OSM::GetSquareTile()
OSM::DrawMap()
;OSM::SetLocation(49.0361165, 2.0456982)
Repeat
Event = WaitWindowEvent()
OSM::Event(Event)
Select Event
Case #PB_Event_CloseWindow : Quit = 1
Case #PB_Event_Gadget ;{
Gadget = EventGadget()
Select Gadget
Case #Button_4
OSM::SetZoom(1)
Case #Button_5
OSM::SetZoom( - 1)
EndSelect
EndSelect
Until Quit = #True
EndIf