PBMap - Cartes OSM, Here, Geoserver dans un Canvas
Re: OpenStreetMap dans un Canvas
Pour le proxy on va toujours avoir le problème, je pense qu'il faut utiliser curl. Je pense qu'il y a un souci avec le code et les index, car ceux-ci peuvent changer en fonction de l'ajout/retrait d'éléments. Il vaut mieux passer par des pointeurs. Je suis dessus...
Re: OpenStreetMap dans un Canvas
Pour le proxy je comprends pas pourquoi Fred ne l'a pas intégré çadjes a écrit :Pour le proxy on va toujours avoir le problème, je pense qu'il faut utiliser curl. Je pense qu'il y a un souci avec le code et les index, car ceux-ci peuvent changer en fonction de l'ajout/retrait d'éléments. Il vaut mieux passer par des pointeurs. Je suis dessus...

Ok ça marche

j'utilise un PostEvent (le windowstimer ça n'a pas marché) pour rafraichir la map
Code : Tout sélectionner
;**************************************************************
; Program: OSM (OpenStreetMap Module)
; Author: Thyphoon And Djes
; Date: Mai 17, 2016
; License: Free, unrestricted, credit appreciated
; but not required.
; Note: Please share improvement !
; Thanks: Progi1984,
;**************************************************************
InitNetwork()
CompilerIf #PB_Compiler_Thread=0
MessageRequester("Warning !!","You must to Enable 'create ThreadSafe' in compiler option",#PB_MessageRequester_Ok )
End
CompilerEndIf
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 SetZoom(Zoom.i, mode.i = #PB_Relative)
Declare ConstructMap()
Declare DrawMap()
Declare LoadGpxFile(file.s);
EndDeclareModule
Module OSM
#USEPROXY = #True
UsePNGImageDecoder()
UsePNGImageEncoder()
Enumeration #PB_Event_FirstCustomValue
#EvenementStartRefresh
#EvenementStopRefresh
EndEnumeration
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.d
Y.d
EndStructure
Structure Pixel
X.i
Y.i
EndStructure
Structure ImgMemCach
nImage.i
Zoom.i
XTile.i
YTile.i
EndStructure
Structure TileMemCach
List Image.ImgMemCach()
Mutex.i
Semaphore.i
EndStructure
Structure OSM
Windows.i ;
Gadget.i ; Canvas Gadget Id
TargetLocation.Location ; Latitude and Longitude from focus point
TargetTile.Tile ; Focus Tile coord
Position.Pixel ; Focus Point coord in Pixel
ServerURL.s ; Web Url ex: http://tile.openstreetmap.org/
ZoomMin.i ; Min Zoom supported by Server
ZoomMax.i ; Max Zoom supported by Server
Zoom.i ; Current Zoom
TileSize.i ; Tile Size downloaded on the server ex : 256
HDDCachePath.S ; path where to load an save tile downloaded from server
MemCache.TileMemCach ; to know image always in memory
; List MapImageIndex.ImgMemCach() ; List of Index from MemCache\Image() to construct map
Array MapImage.ImgMemCach(16,16)
MapImageMutex.i ; Mutex to lock
MapImageSemaphore.i ; Semaphore to control Thread
StartCursor.Pixel ; coord from start drag the map
DeltaCursor.Pixel ; delta from curent position and the start position
List track.Location() ;to display a track GPX on card
EndStructure
Global OSM.OSM
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 getPixelCoorfromLocation(*Location.Location,*Pixel.Pixel) ; TODO to Optimize
Protected mapWidth.l = Pow(2,OSM\Zoom+8)
Protected mapHeight.l = Pow(2,OSM\Zoom+8)
Protected x1.l,y1.l
; get x value
x1 = (*Location\Longitude+180)*(mapWidth/360)
; convert from degrees To radians
Protected latRad.d = *Location\Latitude*#PI/180;
Protected mercN.d = Log(Tan((#PI/4)+(latRad/2)));
y1 = (mapHeight/2)-(mapWidth*mercN/(2*#PI)) ;
Protected x2.l,y2.l
; get x value
x2 = (OSM\TargetLocation\Longitude+180)*(mapWidth/360)
; convert from degrees To radians
latRad = OSM\TargetLocation\Latitude*#PI/180;
; get y value
mercN = Log(Tan((#PI/4)+(latRad/2))) ;
y2 = (mapHeight/2)-(mapWidth*mercN/(2*#PI));
*Pixel\X=GadgetWidth(OSM\Gadget)/2-(x2-x1)+ OSM\DeltaCursor\X
*Pixel\Y=GadgetHeight(OSM\Gadget)/2-(y2-y1)+ OSM\DeltaCursor\Y
EndProcedure
Procedure LoadGpxFile(file.s)
If LoadXML(0, file.s)
Protected Message.s
If XMLStatus(0) <> #PB_XML_Success
Message = "Error in the XML file:" + Chr(13)
Message + "Message: " + XMLError(0) + Chr(13)
Message + "Line: " + Str(XMLErrorLine(0)) + " Character: " + Str(XMLErrorPosition(0))
MessageRequester("Error", Message)
EndIf
Protected *MainNode,*subNode,*child,child.l
*MainNode=MainXMLNode(0)
*MainNode=XMLNodeFromPath(*MainNode,"/gpx/trk/trkseg")
ClearList(OSM\track())
For child = 1 To XMLChildCount(*MainNode)
*child = ChildXMLNode(*MainNode, child)
AddElement(OSM\track())
If ExamineXMLAttributes(*child)
While NextXMLAttribute(*child)
Select XMLAttributeName(*child)
Case "lat"
OSM\track()\Latitude=ValD(XMLAttributeValue(*child))
Case "lon"
OSM\track()\Longitude=ValD(XMLAttributeValue(*child))
EndSelect
Wend
EndIf
Next
EndIf
EndProcedure
Procedure AddTileToMemCache(Zoom.i, XTile.i, YTile.i,nImage.i)
Protected Index.i
If IsImage(nImage)
LockMutex(OSM\MemCache\Mutex)
;We add To the List And load it
FirstElement(OSM\MemCache\Image())
AddElement(OSM\MemCache\Image())
Index=ListIndex(OSM\MemCache\Image())
OSM\MemCache\Image()\XTile=XTile
OSM\MemCache\Image()\YTile=YTile
OSM\MemCache\Image()\Zoom=Zoom
OSM\MemCache\Image()\nImage=nImage
UnlockMutex(OSM\MemCache\Mutex)
ProcedureReturn Index
Else
Debug "NO ADD TILE TO MEM CACHE BECAUSE BAD IMAGE"
EndIf
EndProcedure
Procedure.i GetTileFromMem(Zoom.i, XTile.i, YTile.i)
Protected nImage.i
LockMutex(OSM\MemCache\Mutex)
;Check if we have this Image in Memory
ForEach OSM\MemCache\Image()
If Zoom=OSM\MemCache\Image()\Zoom And OSM\MemCache\Image()\XTile=XTile And OSM\MemCache\Image()\YTile=YTile
nImage=OSM\MemCache\Image()\nImage
Debug "Load From MEM Tile X : " + Str(XTile) + " ; Tile Y : " + Str(YTile)+" IsImage:"+Str(IsImage(nImage))
Break;
;TODO Find a better way to clean Image in memory
; Clean Image in memory
ElseIf Zoom<>OSM\MemCache\Image()\Zoom
FreeImage(OSM\MemCache\Image()\nImage)
DeleteElement(OSM\MemCache\Image())
ElseIf ( OSM\MemCache\Image()\XTile<OSM\TargetTile\X-5 And OSM\MemCache\Image()\XTile>OSM\TargetTile\X+5 And OSM\MemCache\Image()\YTile<OSM\TargetTile\Y-5 And OSM\MemCache\Image()\YTile>OSM\TargetTile\Y+5 )
FreeImage(OSM\MemCache\Image()\nImage)
DeleteElement(OSM\MemCache\Image())
EndIf
Next
UnlockMutex(OSM\MemCache\Mutex)
ProcedureReturn nImage
EndProcedure
Procedure.i GetTileFromHDD(Zoom.i, XTile.i, YTile.i)
Protected nImage.i
Protected CacheFile.s = "OSM_" + Str(Zoom) + "_" + Str(XTile) + "_" + Str(YTile) + ".png"
If FileSize(OSM\HDDCachePath + cacheFile) > 0
nImage=LoadImage(#PB_Any, OSM\HDDCachePath + CacheFile)
If IsImage(nImage)
Debug "Load From HDD Tile X : " + Str(XTile) + " ; Tile Y : " + Str(YTile)+ "IsImage:"+Str(IsImage(nImage))
AddTileToMemCache(Zoom, XTile, YTile,nImage)
ProcedureReturn nImage
EndIf
EndIf
ProcedureReturn #False
EndProcedure
Procedure.i GetTileFromWeb(Zoom.i, XTile.i, YTile.i)
Protected *Buffer
Protected nImage.i
Protected CacheFile.s = "OSM_" + Str(Zoom) + "_" + Str(XTile) + "_" + Str(YTile) + ".png"
Protected TileURL.s = OSM\ServerURL + Str(Zoom) + "/" + Str(XTile) + "/" + Str(YTile) + ".png"
;Debug "DOWNLOAD : " + psURL
CompilerIf #USEPROXY = #True
Protected http.HTTP_Query
HTTP_proxy(@http, "spxy.bpi.fr", 3128)
HTTP_DownloadToMem(@http, TileURL)
nImage=CatchImage(#PB_Any, http\data, MemorySize(http\data))
If IsImage(nImage)
AddTileToMemCache(Zoom, XTile, YTile,nImage)
SaveImage(nImage, OSM\HDDCachePath + CacheFile, #PB_ImagePlugin_PNG)
Debug "Load From WEB Tile X : " + Str(XTile) + " ; Tile Y : " + Str(YTile)
EndIf
CompilerElse
*Buffer = ReceiveHTTPMemory(TileURL)
If *Buffer
nImage=CatchImage(#PB_Any, *Buffer, MemorySize(*Buffer))
If IsImage(nImage)
AddTileToMemCache(Zoom, XTile, YTile,nImage)
SaveImage(nImage, OSM\HDDCachePath + CacheFile, #PB_ImagePlugin_PNG)
Debug "Load From WEB Tile X : " + Str(XTile) + " ; Tile Y : " + Str(YTile)
FreeMemory(*Buffer)
Else
Debug "Can't catch image :" + TileURL
EndIf
Else
Debug "Problem loading :" + TileURL
EndIf
CompilerEndIf
ProcedureReturn nImage
EndProcedure
Procedure GetTile(*Index.ImgMemCach)
Protected Zoom.i, XTile.i, YTile.i
Zoom=*Index\Zoom
XTile=*Index\XTile
YTile=*Index\YTile
Protected nImage.i
nImage=GetTileFromMem(Zoom, XTile, YTile)
If nImage=0
nImage=GetTileFromHDD(Zoom, XTile, YTile)
If nImage=0
nImage=GetTileFromWeb(Zoom, XTile, YTile)
If nImage=0
Debug "Error GetTile Procedure : can't Load this Tile" ; TODO Check Why !!!
ProcedureReturn #False
EndIf
EndIf
EndIf
*Index\nImage=nImage
SignalSemaphore(OSM\MapImageSemaphore)
EndProcedure
Procedure ThreadConstructMap(z.i)
PostEvent(#EvenementStartRefresh)
Protected x.i, y.i
Protected nx.i = (GadgetWidth(OSM\Gadget)/OSM\TileSize)*2 ;How many tiles
Protected ny.i = (GadgetHeight(OSM\Gadget)/OSM\TileSize)*2
Protected tx.i = Int(OSM\TargetTile\X)
Protected ty.i = Int(OSM\TargetTile\Y)
Protected mx.i=Int(nx/2)
Protected my.i=Int(ny/2)
LockMutex(OSM\MapImageMutex)
For y = 0 To nx
For x = 0 To ny
WaitSemaphore(OSM\MapImageSemaphore)
OSM\MapImage(x,y)\XTile=tx+x-mx
OSM\MapImage(x,y)\YTile=ty+y-my
OSM\MapImage(x,y)\Zoom=OSM\Zoom
Protected th.i
th.i=CreateThread(@GetTile(),@OSM\MapImage(x,y))
Next
Next
UnlockMutex(OSM\MapImageMutex)
WaitThread(th)
PostEvent(#EvenementStopRefresh)
EndProcedure
Procedure ConstructMap()
CreateThread(@ThreadConstructMap(),0)
EndProcedure
Procedure DrawMap()
Static myTimer.i
If myTimer=0 Or ElapsedMilliseconds()-myTimer>250 ;To limit refreash
Protected x.i, y.i, nx.i, ny.i, mx.i, my.i, n.i = 0
Protected deltaX.i, deltaY.i
Protected nImage.i
Protected x2.i, y2.i
LockMutex(OSM\MapImageMutex)
deltaX = OSM\TileSize*(OSM\TargetTile\X - Int(OSM\TargetTile\X))
deltaY = OSM\TileSize*(OSM\TargetTile\Y - Int(OSM\TargetTile\Y))
mx = GadgetWidth(OSM\Gadget)/2
my = GadgetHeight(OSM\Gadget)/2
nx = (GadgetWidth(OSM\Gadget)/OSM\TileSize)*2 ;How many tiles
ny = (GadgetWidth(OSM\Gadget)/OSM\TileSize)*2
StartDrawing(CanvasOutput(OSM\Gadget))
Box(0, 0, GadgetWidth(OSM\Gadget), GadgetHeight(OSM\Gadget), RGB(255, 255, 255))
For y = 0 To nx
For x = 0 To ny
x2 = x*256 + OSM\DeltaCursor\X + mx -deltaX-(nx/2)*OSM\TileSize
y2 = y*256 + OSM\DeltaCursor\Y + my - deltaY-(ny/2)*OSM\TileSize
nImage=OSM\MapImage(x,y)\nImage
If nimage=0
DrawText( x2, y2+20, "Loading")
ElseIf IsImage(nImage) And (x2 + 256) > 0 And (y2 + 256) > 0 And x2 < GadgetWidth(OSM\Gadget) And y2 < GadgetHeight(OSM\Gadget)
DrawImage(ImageID(nImage), x2,y2)
Else
DrawText( x2, y2+20, "Error to Display Image")
EndIf
Next
Next
UnlockMutex(OSM\MapImageMutex)
Circle(GadgetWidth(OSM\Gadget)/2, GadgetHeight(OSM\Gadget)/2, 5, RGB(Random(255),Random(255),Random(255)))
;DrawText(0, 0, "DeltaCursorX : " + Str(OSM\DeltaCursor\X) + " deltaX : " + Str(deltaX) + " Tile X : " + StrD(OSM\TargetTile\X))
DrawText(0, 16, "Image loaded:"+Str(ListSize(OSM\MemCache\Image())))
; Draw Track
Protected Pixel.Pixel
Protected Location.Location
ForEach OSM\track()
If @OSM\TargetLocation\Latitude<>0 And @OSM\TargetLocation\Longitude<>0
getPixelCoorfromLocation(@OSM\track(),@Pixel)
x=Pixel\X
y=Pixel\Y
If x>0 And y>0 And x<GadgetWidth(OSM\Gadget) And y<GadgetHeight(OSM\Gadget)
Circle(x,y,2,#Green)
EndIf
EndIf
Next
StopDrawing()
myTimer=ElapsedMilliseconds()
EndIf
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)
OSM\Position\X = OSM\TargetTile\X * OSM\TileSize ;Convert X, Y in tile.decimal into real pixels
OSM\Position\Y = OSM\TargetTile\Y * OSM\TileSize
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)
OSM\Position\X = OSM\TargetTile\X * OSM\TileSize ;Convert X, Y in tile.decimal into real pixels
OSM\Position\Y = OSM\TargetTile\Y * OSM\TileSize
ConstructMap()
DrawMap()
EndProcedure
Procedure InitOSM()
Debug GetTemporaryDirectory()
OSM\HDDCachePath = GetTemporaryDirectory()
OSM\ServerURL = "http://tile.openstreetmap.org/" ;"https://tile.thunderforest.com/cycle/";
OSM\ZoomMin = 0
OSM\ZoomMax = 18
OSM\StartCursor\X = - 1
OSM\TileSize = 256
OSM\MemCache\Mutex=CreateMutex()
;OSM\MemCache\Semaphore=CreateSemaphore(1)
OSM\MapImageMutex=CreateMutex()
OSM\MapImageSemaphore=CreateSemaphore(8)
OSM\Windows=0
AddWindowTimer(OSM\Windows,1, 500)
EndProcedure
Procedure Event(Event.l)
Protected Gadget.i
Protected tx.d, ty.d
Protected OldX.i, OldY.i
If IsGadget(OSM\Gadget) And GadgetType(OSM\Gadget) = #PB_GadgetType_Canvas
Select Event
Case #EvenementStartRefresh
;Debug "Start"
AddWindowTimer(OSM\Windows,1, 500)
Case #EvenementStopRefresh
;Debug "Stop"
DrawMap()
;RemoveWindowTimer(OSM\Windows, 1)
Case #PB_Event_Timer
If EventTimer()=1;=#Timer_Draw
DrawMap()
EndIf
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
OSM\DeltaCursor\X=GetGadgetAttribute(OSM\Gadget, #PB_Canvas_MouseX)-OSM\StartCursor\X
OSM\DeltaCursor\Y=GetGadgetAttribute(OSM\Gadget, #PB_Canvas_MouseY)-OSM\StartCursor\Y
EndIf
DrawMap()
Case #PB_EventType_LeftButtonUp
DrawMap()
tx=(OSM\DeltaCursor\X/256)
ty=(OSM\DeltaCursor\Y/256)
OSM\DeltaCursor\X=0
OSM\DeltaCursor\Y=0
OSM\StartCursor\X=-1
TileTranslate(@OSM\TargetTile,tx,ty)
XY2LatLon(@OSM\TargetTile,@OSM\TargetLocation)
ConstructMap()
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, 17)
OSM::SetLocation(49.0346374511718750,2.0787782669067383,17)
OSM::ConstructMap()
OSM::DrawMap()
OSM::LoadGpxFile("Roller.gpx")
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
Re: OpenStreetMap dans un Canvas
Non, je vais tester quand je rentre du travail.
Re: OpenStreetMap dans un Canvas
Je pense qu'il ne l'a pas implémenté parce que c'est pour des développements avancés, et que normalement le système devrait le prendre en compte. Et puis, maintenant, on peut intégrer directement les fonctions de curl dans le code sans dll, alors on aurait tort de s'en priver, d'autant que ça va beaucoup plus loin...
Re: OpenStreetMap dans un Canvas
Je n'ai pas pu bosser encore comme je le voulais, voici un WIP de débogage, où j'ai mélangé nos deux codes. Le threading est plus ou moins désactivé, j'étais en train d'essayer de comprendre pourquoi j'ai un affichage avant le chargement et pourquoi l'affichage n'affiche rien.
Code : Tout sélectionner
;**************************************************************
; Program: OSM (OpenStreetMap Module)
; Author: Thyphoon And Djes
; Date: Mai 17, 2016
; License: Free, unrestricted, credit appreciated
; but not required.
; Note: Please share improvement !
; Thanks: Progi1984,
;**************************************************************
CompilerIf #PB_Compiler_Thread = #False
MessageRequester("Warning !!","You must enable ThreadSafe support in compiler options",#PB_MessageRequester_Ok )
End
CompilerEndIf
EnableExplicit
InitNetwork()
UsePNGImageDecoder()
UsePNGImageEncoder()
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 ConstructMap()
Declare DrawMap()
Declare SetZoom(Zoom.i, mode.i = #PB_Relative)
Declare LoadGpxFile(file.s);
EndDeclareModule
Module OSM
#USEPROXY = #False
CompilerIf #USEPROXY = #True
; IncludeFile("C : \Users\lebrun_y_413\Documents\Developpement\Purebasic\includes Share\http.pbi")
Global ProxyURL$ = "";InputRequester("ProxyServer", "Do you use a Proxy Server? Then enter the full url:", "")
Global ProxyPort$ = "";InputRequester("ProxyPort" , "Do you use a specific port? Then enter it", "")
Global ProxyUser$ = "";InputRequester("ProxyUser" , "Do you use a user name? Then enter it", "")
Global ProxyPassword$ = InputRequester("ProxyPass" , "Do you use a password? Then enter it:", "")
IncludeFile("ReceiveHTTPToMemory.pbi")
CompilerEndIf
Structure Location
Longitude.d
Latitude.d
EndStructure
Structure Tile
X.d
Y.d
EndStructure
Structure Pixel
X.i
Y.i
EndStructure
Structure ImgMemCach
nImage.i
Zoom.i
XTile.i
YTile.i
EndStructure
Structure TileMemCach
List Image.ImgMemCach()
Mutex.i
Semaphore.i
EndStructure
Structure OSM
Gadget.i ; Canvas Gadget Id
TargetLocation.Location ; Latitude and Longitude from focus point
TargetTile.Tile ; Focus Tile coord
Position.Pixel ; Actual focus Point coords in pixels
StartCursor.Pixel ; Start mouse position coords when dragging the map
ServerURL.s ; Web URL ex: http://tile.openstreetmap.org/
ZoomMin.i ; Min Zoom supported by server
ZoomMax.i ; Max Zoom supported by server
Zoom.i ; Current zoom
TileSize.i ; Tile size downloaded on the server ex : 256
HDDCachePath.S ; Path where to load and save tiles downloaded from server
MemCache.TileMemCach ; Image in memory cache
List MapImageIndex.ImgMemCach() ; Index from MemCache\Image() to construct map
MapImageMutex.i ; Mutex to lock
MapImageSemaphore.i ; Semaphore to control Thread
List track.Location() ;to display a GPX track
EndStructure
Global OSM.OSM
Procedure InitOSM()
OSM\HDDCachePath = GetTemporaryDirectory()
OSM\ServerURL = "http://tile.openstreetmap.org/"
OSM\ZoomMin = 0
OSM\ZoomMax = 18
OSM\StartCursor\X = - 1
OSM\TileSize = 256
OSM\MemCache\Mutex = CreateMutex()
;OSM\MemCache\Semaphore = CreateSemaphore(1)
OSM\MapImageMutex = CreateMutex()
OSM\MapImageSemaphore = CreateSemaphore(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 getPixelCoorfromLocation(*Location.Location, *Pixel.Pixel) ; TODO to Optimize
Protected mapWidth.l = Pow(2,OSM\Zoom+8)
Protected mapHeight.l = Pow(2,OSM\Zoom+8)
Protected x1.l,y1.l
Protected deltaX = OSM\Position\X - Int(OSM\TargetTile\X) * OSM\TileSize ;Get the position into the tile
Protected deltaY = OSM\Position\Y - Int(OSM\TargetTile\Y) * OSM\TileSize
; get x value
x1 = (*Location\Longitude+180)*(mapWidth/360)
; convert from degrees To radians
Protected latRad.d = *Location\Latitude*#PI/180;
Protected mercN.d = Log(Tan((#PI/4)+(latRad/2)));
y1 = (mapHeight/2)-(mapWidth*mercN/(2*#PI)) ;
Protected x2.l, y2.l
; get x value
x2 = (OSM\TargetLocation\Longitude+180)*(mapWidth/360)
; convert from degrees To radians
latRad = OSM\TargetLocation\Latitude*#PI/180;
; get y value
mercN = Log(Tan((#PI/4)+(latRad/2))) ;
y2 = (mapHeight/2)-(mapWidth*mercN/(2*#PI));
*Pixel\X=GadgetWidth(OSM\Gadget)/2 - (x2-x1) + deltaX
*Pixel\Y=GadgetHeight(OSM\Gadget)/2 - (y2-y1) + deltaY
EndProcedure
Procedure LoadGpxFile(file.s)
If LoadXML(0, file.s)
Protected Message.s
If XMLStatus(0) <> #PB_XML_Success
Message = "Error in the XML file:" + Chr(13)
Message + "Message: " + XMLError(0) + Chr(13)
Message + "Line: " + Str(XMLErrorLine(0)) + " Character: " + Str(XMLErrorPosition(0))
MessageRequester("Error", Message)
EndIf
Protected *MainNode,*subNode,*child,child.l
*MainNode=MainXMLNode(0)
*MainNode=XMLNodeFromPath(*MainNode,"/gpx/trk/trkseg")
ClearList(OSM\track())
For child = 1 To XMLChildCount(*MainNode)
*child = ChildXMLNode(*MainNode, child)
AddElement(OSM\track())
If ExamineXMLAttributes(*child)
While NextXMLAttribute(*child)
Select XMLAttributeName(*child)
Case "lat"
OSM\track()\Latitude=ValD(XMLAttributeValue(*child))
Case "lon"
OSM\track()\Longitude=ValD(XMLAttributeValue(*child))
EndSelect
Wend
EndIf
Next
EndIf
EndProcedure
Procedure AddTileToMemCache(Zoom.i, XTile.i, YTile.i, nImage.i)
Protected Index.i
If IsImage(nImage)
Debug "Adding tile " + Str(nImage) + " to mem cache"
LockMutex(OSM\MemCache\Mutex)
;Add to the list
;FirstElement(OSM\MemCache\Image())
AddElement(OSM\MemCache\Image())
;Index = ListIndex(OSM\MemCache\Image())
OSM\MemCache\Image()\XTile = XTile
OSM\MemCache\Image()\YTile = YTile
OSM\MemCache\Image()\Zoom = Zoom
OSM\MemCache\Image()\nImage = nImage
UnlockMutex(OSM\MemCache\Mutex)
;ProcedureReturn Index
Else
Debug "Tile not added to mem cache"
EndIf
EndProcedure
Procedure.i GetTileFromMem(Zoom.i, XTile.i, YTile.i)
Protected nImage.i
LockMutex(OSM\MemCache\Mutex)
;Check if we have this Image in Memory
ForEach OSM\MemCache\Image()
If Zoom = OSM\MemCache\Image()\Zoom And OSM\MemCache\Image()\XTile = XTile And OSM\MemCache\Image()\YTile = YTile And OSM\MemCache\Image()\nImage > 0
nImage = OSM\MemCache\Image()\nImage
Debug "Load from MEM Tile X : " + Str(XTile) + " ; Tile Y : " + Str(YTile) + " nImage:" + Str(nImage)
Break;
ElseIf Zoom<>OSM\MemCache\Image()\Zoom
; DeleteElement(OSM\MemCache\Image())
EndIf
Next
UnlockMutex(OSM\MemCache\Mutex)
ProcedureReturn nImage
EndProcedure
Procedure.i GetTileFromHDD(Zoom.i, XTile.i, YTile.i)
Protected nImage.i
Protected CacheFile.s = "OSM_" + Str(Zoom) + "_" + Str(XTile) + "_" + Str(YTile) + ".png"
If FileSize(OSM\HDDCachePath + cacheFile) > 0
nImage=LoadImage(#PB_Any, OSM\HDDCachePath + CacheFile)
If IsImage(nImage)
Debug "Load from HDD Tile X : " + Str(XTile) + " ; Tile Y : " + Str(YTile) + " nImage:" + Str(nImage)
AddTileToMemCache(Zoom, XTile, YTile, nImage)
ProcedureReturn nImage
EndIf
EndIf
ProcedureReturn #False
EndProcedure
Procedure.i GetTileFromWeb(Zoom.i, XTile.i, YTile.i)
Protected *Buffer
Protected nImage.i
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"
CompilerIf #USEPROXY = #True
*Buffer = ReceiveHTTPToMemory(TileURL, ProxyURL$, ProxyPort$, ProxyUser$, ProxyPassword$)
CompilerElse
*Buffer = ReceiveHTTPMemory(TileURL) ;TODO to thread by using #PB_HTTP_Asynchronous
CompilerEndIf
If *Buffer
nImage = CatchImage(#PB_Any, *Buffer, MemorySize(*Buffer))
If nImage > 0
Debug "Loaded from web " + TileURL + " as Tile nb " + nImage
AddTileToMemCache(Zoom, XTile, YTile, nImage)
SaveImage(nImage, OSM\HDDCachePath + CacheFile, #PB_ImagePlugin_PNG)
FreeMemory(*Buffer)
Else
Debug "Can't catch image " + TileURL
;ShowMemoryViewer(*Buffer, MemorySize(*Buffer))
;CallDebugger
EndIf
Else
Debug "Problem loading from web " + TileURL
EndIf
ProcedureReturn nImage
EndProcedure
Procedure GetTile(*ptr)
Protected Zoom.i, XTile.i, YTile.i
Protected nImage.i
LockMutex(OSM\MapImageMutex)
ChangeCurrentElement(OSM\MapImageIndex(), *ptr)
Zoom = OSM\MapImageIndex()\Zoom
XTile = OSM\MapImageIndex()\XTile
YTile = OSM\MapImageIndex()\YTile
;UnlockMutex(OSM\MapImageMutex)
nImage = GetTileFromMem(Zoom, XTile, YTile)
If nImage = 0
nImage = GetTileFromHDD(Zoom, XTile, YTile)
If nImage = 0
nImage = GetTileFromWeb(Zoom, XTile, YTile)
If nImage = 0
Debug "Error GetTile procedure : can't load this tile" + Str(XTile) + " Y " + Str(YTile) + " Zoom "+Str(Zoom)
ProcedureReturn #False
EndIf
EndIf
EndIf
;LockMutex(OSM\MapImageMutex)
If ChangeCurrentElement(OSM\MapImageIndex(), *ptr)
OSM\MapImageIndex()\nImage = nImage
Else
Debug "Error GetTile procedure : list doesn't have current element" ; TODO Check Why !!!
EndIf
UnlockMutex(OSM\MapImageMutex)
;SignalSemaphore(OSM\MapImageSemaphore)
EndProcedure
Procedure ThreadConstructMap(z.i)
Protected x.i, y.i
Protected Index.i
Protected CenterX = GadgetWidth(OSM\Gadget) / 2
Protected CenterY = GadgetHeight(OSM\Gadget) / 2
Protected nx = CenterX / OSM\TileSize ;How many tiles around the point
Protected ny = CenterY / OSM\TileSize
Protected tx = Int(OSM\TargetTile\X) ;Don't forget the Int() !
Protected ty = Int(OSM\TargetTile\Y)
LockMutex(OSM\MapImageMutex)
ClearList(OSM\MapImageIndex())
Debug " Constructing"
For y = ty - ny To ty + ny
For x = tx - nx To tx + nx
;WaitSemaphore(OSM\MapImageSemaphore)
;LockMutex(OSM\MapImageMutex)
LastElement(OSM\MapImageIndex())
AddElement(OSM\MapImageIndex())
OSM\MapImageIndex()\XTile = x
OSM\MapImageIndex()\YTile = y
OSM\MapImageIndex()\Zoom = OSM\Zoom
;UnlockMutex(OSM\MapImageMutex)
CreateThread(@GetTile(), @OSM\MapImageIndex())
Next
Next
UnlockMutex(OSM\MapImageMutex)
EndProcedure
Procedure ConstructMap()
; CreateThread(@ThreadConstructMap(), 0)
ThreadConstructMap(0)
EndProcedure
Procedure DrawMap()
Protected x.i, y.i, nx.i, ny.i, CenterX.i, CenterY.i, n.i = 0
Protected deltaX.i, deltaY.i
Protected x2.i, y2.i
deltaX = OSM\Position\X - Int(OSM\TargetTile\X) * OSM\TileSize ;Get the position into the tile
deltaY = OSM\Position\Y - Int(OSM\TargetTile\Y) * OSM\TileSize
CenterX = GadgetWidth(OSM\Gadget) / 2
CenterY = GadgetHeight(OSM\Gadget) / 2
nx = CenterX / OSM\TileSize ;How many tiles around the point
ny = CenterY / OSM\TileSize
LockMutex(OSM\MapImageMutex)
ResetList(OSM\MapImageIndex())
StartDrawing(CanvasOutput(OSM\Gadget))
Box(0, 0, GadgetWidth(OSM\Gadget), GadgetHeight(OSM\Gadget), RGB(255, 255, 255))
Debug " Drawing"
For y = - ny To ny
For x = - nx To nx
If NextElement(OSM\MapImageIndex())
x2 = CenterX - deltaX + x * OSM\TileSize
y2 = CenterY - deltaY + y * OSM\TileSize
nImage = OSM\MapImageIndex()\nImage
If IsImage(nImage)
DrawImage(ImageID(nImage), x2, y2)
DrawText( x2, y2, Str(x) + ", " + Str(y))
Else
;No image
Box(x2, y2, OSM\TileSize, OSM\TileSize, RGB($EE, $EE, $EE))
Line(x2, y2, OSM\TileSize, OSM\TileSize, RGB($AA, $AA, $AA))
Line(x2, y2 + OSM\TileSize, OSM\TileSize, -OSM\TileSize, RGB($AA, $AA, $AA))
DrawText(x2 + OSM\TileSize / 2 - TextWidth("Loading")/2, y2 + OSM\TileSize / 2 - TextHeight("Loading") / 2, "Loading", RGB($AA, $AA, $AA), RGB($EE, $EE, $EE))
EndIf
;n = n + 1
Else
Debug" Error, no next element"
Break 2
EndIf
Next
Next
Circle(CenterX, CenterY, 5, #Red)
UnlockMutex(OSM\MapImageMutex)
; Draw Track
Protected Pixel.Pixel
Protected Location.Location
n=0;
ForEach OSM\track()
n=n+1
If @OSM\TargetLocation\Latitude<>0 And @OSM\TargetLocation\Longitude<>0
getPixelCoorfromLocation(@OSM\track(),@Pixel)
x=Pixel\X
y=Pixel\Y
If x>0 And y>0 And x<GadgetWidth(OSM\Gadget) And y<GadgetHeight(OSM\Gadget)
Circle(x,y,2,#Green)
EndIf
EndIf
Next
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)
OSM\Position\X = OSM\TargetTile\X * OSM\TileSize ;Convert X, Y in tile.decimal into real pixels
OSM\Position\Y = OSM\TargetTile\Y * OSM\TileSize
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)
OSM\Position\X = OSM\TargetTile\X * OSM\TileSize ;Convert X, Y in tile.decimal into real pixels
OSM\Position\Y = OSM\TargetTile\Y * OSM\TileSize
ConstructMap()
DrawMap()
EndProcedure
Procedure Event(Event.l)
Protected Gadget.i
Protected tx.i, ty.i
Protected OldX.i, OldY.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
ty = GetGadgetAttribute(OSM\Gadget, #PB_Canvas_MouseY) - OSM\StartCursor\Y
OldX = OSM\Position\X : OldY = OSM\Position\Y
OSM\Position\X - tx
OSM\Position\Y - ty
;Moved to a new tile ?
If (OSM\Position\X / OSM\TileSize) <> (OldX / OSM\TileSize) Or (OSM\Position\Y / OSM\TileSize) <> (OldY / OSM\TileSize)
Debug "--- New tile"
OSM\TargetTile\X = OSM\Position\X / OSM\TileSize
OSM\TargetTile\Y = OSM\Position\Y / OSM\TileSize
Debug "OSM\Position\X " + Str(OSM\Position\X) + " ; OSM\Position\Y " + Str(OSM\Position\Y)
XY2LatLon(@OSM\TargetTile, @OSM\TargetLocation)
Debug "OSM\TargetTile\X " + StrD(OSM\TargetTile\X) + " ; OSM\TargetTile\Y " + StrD(OSM\TargetTile\Y)
ConstructMap()
EndIf
DrawMap()
OSM\StartCursor\X = GetGadgetAttribute(OSM\Gadget, #PB_Canvas_MouseX)
OSM\StartCursor\Y = GetGadgetAttribute(OSM\Gadget, #PB_Canvas_MouseY)
EndIf
Case #PB_EventType_LeftButtonUp
OSM\StartCursor\X = - 1
OSM\TargetTile\X = OSM\Position\X / OSM\TileSize
OSM\TargetTile\Y = OSM\Position\Y / OSM\TileSize
Debug "OSM\Position\X " + Str(OSM\Position\X) + " ; OSM\Position\Y " + Str(OSM\Position\Y)
XY2LatLon(@OSM\TargetTile, @OSM\TargetLocation)
Debug "OSM\TargetTile\X " + StrD(OSM\TargetTile\X) + " ; OSM\TargetTile\Y " + StrD(OSM\TargetTile\Y)
;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, 17)
OSM::ConstructMap()
Delay(1000)
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
Re: OpenStreetMap dans un Canvas
C'est prometteur ^_^ Je pars demain matin pour 3 jours je sais pas si j'aurais beaucoup de temps mais j'essayerai d'avancer sur des petits trucs en attendant. et j'éspère bien dimanche avoir du temps. On a quand bien bien avancé on est plus très loindjes a écrit :Je n'ai pas pu bosser encore comme je le voulais, voici un WIP de débogage, où j'ai mélangé nos deux codes. Le threading est plus ou moins désactivé, j'étais en train d'essayer de comprendre pourquoi j'ai un affichage avant le chargement et pourquoi l'affichage n'affiche rien.

Re: OpenStreetMap dans un Canvas
Ouais c'est kler que vous avez bien bossé. Dommage qu'on ne trouve pas en natif un MapGadget() en natif a PB qui utilise OpenStreetMap.
Re: OpenStreetMap dans un Canvas
le but ici est d'essayer de donné un MapGadget le plus simple possible a utiliser. Et on est en bonne voit !! ^_^MetalOS a écrit :Ouais c'est kler que vous avez bien bossé. Dommage qu'on ne trouve pas en natif un MapGadget() en natif a PB qui utilise OpenStreetMap.
Re: OpenStreetMap dans un Canvas
Je ne sais pas si j'aurai le temps de coder ces jours-ci, en tous cas dans la tête oui. Prochaine étape, virer le drawmap (ou plutôt, le fusionner avec le constructmap), créer une liste des choses à dessiner (liste effacée en cas de déplacement), et faire le dessin en threadé (avec la gestion du chargement en threadé idem).
Re: OpenStreetMap dans un Canvas
Pas beaucoup de temps ce week-end moi aussidjes a écrit :Je ne sais pas si j'aurai le temps de coder ces jours-ci, en tous cas dans la tête oui. Prochaine étape, virer le drawmap (ou plutôt, le fusionner avec le constructmap), créer une liste des choses à dessiner (liste effacée en cas de déplacement), et faire le dessin en threadé (avec la gestion du chargement en threadé idem).


Mais j'ai quand même eu le temps de faire cette fonction qui permet de centrer la carte sur un ensemble de point. Il y a encore une erreur sur le calcul du zoom mais je suis pas loin...

Edit: C'est bon fonction mis à jour ça marche super ^_^
Code : Tout sélectionner
Macro Min(a,b)
(Bool((a) <= (b)) * (a) + Bool((b) < (a)) * (b))
EndMacro
Macro Max(a,b)
(Bool((a) >= (b)) * (a) + Bool((b) > (a)) * (b))
EndMacro
Procedure ZoomToArea()
;Source => http://gis.stackexchange.com/questions/19632/how-to-calculate-the-optimal-zoom-level-to-display-two-or-more-points-on-a-map
;bounding box in long/lat coords (x=long, y=lat)
Protected MinY.d,MaxY.d,MinX.d,MaxX.d
ForEach OSM\track()
If ListIndex(OSM\track())=0 Or OSM\track()\Longitude<MinX
MinX=OSM\track()\Longitude
EndIf
If ListIndex(OSM\track())=0 Or OSM\track()\Longitude>MaxX
MaxX=OSM\track()\Longitude
EndIf
If ListIndex(OSM\track())=0 Or OSM\track()\Latitude<MinY
MinY=OSM\track()\Latitude
EndIf
If ListIndex(OSM\track())=0 Or OSM\track()\Latitude>MaxY
MaxY=OSM\track()\Latitude
EndIf
Next
Protected DeltaX.d=MaxX-MinX ;assumption ! In original code DeltaX have no source
Protected centerX.d=MinX+DeltaX/2 ; assumption ! In original code CenterX have no source
Protected paddingFactor.f= 1.2 ;paddingFactor: this can be used to get the "120%" effect ThomM refers to. Value of 1.2 would get you the 120%.
ry1.d = Log((Sin(Radian(MinY)) + 1) / Cos(Radian(MinY)));
ry2.d = Log((Sin(Radian(MaxY)) + 1) / Cos(Radian(MaxY)));
ryc.d = (ry1 + ry2) / 2;
centerY.d = Degree(ATan(SinH(ryc)));
resolutionHorizontal.d = DeltaX / GadgetWidth(OSM\Gadget);
vy0.d = Log(Tan(#PI*(0.25 + centerY/360)));
vy1.d = Log(Tan(#PI*(0.25 + MaxY/360)));
viewHeightHalf.d = GadgetHeight(OSM\Gadget)/2;
zoomFactorPowered.d = viewHeightHalf / (40.7436654315252*(vy1 - vy0));
resolutionVertical.d = 360.0 / (zoomFactorPowered * OSM\TileSize);
resolution.d = Max(resolutionHorizontal, resolutionVertical)* paddingFactor;
zoom.d = Log(360 / (resolution * OSM\TileSize))/Log(2)
lon.d = centerX;
lat.d = centerY;
Debug "lat:"+StrD(lat)
Debug "lon:"+StrD(lon)
Debug "zoom:"+StrD(zoom)
SetLocation(lat,lon, Round(zoom,#PB_Round_Up))
EndProcedure
Re: OpenStreetMap dans un Canvas
Je vais regarder après. Sinon pour la fusion, oui, je pense que c'est la voie à suivre pour mieux séparer le chargement de l'affichage. En gros, le maître est l'utilisateur (thread principal)->calcul des tuiles à afficher->les tuiles sont indépendantes autant en chargement qu'en affichage (un thread par tuile qui peut s'arrêter si l'utilisateur bouge). Je m'en occupe dès que j'ai un peu de temps 

Re: OpenStreetMap dans un Canvas
ça marchedjes a écrit :Je vais regarder après. Sinon pour la fusion, oui, je pense que c'est la voie à suivre pour mieux séparer le chargement de l'affichage. En gros, le maître est l'utilisateur (thread principal)->calcul des tuiles à afficher->les tuiles sont indépendantes autant en chargement qu'en affichage (un thread par tuile qui peut s'arrêter si l'utilisateur bouge). Je m'en occupe dès que j'ai un peu de temps


si ça t'amuse voilà mon dernier code. Je n'ai pas retouché a la partie affichage je te laisse cette partie.
Code : Tout sélectionner
;**************************************************************
; Program: OSM (OpenStreetMap Module)
; Author: Thyphoon And Djes
; Date: Mai 17, 2016
; License: Free, unrestricted, credit appreciated
; but not required.
; Note: Please share improvement !
; Thanks: Progi1984 for the first OSM implementation
; Fred, Freak and all people who made purebasic what is it !
;**************************************************************
InitNetwork()
CompilerIf #PB_Compiler_Thread=0
MessageRequester("Warning !!","You must to Enable 'create ThreadSafe' in compiler option",#PB_MessageRequester_Ok )
End
CompilerEndIf
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 SetZoom(Zoom.i, mode.i = #PB_Relative)
Declare LoadGpxFile(file.s);
Declare ZoomToArea()
Declare ConstructMap()
Declare DrawMap()
EndDeclareModule
Module OSM
#USEPROXY = #False
UsePNGImageDecoder()
UsePNGImageEncoder()
Enumeration #PB_Event_FirstCustomValue
#EvenementStartRefresh
#EvenementStopRefresh
EndEnumeration
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.d
Y.d
EndStructure
Structure Pixel
X.i
Y.i
EndStructure
Structure ImgMemCach
nImage.i
Zoom.i
XTile.i
YTile.i
EndStructure
Structure TileMemCach
List Image.ImgMemCach()
Mutex.i
Semaphore.i
EndStructure
Structure OSM
Windows.i ;
Gadget.i ; Canvas Gadget Id
TargetLocation.Location ; Latitude and Longitude from focus point
TargetTile.Tile ; Focus Tile coord
Position.Pixel ; Focus Point coord in Pixel
ServerURL.s ; Web Url ex: http://tile.openstreetmap.org/
ZoomMin.i ; Min Zoom supported by Server
ZoomMax.i ; Max Zoom supported by Server
Zoom.i ; Current Zoom
TileSize.i ; Tile Size downloaded on the server ex : 256
HDDCachePath.S ; path where to load an save tile downloaded from server
MemCache.TileMemCach ; to know image always in memory
; List MapImageIndex.ImgMemCach() ; List of Index from MemCache\Image() to construct map
Array MapImage.ImgMemCach(16,16)
MapImageMutex.i ; Mutex to lock
MapImageSemaphore.i ; Semaphore to control Thread
StartCursor.Pixel ; coord from start drag the map
DeltaCursor.Pixel ; delta from curent position and the start position
List track.Location() ;to display a track GPX on card
EndStructure
Global OSM.OSM
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 getPixelCoorfromLocation(*Location.Location,*Pixel.Pixel) ; TODO to Optimize
Protected mapWidth.l = Pow(2,OSM\Zoom+8)
Protected mapHeight.l = Pow(2,OSM\Zoom+8)
Protected x1.l,y1.l
; get x value
x1 = (*Location\Longitude+180)*(mapWidth/360)
; convert from degrees To radians
Protected latRad.d = *Location\Latitude*#PI/180;
Protected mercN.d = Log(Tan((#PI/4)+(latRad/2)));
y1 = (mapHeight/2)-(mapWidth*mercN/(2*#PI)) ;
Protected x2.l,y2.l
; get x value
x2 = (OSM\TargetLocation\Longitude+180)*(mapWidth/360)
; convert from degrees To radians
latRad = OSM\TargetLocation\Latitude*#PI/180;
; get y value
mercN = Log(Tan((#PI/4)+(latRad/2))) ;
y2 = (mapHeight/2)-(mapWidth*mercN/(2*#PI));
*Pixel\X=GadgetWidth(OSM\Gadget)/2-(x2-x1)+ OSM\DeltaCursor\X
*Pixel\Y=GadgetHeight(OSM\Gadget)/2-(y2-y1)+ OSM\DeltaCursor\Y
EndProcedure
Procedure distance(*posA.Location,*posB.Location)
Protected R.l = 6371; // km
Protected dLat.d = Radian(*posB\Latitude-*posA\Latitude);
Protected dLon.d = Radian(*posB\Longitude-*posA\Longitude)
Protected lat1.d = Radian(*posA\Latitude);
Protected lat2.d = Radian(*posB\Latitude);
Protected a.d = Sin(dLat/2) * Sin(dLat/2) + Sin(dLon/2) * Sin(dLon/2) * Cos(lat1) * Cos(lat2);
Protected c.d = 2 * ATan2(Sqr(a), Sqr(1-a));
Protected distance.d = R * c ;
ProcedureReturn distance
EndProcedure
; HaversineAlgorithm
Procedure.d HaversineInKM(*posA.Location,*posB.Location)
Static eQuatorialEarthRadius.d = 6378.1370;
Protected dlong.d = Radian(*posB\Longitude - *posA\Longitude);
Protected dlat.d = Radian(*posB\Latitude - *posA\Latitude);
Protected a.d = Pow(Sin(dlat / 2), 2) + Cos(Radian(*posA\Latitude)) * Cos(Radian(*posB\Latitude))* Pow(Sin(dlong / 2), 2);
Protected c.d = 2 * ATan2(Sqr(a), Sqr(1 - a));
Protected didstance.d = eQuatorialEarthRadius * c;
ProcedureReturn d;
EndProcedure
Procedure.d HaversineInM(*posA.Location,*posB.Location)
ProcedureReturn (1000 * HaversineInKM(@*posA,@*posB));
EndProcedure
Procedure LoadGpxFile(file.s)
If LoadXML(0, file.s)
Protected Message.s
If XMLStatus(0) <> #PB_XML_Success
Message = "Error in the XML file:" + Chr(13)
Message + "Message: " + XMLError(0) + Chr(13)
Message + "Line: " + Str(XMLErrorLine(0)) + " Character: " + Str(XMLErrorPosition(0))
MessageRequester("Error", Message)
EndIf
Protected *MainNode,*subNode,*child,child.l
*MainNode=MainXMLNode(0)
*MainNode=XMLNodeFromPath(*MainNode,"/gpx/trk/trkseg")
ClearList(OSM\track())
For child = 1 To XMLChildCount(*MainNode)
*child = ChildXMLNode(*MainNode, child)
AddElement(OSM\track())
If ExamineXMLAttributes(*child)
While NextXMLAttribute(*child)
Select XMLAttributeName(*child)
Case "lat"
OSM\track()\Latitude=ValD(XMLAttributeValue(*child))
Case "lon"
OSM\track()\Longitude=ValD(XMLAttributeValue(*child))
EndSelect
Wend
EndIf
Next
EndIf
EndProcedure
Procedure AddTileToMemCache(Zoom.i, XTile.i, YTile.i,nImage.i)
Protected Index.i
If IsImage(nImage)
LockMutex(OSM\MemCache\Mutex)
;We add To the List And load it
FirstElement(OSM\MemCache\Image())
AddElement(OSM\MemCache\Image())
Index=ListIndex(OSM\MemCache\Image())
OSM\MemCache\Image()\XTile=XTile
OSM\MemCache\Image()\YTile=YTile
OSM\MemCache\Image()\Zoom=Zoom
OSM\MemCache\Image()\nImage=nImage
UnlockMutex(OSM\MemCache\Mutex)
ProcedureReturn Index
Else
Debug "NO ADD TILE TO MEM CACHE BECAUSE BAD IMAGE"
EndIf
EndProcedure
Procedure.i GetTileFromMem(Zoom.i, XTile.i, YTile.i)
Protected nImage.i
LockMutex(OSM\MemCache\Mutex)
;Check if we have this Image in Memory
ForEach OSM\MemCache\Image()
If Zoom=OSM\MemCache\Image()\Zoom And OSM\MemCache\Image()\XTile=XTile And OSM\MemCache\Image()\YTile=YTile
nImage=OSM\MemCache\Image()\nImage
Debug "Load From MEM Tile X : " + Str(XTile) + " ; Tile Y : " + Str(YTile)+" IsImage:"+Str(IsImage(nImage))
Break;
;TODO Find a better way to clean Image in memory
; Clean Image in memory
ElseIf Zoom<>OSM\MemCache\Image()\Zoom
FreeImage(OSM\MemCache\Image()\nImage)
DeleteElement(OSM\MemCache\Image())
ElseIf ( OSM\MemCache\Image()\XTile<OSM\TargetTile\X-5 And OSM\MemCache\Image()\XTile>OSM\TargetTile\X+5 And OSM\MemCache\Image()\YTile<OSM\TargetTile\Y-5 And OSM\MemCache\Image()\YTile>OSM\TargetTile\Y+5 )
FreeImage(OSM\MemCache\Image()\nImage)
DeleteElement(OSM\MemCache\Image())
EndIf
Next
UnlockMutex(OSM\MemCache\Mutex)
ProcedureReturn nImage
EndProcedure
Procedure.i GetTileFromHDD(Zoom.i, XTile.i, YTile.i)
Protected nImage.i
Protected CacheFile.s = "OSM_" + Str(Zoom) + "_" + Str(XTile) + "_" + Str(YTile) + ".png"
If FileSize(OSM\HDDCachePath + cacheFile) > 0
nImage=LoadImage(#PB_Any, OSM\HDDCachePath + CacheFile)
If IsImage(nImage)
Debug "Load From HDD Tile X : " + Str(XTile) + " ; Tile Y : " + Str(YTile)+ "IsImage:"+Str(IsImage(nImage))
AddTileToMemCache(Zoom, XTile, YTile,nImage)
ProcedureReturn nImage
EndIf
EndIf
ProcedureReturn #False
EndProcedure
Procedure.i GetTileFromWeb(Zoom.i, XTile.i, YTile.i)
Protected *Buffer
Protected nImage.i
Protected CacheFile.s = "OSM_" + Str(Zoom) + "_" + Str(XTile) + "_" + Str(YTile) + ".png"
Protected TileURL.s = OSM\ServerURL + Str(Zoom) + "/" + Str(XTile) + "/" + Str(YTile) + ".png"
;Debug "DOWNLOAD : " + psURL
CompilerIf #USEPROXY = #True
Protected http.HTTP_Query
HTTP_proxy(@http, "spxy.bpi.fr", 3128)
HTTP_DownloadToMem(@http, TileURL)
nImage=CatchImage(#PB_Any, http\data, MemorySize(http\data))
If IsImage(nImage)
AddTileToMemCache(Zoom, XTile, YTile,nImage)
SaveImage(nImage, OSM\HDDCachePath + CacheFile, #PB_ImagePlugin_PNG)
Debug "Load From WEB Tile X : " + Str(XTile) + " ; Tile Y : " + Str(YTile)
EndIf
CompilerElse
*Buffer = ReceiveHTTPMemory(TileURL)
If *Buffer
nImage=CatchImage(#PB_Any, *Buffer, MemorySize(*Buffer))
If IsImage(nImage)
AddTileToMemCache(Zoom, XTile, YTile,nImage)
SaveImage(nImage, OSM\HDDCachePath + CacheFile, #PB_ImagePlugin_PNG)
Debug "Load From WEB Tile X : " + Str(XTile) + " ; Tile Y : " + Str(YTile)
FreeMemory(*Buffer)
Else
Debug "Can't catch image :" + TileURL
EndIf
Else
Debug "Problem loading :" + TileURL
EndIf
CompilerEndIf
ProcedureReturn nImage
EndProcedure
Procedure GetTile(*Index.ImgMemCach)
Protected Zoom.i, XTile.i, YTile.i
Zoom=*Index\Zoom
XTile=*Index\XTile
YTile=*Index\YTile
Protected nImage.i
nImage=GetTileFromMem(Zoom, XTile, YTile)
If nImage=0
nImage=GetTileFromHDD(Zoom, XTile, YTile)
If nImage=0
nImage=GetTileFromWeb(Zoom, XTile, YTile)
If nImage=0
Debug "Error GetTile Procedure : can't Load this Tile" ; TODO Check Why !!!
ProcedureReturn #False
EndIf
EndIf
EndIf
*Index\nImage=nImage
SignalSemaphore(OSM\MapImageSemaphore)
EndProcedure
Procedure ThreadConstructMap(z.i)
PostEvent(#EvenementStartRefresh)
Protected x.i, y.i
Protected nx.i = (GadgetWidth(OSM\Gadget)/OSM\TileSize)*2 ;How many tiles
Protected ny.i = (GadgetHeight(OSM\Gadget)/OSM\TileSize)*2
Protected tx.i = Int(OSM\TargetTile\X)
Protected ty.i = Int(OSM\TargetTile\Y)
Protected mx.i=Int(nx/2)
Protected my.i=Int(ny/2)
LockMutex(OSM\MapImageMutex)
For y = 0 To nx
For x = 0 To ny
WaitSemaphore(OSM\MapImageSemaphore)
OSM\MapImage(x,y)\XTile=tx+x-mx
OSM\MapImage(x,y)\YTile=ty+y-my
OSM\MapImage(x,y)\Zoom=OSM\Zoom
Protected th.i
th.i=CreateThread(@GetTile(),@OSM\MapImage(x,y))
Next
Next
UnlockMutex(OSM\MapImageMutex)
WaitThread(th)
PostEvent(#EvenementStopRefresh)
EndProcedure
Procedure ConstructMap()
CreateThread(@ThreadConstructMap(),0)
EndProcedure
Procedure DrawMap()
Static myTimer.i
If myTimer=0 Or ElapsedMilliseconds()-myTimer>250 ;To limit refreash
Protected x.i, y.i, nx.i, ny.i, mx.i, my.i, n.i = 0
Protected deltaX.i, deltaY.i
Protected nImage.i
Protected x2.i, y2.i
LockMutex(OSM\MapImageMutex)
deltaX = OSM\TileSize*(OSM\TargetTile\X - Int(OSM\TargetTile\X))
deltaY = OSM\TileSize*(OSM\TargetTile\Y - Int(OSM\TargetTile\Y))
mx = GadgetWidth(OSM\Gadget)/2
my = GadgetHeight(OSM\Gadget)/2
nx = (GadgetWidth(OSM\Gadget)/OSM\TileSize)*2 ;How many tiles
ny = (GadgetWidth(OSM\Gadget)/OSM\TileSize)*2
StartVectorDrawing(CanvasVectorOutput(OSM\Gadget))
AddPathBox(0, 0, GadgetWidth(OSM\Gadget), GadgetHeight(OSM\Gadget))
VectorSourceColor(RGBA(255, 255, 255, 255))
StrokePath(10)
For y = 0 To nx
For x = 0 To ny
x2 = x*256 + OSM\DeltaCursor\X + mx -deltaX-(nx/2)*OSM\TileSize
y2 = y*256 + OSM\DeltaCursor\Y + my - deltaY-(ny/2)*OSM\TileSize
nImage=OSM\MapImage(x,y)\nImage
If nimage=0
MovePathCursor(x2, y2+20)
DrawVectorText( "Loading")
ElseIf IsImage(nImage) And (x2 + 256) > 0 And (y2 + 256) > 0 And x2 < GadgetWidth(OSM\Gadget) And y2 < GadgetHeight(OSM\Gadget)
MovePathCursor(x2,y2)
DrawVectorImage(ImageID(nImage))
Else
MovePathCursor(x2, y2+20)
DrawVectorText("Error Loading")
EndIf
Next
Next
UnlockMutex(OSM\MapImageMutex)
;Circle(GadgetWidth(OSM\Gadget)/2, GadgetHeight(OSM\Gadget)/2, 5, RGB(Random(255),Random(255),Random(255)))
;DrawText(0, 0, "DeltaCursorX : " + Str(OSM\DeltaCursor\X) + " deltaX : " + Str(deltaX) + " Tile X : " + StrD(OSM\TargetTile\X))
;DrawText(0, 16, "Image loaded:"+Str(ListSize(OSM\MemCache\Image())))
; Draw Track
Protected Pixel.Pixel
Protected Location.Location
ForEach OSM\track()
If ListIndex(OSM\track())=0
Location\Latitude=OSM\track()\Latitude
Location\Longitude=OSM\track()\Longitude
EndIf
If ListIndex(OSM\track())=50
; Debug HaversineInKM(@Location,@OSM\track())
Location\Latitude=OSM\track()\Latitude
Location\Longitude=OSM\track()\Longitude
EndIf
If @OSM\TargetLocation\Latitude<>0 And @OSM\TargetLocation\Longitude<>0
getPixelCoorfromLocation(@OSM\track(),@Pixel)
x=Pixel\X
y=Pixel\Y
;If x>0 And y>0 And x<GadgetWidth(OSM\Gadget) And y<GadgetHeight(OSM\Gadget)
If ListIndex(OSM\track())=0
MovePathCursor(x,y)
Else
AddPathLine(x,y)
EndIf
;EndIf
EndIf
Next
VectorSourceColor(RGBA(0, 255, 0, 150))
StrokePath(10, #PB_Path_RoundEnd|#PB_Path_RoundCorner)
StopVectorDrawing()
myTimer=ElapsedMilliseconds()
EndIf
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)
OSM\Position\X = OSM\TargetTile\X * OSM\TileSize ;Convert X, Y in tile.decimal into real pixels
OSM\Position\Y = OSM\TargetTile\Y * OSM\TileSize
EndProcedure
Macro Min(a,b)
(Bool((a) <= (b)) * (a) + Bool((b) < (a)) * (b))
EndMacro
Macro Max(a,b)
(Bool((a) >= (b)) * (a) + Bool((b) > (a)) * (b))
EndMacro
Procedure ZoomToArea()
;Source => http://gis.stackexchange.com/questions/19632/how-to-calculate-the-optimal-zoom-level-to-display-two-or-more-points-on-a-map
;bounding box in long/lat coords (x=long, y=lat)
Protected MinY.d,MaxY.d,MinX.d,MaxX.d
ForEach OSM\track()
If ListIndex(OSM\track())=0 Or OSM\track()\Longitude<MinX
MinX=OSM\track()\Longitude
EndIf
If ListIndex(OSM\track())=0 Or OSM\track()\Longitude>MaxX
MaxX=OSM\track()\Longitude
EndIf
If ListIndex(OSM\track())=0 Or OSM\track()\Latitude<MinY
MinY=OSM\track()\Latitude
EndIf
If ListIndex(OSM\track())=0 Or OSM\track()\Latitude>MaxY
MaxY=OSM\track()\Latitude
EndIf
Next
Protected DeltaX.d=MaxX-MinX ;assumption ! In original code DeltaX have no source
Protected centerX.d=MinX+DeltaX/2 ; assumption ! In original code CenterX have no source
Protected paddingFactor.f= 1.2 ;paddingFactor: this can be used to get the "120%" effect ThomM refers to. Value of 1.2 would get you the 120%.
ry1.d = Log((Sin(Radian(MinY)) + 1) / Cos(Radian(MinY)));
ry2.d = Log((Sin(Radian(MaxY)) + 1) / Cos(Radian(MaxY)));
ryc.d = (ry1 + ry2) / 2;
centerY.d = Degree(ATan(SinH(ryc)));
resolutionHorizontal.d = DeltaX / GadgetWidth(OSM\Gadget);
vy0.d = Log(Tan(#PI*(0.25 + centerY/360)));
vy1.d = Log(Tan(#PI*(0.25 + MaxY/360)));
viewHeightHalf.d = GadgetHeight(OSM\Gadget)/2;
zoomFactorPowered.d = viewHeightHalf / (40.7436654315252*(vy1 - vy0));
resolutionVertical.d = 360.0 / (zoomFactorPowered * OSM\TileSize);
resolution.d = Max(resolutionHorizontal, resolutionVertical)* paddingFactor;
zoom.d = Log(360 / (resolution * OSM\TileSize))/Log(2)
lon.d = centerX;
lat.d = centerY;
Debug "lat:"+StrD(lat)
Debug "lon:"+StrD(lon)
Debug "zoom:"+StrD(zoom)
SetLocation(lat,lon, Round(zoom,#PB_Round_Down))
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)
OSM\Position\X = OSM\TargetTile\X * OSM\TileSize ;Convert X, Y in tile.decimal into real pixels
OSM\Position\Y = OSM\TargetTile\Y * OSM\TileSize
ConstructMap()
DrawMap()
EndProcedure
Procedure InitOSM()
Debug GetTemporaryDirectory()
OSM\HDDCachePath = GetTemporaryDirectory()
OSM\ServerURL = "http://tile.openstreetmap.org/" ;"https://tile.thunderforest.com/cycle/";
OSM\ZoomMin = 0
OSM\ZoomMax = 18
OSM\StartCursor\X = - 1
OSM\TileSize = 256
OSM\MemCache\Mutex=CreateMutex()
;OSM\MemCache\Semaphore=CreateSemaphore(1)
OSM\MapImageMutex=CreateMutex()
OSM\MapImageSemaphore=CreateSemaphore(8)
OSM\Windows=0
AddWindowTimer(OSM\Windows,1, 500)
EndProcedure
Procedure Event(Event.l)
Protected Gadget.i
Protected tx.d, ty.d
Protected OldX.i, OldY.i
If IsGadget(OSM\Gadget) And GadgetType(OSM\Gadget) = #PB_GadgetType_Canvas
Select Event
Case #EvenementStartRefresh
;Debug "Start"
AddWindowTimer(OSM\Windows,1, 500)
Case #EvenementStopRefresh
;Debug "Stop"
DrawMap()
;RemoveWindowTimer(OSM\Windows, 1)
Case #PB_Event_Timer
If EventTimer()=1;=#Timer_Draw
DrawMap()
EndIf
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
OSM\DeltaCursor\X=GetGadgetAttribute(OSM\Gadget, #PB_Canvas_MouseX)-OSM\StartCursor\X
OSM\DeltaCursor\Y=GetGadgetAttribute(OSM\Gadget, #PB_Canvas_MouseY)-OSM\StartCursor\Y
EndIf
DrawMap()
Case #PB_EventType_LeftButtonUp
DrawMap()
tx=(OSM\DeltaCursor\X/256)
ty=(OSM\DeltaCursor\Y/256)
OSM\DeltaCursor\X=0
OSM\DeltaCursor\Y=0
OSM\StartCursor\X=-1
TileTranslate(@OSM\TargetTile,tx,ty)
XY2LatLon(@OSM\TargetTile,@OSM\TargetLocation)
ConstructMap()
EndSelect
EndSelect
EndSelect
Else
MessageRequester("Module OSM", "You must use OSMGadget before", #PB_MessageRequester_Ok )
End
EndIf
EndProcedure
EndModule
;Demonstration
CompilerIf #PB_Compiler_IsMainFile
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, 17)
OSM::SetLocation(49.0346374511718750,2.0787782669067383,17)
OSM::LoadGpxFile("Rallye.gpx")
OSM::ZoomToArea()
OSM::ConstructMap()
OSM::DrawMap()
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
CompilerEndIf
Re: OpenStreetMap dans un Canvas
Ah oui, ça rend bien, effectivement 

Re: OpenStreetMap dans un Canvas
Bon, j'ai codé le bazar, mais comme tout est threadé, y'a encore des bugs de synchro. Je devrais poster un code demain.
Re: OpenStreetMap dans un Canvas
pas de problème j'ai pas eu beaucoup de temps aujourd'hui.djes a écrit :Bon, j'ai codé le bazar, mais comme tout est threadé, y'a encore des bugs de synchro. Je devrais poster un code demain.
