From 4cb1f57bbcf1ef62facb88a227196e6657b2f65a Mon Sep 17 00:00:00 2001 From: djes Date: Wed, 7 Jun 2017 17:15:04 +0200 Subject: [PATCH 01/16] Cache bugfix in progress And better web loading by thread limit --- .gitignore | 3 +- PBMap.pb | 326 +++++++++++++++++++++++++++++------------------------ 2 files changed, 181 insertions(+), 148 deletions(-) diff --git a/.gitignore b/.gitignore index 9a024d7..c2404a1 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ -PBMap.pb.bak \ No newline at end of file +PBMap.pb.bak +*.exe diff --git a/PBMap.pb b/PBMap.pb index 2dfe868..facf566 100644 --- a/PBMap.pb +++ b/PBMap.pb @@ -79,8 +79,8 @@ DeclareModule PBMap Declare SetZoomToArea(MinY.d, MaxY.d, MinX.d, MaxX.d) Declare SetZoomToTracks(*Tracks) Declare NominatimGeoLocationQuery(Address.s, *ReturnPosition = 0) ;Send back the position *ptr.GeographicCoordinates - Declare.i LoadGpxFile(FileName.s) ; - Declare.i SaveGpxFile(FileName.s, *Track) ; + Declare.i LoadGpxFile(FileName.s) ; + Declare.i SaveGpxFile(FileName.s, *Track) ; Declare ClearTracks() Declare DeleteTrack(*Ptr) Declare DeleteSelectedTracks() @@ -153,7 +153,7 @@ Module PBMap Structure ImgMemCach nImage.i *Tile.Tile - TimeStackPosition.i + *TimeStackPtr Alpha.i EndStructure @@ -197,6 +197,7 @@ Module PBMap ShowPointer.i TimerInterval.i MaxMemCache.i ; in MiB + MaxThreads.i ; Maximum simultaneous web loading threads TileLifetime.i Verbose.i ; Maximum debug informations Warning.i ; Warning requesters @@ -281,6 +282,8 @@ Module PBMap MemCache.TileMemCach ; Images in memory cache + ThreadsNB.i ; Current web threads nb + Mode.i ; User mode : 0 (default)->hand (moving map) and select markers, 1->hand, 2->select only (moving objects), 3->drawing (todo) Redraw.i Dragging.i @@ -376,7 +379,7 @@ Module PBMap SetFileAttributes(Name, Attribs) EndMacro CompilerEndSelect - + Procedure CreateDirectoryEx(DirectoryName.s, FileAttribute = #PB_Default) Protected i, c, tmp.s If Right(DirectoryName, 1) = slash @@ -681,6 +684,8 @@ Module PBMap PBMap\Options\HDDCachePath = Value Case "maxmemcache" PBMap\Options\MaxMemCache = Val(Value) + Case "maxthreads" + PBMap\Options\MaxThreads = Val(Value) Case "tilelifetime" PBMap\Options\TileLifetime = Val(Value) Case "verbose" @@ -732,57 +737,59 @@ Module PBMap Option = StringCheck(Option) With PBMap\Options Select LCase(Option) - Case "proxy" - ProcedureReturn GetBoolString(\Proxy) - Case "proxyurl" - ProcedureReturn \ProxyURL - Case "proxyport" - ProcedureReturn \ProxyPort - Case "proxyuser" - ProcedureReturn \ProxyUser - Case "appid" - ProcedureReturn \appid - Case "appcode" - ProcedureReturn \appcode - Case "tilescachepath" - ProcedureReturn \HDDCachePath - Case "maxmemcache" - ProcedureReturn StrU(\MaxMemCache) - Case "tilelifetime" - ProcedureReturn StrU(\TileLifetime) - Case "verbose" - ProcedureReturn GetBoolString(\Verbose) - Case "warning" - ProcedureReturn GetBoolString(\Warning) - Case "wheelmouserelative" - ProcedureReturn GetBoolString(\WheelMouseRelative) - Case "showdegrees" - ProcedureReturn GetBoolString(\ShowDegrees) - Case "showdebuginfos" - ProcedureReturn GetBoolString(\ShowDebugInfos) - Case "showscale" - ProcedureReturn GetBoolString(\ShowScale) - Case "showmarkers" - ProcedureReturn GetBoolString(\ShowMarkers) - Case "showpointer" - ProcedureReturn GetBoolString(\ShowPointer) - Case "showtrack" - ProcedureReturn GetBoolString(\ShowTrack) - Case "showmarkersnb" - ProcedureReturn GetBoolString(\ShowMarkersNb) - Case "showmarkerslegend" - ProcedureReturn GetBoolString(\ShowMarkersLegend) - Case "showtrackkms" - ProcedureReturn GetBoolString(\ShowTrackKms) - Case "strokewidthtrackdefault" - ProcedureReturn GetBoolString(\StrokeWidthTrackDefault) - Case "colourfocus" - ProcedureReturn Value2ColourString(\ColourFocus) - Case "colourselected" - ProcedureReturn Value2ColourString(\ColourSelected) - Case "colourtrackdefault" - ProcedureReturn Value2ColourString(\ColourTrackDefault) - EndSelect + Case "proxy" + ProcedureReturn GetBoolString(\Proxy) + Case "proxyurl" + ProcedureReturn \ProxyURL + Case "proxyport" + ProcedureReturn \ProxyPort + Case "proxyuser" + ProcedureReturn \ProxyUser + Case "appid" + ProcedureReturn \appid + Case "appcode" + ProcedureReturn \appcode + Case "tilescachepath" + ProcedureReturn \HDDCachePath + Case "maxmemcache" + ProcedureReturn StrU(\MaxMemCache) + Case "maxthreads" + ProcedureReturn StrU(\MaxThreads) + Case "tilelifetime" + ProcedureReturn StrU(\TileLifetime) + Case "verbose" + ProcedureReturn GetBoolString(\Verbose) + Case "warning" + ProcedureReturn GetBoolString(\Warning) + Case "wheelmouserelative" + ProcedureReturn GetBoolString(\WheelMouseRelative) + Case "showdegrees" + ProcedureReturn GetBoolString(\ShowDegrees) + Case "showdebuginfos" + ProcedureReturn GetBoolString(\ShowDebugInfos) + Case "showscale" + ProcedureReturn GetBoolString(\ShowScale) + Case "showmarkers" + ProcedureReturn GetBoolString(\ShowMarkers) + Case "showpointer" + ProcedureReturn GetBoolString(\ShowPointer) + Case "showtrack" + ProcedureReturn GetBoolString(\ShowTrack) + Case "showmarkersnb" + ProcedureReturn GetBoolString(\ShowMarkersNb) + Case "showmarkerslegend" + ProcedureReturn GetBoolString(\ShowMarkersLegend) + Case "showtrackkms" + ProcedureReturn GetBoolString(\ShowTrackKms) + Case "strokewidthtrackdefault" + ProcedureReturn GetBoolString(\StrokeWidthTrackDefault) + Case "colourfocus" + ProcedureReturn Value2ColourString(\ColourFocus) + Case "colourselected" + ProcedureReturn Value2ColourString(\ColourSelected) + Case "colourtrackdefault" + ProcedureReturn Value2ColourString(\ColourTrackDefault) + EndSelect EndWith EndProcedure @@ -809,6 +816,7 @@ Module PBMap PreferenceGroup("OPTIONS") WritePreferenceInteger("WheelMouseRelative", \WheelMouseRelative) WritePreferenceInteger("MaxMemCache", \MaxMemCache) + WritePreferenceInteger("MaxThreads", \MaxThreads) WritePreferenceInteger("TileLifetime", \TileLifetime) WritePreferenceInteger("Verbose", \Verbose) WritePreferenceInteger("Warning", \Warning) @@ -873,6 +881,7 @@ Module PBMap PreferenceGroup("OPTIONS") \WheelMouseRelative = ReadPreferenceInteger("WheelMouseRelative", #True) \MaxMemCache = ReadPreferenceInteger("MaxMemCache", 20480) ;20 MiB, about 80 tiles in memory + \MaxThreads = ReadPreferenceInteger("MaxThreads", 20) \TileLifetime = ReadPreferenceInteger("TileLifetime", 1209600) ;about 2 weeks ; -1 = unlimited \Verbose = ReadPreferenceInteger("Verbose", #False) \Warning = ReadPreferenceInteger("Warning", #False) @@ -973,12 +982,12 @@ Module PBMap Protected *Ptr.Layer = AddLayer(LayerName, Order, 1) If *Ptr With *Ptr ;PBMap\Layers() - \ServerURL = ServerURL - \path = path - \LayerType = 2 ; GeoServer - \format = format - \Enabled = #True - \ServerLayerName = ServerLayerName + \ServerURL = ServerURL + \path = path + \LayerType = 2 ; GeoServer + \format = format + \Enabled = #True + \ServerLayerName = ServerLayerName EndWith PBMap\Redraw = #True ProcedureReturn *Ptr @@ -1030,23 +1039,26 @@ Module PBMap If MaxLifeTime <> -1 LifeTime = Date() - GetFileDate(CacheFile, #PB_Date_Modified) ;There's a bug with #PB_Date_Created If LifeTime > MaxLifeTime - MyDebug("Deleting too old (" + StrU(LifeTime) + " secs) " + CacheFile, 3) + MyDebug(" Deleting too old (" + StrU(LifeTime) + " secs) " + CacheFile, 3) DeleteFile(CacheFile) ProcedureReturn -1 EndIf EndIf ;Everything is OK, load the file nImage = LoadImage(#PB_Any, CacheFile) - If IsImage(nImage) - MyDebug("Success loading " + CacheFile + " as nImage " + Str(nImage), 3) + If nImage And IsImage(nImage) + MyDebug(" Success loading " + CacheFile + " as nImage " + Str(nImage), 3) ProcedureReturn nImage Else - MyDebug("Failed loading " + CacheFile + " as nImage " + Str(nImage) + " -> not an image !", 3) - MyDebug("Deleting faulty image file " + CacheFile, 3) - DeleteFile(CacheFile) + MyDebug(" Failed loading " + CacheFile + " as nImage " + Str(nImage) + " -> not an image !", 3) + If DeleteFile(CacheFile) + MyDebug(" Deleting faulty image file " + CacheFile, 3) + Else + MyDebug(" Can't delete faulty image file " + CacheFile, 3) + EndIf EndIf Else - MyDebug("Failed loading " + CacheFile + " -> Size <= 0", 3) + MyDebug(" Failed loading " + CacheFile + " -> Filesize = " + FileSize(CacheFile), 3) EndIf ProcedureReturn -1 EndProcedure @@ -1054,13 +1066,12 @@ Module PBMap Procedure.i GetTileFromWeb(TileURL.s, CacheFile.s) Protected *Buffer Protected nImage.i = -1 - Protected FileSize.i, timg - FileSize = ReceiveHTTPFile(TileURL, CacheFile) - If FileSize > 0 - MyDebug("Loaded from web " + TileURL + " as CacheFile " + CacheFile, 3) + Protected timg + If ReceiveHTTPFile(TileURL, CacheFile) + MyDebug(" Loaded from web " + TileURL + " as CacheFile " + CacheFile, 3) nImage = GetTileFromHDD(CacheFile) Else - MyDebug("Problem loading from web " + TileURL + " as CacheFile " + CacheFile, 3) + MyDebug(" Problem receving from web " + TileURL + " as CacheFile " + CacheFile, 3) EndIf ; **** IMPORTANT NOTICE (please not remove) ; I'm (djes) now using Curl (actually, just normal pb) only, as this original catchimage/saveimage method is a double operation (uncompress/recompress PNG) @@ -1089,17 +1100,17 @@ Module PBMap Procedure GetImageThread(*Tile.Tile) Protected nImage.i = -1 + MyDebug("Thread for image key " + *Tile\key, 3) Repeat nImage = GetTileFromWeb(*Tile\URL, *Tile\CacheFile) If nImage <> -1 - MyDebug("Image key : " + *Tile\key + " web image loaded", 3) *Tile\RetryNb = 0 Else - MyDebug("Image key : " + *Tile\key + " web image not correctly loaded, will retry in 2 secs", 3) Delay(2000) *Tile\RetryNb - 1 EndIf Until *Tile\RetryNb <= 0 + MyDebug(" Thread for image key " + *Tile\key + " finished", 3) *Tile\nImage = nImage *Tile\RetryNb = -2 ;End of the thread PostEvent(#PB_Event_Gadget, PBMap\Window, PBmap\Gadget, #PB_MAP_TILE_CLEANUP, *Tile) ;To free memory outside the thread @@ -1107,81 +1118,100 @@ Module PBMap ;-*** Procedure.i GetTile(key.s, URL.s, CacheFile.s) - ; Try to find the tile in memory cache. If not found, add it, try to load it from the - ; HDD, or launch a loading thread, and try again on the next drawing loop. + ; Try to find the tile in memory cache. If not found, add it if there's enough room in the cache, try to load the picture from the + ; HDD, or launch a web loading thread, and try again on the next drawing loop. Protected img.i = -1 Protected *timg.ImgMemCach = FindMapElement(PBMap\MemCache\Images(), key) If *timg MyDebug("Key : " + key + " found in memory cache", 3) img = *timg\nImage If img <> -1 - MyDebug("Image : " + img + " found in memory cache", 3) + MyDebug(" as image " + img, 3) ;*** Cache management - ; Move the newly used element to the last position of the time stack - SelectElement(PBMap\MemCache\ImagesTimeStack(), *timg\TimeStackPosition) + ; Retrieves the image in the time stack, push it to the end (to say it's the lastly used) + ChangeCurrentElement(PBMap\MemCache\ImagesTimeStack(), *timg\TimeStackPtr) MoveElement(PBMap\MemCache\ImagesTimeStack(), #PB_List_Last) + ;*timg\TimeStackPtr = LastElement(PBMap\MemCache\ImagesTimeStack()) ;*** ProcedureReturn *timg EndIf Else - ;PushMapPosition(PBMap\MemCache\Images()) ;*** Cache management - ; if cache size exceeds limit, try to delete the oldest tile used (first in the list) + ; if cache size exceeds limit, try to delete the oldest tiles used (first in the time stack) Protected CacheSize = MapSize(PBMap\MemCache\Images()) * Pow(PBMap\TileSize, 2) * 4 ; Size of a tile = TileSize * TileSize * 4 bytes (RGBA) Protected CacheLimit = PBMap\Options\MaxMemCache * 1024 MyDebug("Cache size : " + Str(CacheSize/1024) + " / CacheLimit : " + Str(CacheLimit/1024), 4) - ResetList(PBMap\MemCache\ImagesTimeStack()) - While NextElement(PBMap\MemCache\ImagesTimeStack()) And CacheSize > CacheLimit - Protected CacheMapKey.s = PBMap\MemCache\ImagesTimeStack()\MapKey - Protected Image = PBMap\MemCache\Images(CacheMapKey)\nImage - If IsImage(Image) ; Check if the image is valid (is a loading thread running ?) - FreeImage(Image) - MyDebug("Delete " + CacheMapKey + " As image nb " + Str(Image), 4) - DeleteMapElement(PBMap\MemCache\Images(), CacheMapKey) - DeleteElement(PBMap\MemCache\ImagesTimeStack()) + If CacheSize > CacheLimit + MyDebug(" Cache full. Trying cache cleaning", 4) + ResetList(PBMap\MemCache\ImagesTimeStack()) + ; Try to free half the cache memory (one pass) + While NextElement(PBMap\MemCache\ImagesTimeStack()) And CacheSize > (CacheLimit / 2) ; /2 = half + Protected CacheMapKey.s = PBMap\MemCache\ImagesTimeStack()\MapKey + Protected Image = PBMap\MemCache\Images(CacheMapKey)\nImage + If IsImage(Image) ; Check if the image is valid (is a loading thread running ?) + FreeImage(Image) + DeleteMapElement(PBMap\MemCache\Images(), CacheMapKey) + DeleteElement(PBMap\MemCache\ImagesTimeStack()) + MyDebug(" Delete " + CacheMapKey + " as image nb " + Str(Image), 4) + EndIf CacheSize = MapSize(PBMap\MemCache\Images()) * Pow(PBMap\TileSize, 2) * 4 ; Size of a tile = TileSize * TileSize * 4 bytes (RGBA) + Wend + MyDebug(" New cache size : " + Str(CacheSize/1024) + " / CacheLimit : " + Str(CacheLimit/1024), 4) + If CacheSize > CacheLimit + MyDebug(" Cache cleaning unsuccessfull, can't add new tiles.", 4) + ProcedureReturn 0 EndIf - Wend - LastElement(PBMap\MemCache\ImagesTimeStack()) - ;PopMapPosition(PBMap\MemCache\Images()) + EndIf + ; Creates a new cache element AddMapElement(PBMap\MemCache\Images(), key) - AddElement(PBMap\MemCache\ImagesTimeStack()) - ;MoveElement(PBMap\MemCache\ImagesTimeStack(), #PB_List_Last) - PBMap\MemCache\ImagesTimeStack()\MapKey = MapKey(PBMap\MemCache\Images()) - ;*** - MyDebug("Key : " + key + " added in memory cache", 3) *timg = PBMap\MemCache\Images() - *timg\nImage = -1 + ; Add a new time stack element at the end + LastElement(PBMap\MemCache\ImagesTimeStack()) + ; Stores the time stack ptr + *timg\TimeStackPtr = AddElement(PBMap\MemCache\ImagesTimeStack()) + ; Associates the time stack element to the cache element + PBMap\MemCache\ImagesTimeStack()\MapKey = MapKey(PBMap\MemCache\Images()) + *timg\nImage = -1 + MyDebug("Key : " + key + " added in memory cache", 3) + ;*** EndIf - If *timg\Tile = 0 ; Check if a loading thread is not running - MyDebug("Trying to load from HDD " + CacheFile, 3) + If *timg\Tile = 0 ; Check if a loading thread is not already running img = GetTileFromHDD(CacheFile.s) If img <> -1 - MyDebug("Key : " + key + " found on HDD", 3) + ; Image found and loaded from HDD *timg\nImage = img *timg\Alpha = 256 ProcedureReturn *timg EndIf - MyDebug("Key : " + key + " not found on HDD", 3) - ;Launch a new thread - Protected *NewTile.Tile = AllocateMemory(SizeOf(Tile)) - If *NewTile - With *NewTile - *timg\Tile = *NewTile - *timg\Alpha = 0 - ;*timg\nImage = -1 - ;New tile parameters - \key = key - \URL = URL - \CacheFile = CacheFile - \RetryNb = 5 - \nImage = -1 - MyDebug(" Creating get image thread nb " + Str(\GetImageThread) + " to get " + CacheFile, 3) - \GetImageThread = CreateThread(@GetImageThread(), *NewTile) - EndWith + ; Image not found on HDD, launch a new web loading thread + If PBMap\ThreadsNB < PBMap\Options\MaxThreads + Protected *NewTile.Tile = AllocateMemory(SizeOf(Tile)) + If *NewTile + With *NewTile + *timg\Tile = *NewTile + *timg\Alpha = 0 + ;*timg\nImage = -1 + ;New tile parameters + \key = key + \URL = URL + \CacheFile = CacheFile + \RetryNb = 5 + \nImage = -1 + \GetImageThread = CreateThread(@GetImageThread(), *NewTile) + If \GetImageThread + MyDebug(" Creating get image thread nb " + Str(\GetImageThread) + " to get " + CacheFile, 3) + PBMap\ThreadsNB + 1 + Else + MyDebug(" Can't create get image thread to get " + CacheFile, 3) + FreeMemory(*NewTile) + EndIf + EndWith + Else + MyDebug(" Error, can't allocate memory for a new tile loading thread", 3) + EndIf Else - MyDebug(" Error, can't create a new tile loading thread", 3) - EndIf + MyDebug(" Error, maximum threads nb reached", 3) + EndIf EndIf ProcedureReturn *timg EndProcedure @@ -1239,12 +1269,12 @@ Module PBMap EndIf With PBMap\Layers() Select \LayerType - ;---- OSM tiles + ;---- OSM tiles Case 0 URL = \ServerURL + Str(PBMap\Zoom) + "/" + Str(tilex) + "/" + Str(tiley) + ".png" ; Tile cache name based on y CacheFile = DirName + slash + Str(tiley) + ".png" - ;---- Here tiles + ;---- Here tiles Case 1 HereLoadBalancing = 1 + ((tiley + tilex) % 4) ; {Base URL}{Path}{resource (tile type)}/{Map id}/{scheme}/{zoom}/{column}/{row}/{size}/{format}?app_id={YOUR_APP_ID}&app_code={YOUR_APP_CODE}&{param}={value} @@ -1254,7 +1284,7 @@ Module PBMap EndIf ; Tile cache name based on y CacheFile = DirName + slash + Str(tiley) + "." + \format - ;---- GeoServer / geowebcache - google maps service tiles + ;---- GeoServer / geowebcache - google maps service tiles Case 2 ; template 'http://localhost:8080/geowebcache/service/gmaps?layers=layer-name&zoom={Z}&x={X}&y={Y}&format=image/png' URL = \ServerURL + \path + "?layers=" + \ServerLayerName + "&zoom={" + Str(PBMap\Zoom) + "}&x={" + Str(tilex) + "}&y={" + Str(tiley) + "}&format=" + \format @@ -1263,7 +1293,7 @@ Module PBMap EndSelect EndWith *timg = GetTile(key, URL, CacheFile) - If *timg\nImage <> -1 + If *timg And *timg\nImage <> -1 MovePathCursor(px, py) If *timg\Alpha <= 224 DrawVectorImage(ImageID(*timg\nImage), *timg\Alpha * PBMap\Layers()\Alpha) @@ -1737,7 +1767,7 @@ Module PBMap VectorFont(FontID(PBMap\Font), 16) VectorSourceColor(RGBA(0, 0, 0, 80)) MovePathCursor(50, 50) - DrawVectorText(Str(MapSize(PBMap\MemCache\Images()))) + DrawVectorText("Images in cache : " + Str(MapSize(PBMap\MemCache\Images()))) MovePathCursor(50, 70) Protected ThreadCounter = 0 ForEach PBMap\MemCache\Images() @@ -1747,13 +1777,13 @@ Module PBMap EndIf EndIf Next - DrawVectorText(Str(ThreadCounter)) + DrawVectorText("Threads nb : " + Str(ThreadCounter)) MovePathCursor(50, 90) - DrawVectorText(Str(PBMap\Zoom)) + DrawVectorText("Zoom : " + Str(PBMap\Zoom)) MovePathCursor(50, 110) - DrawVectorText(StrD(*Drawing\Bounds\NorthWest\Latitude) + "," + StrD(*Drawing\Bounds\NorthWest\Longitude)) + DrawVectorText("Lat-Lon 1 : " + StrD(*Drawing\Bounds\NorthWest\Latitude) + "," + StrD(*Drawing\Bounds\NorthWest\Longitude)) MovePathCursor(50, 130) - DrawVectorText(StrD(*Drawing\Bounds\SouthEast\Latitude) + "," + StrD(*Drawing\Bounds\SouthEast\Longitude)) + DrawVectorText("Lat-Lon 2 : " + StrD(*Drawing\Bounds\SouthEast\Latitude) + "," + StrD(*Drawing\Bounds\SouthEast\Longitude)) EndProcedure Procedure DrawOSMCopyright(*Drawing.DrawingParameters) @@ -2113,11 +2143,11 @@ Module PBMap EndIf EndIf If DeleteDirectory(PBMap\Options\HDDCachePath, "", #PB_FileSystem_Recursive) - MyDebug("Cache in : " + PBMap\Options\HDDCachePath + " cleared") + MyDebug("Cache in : " + PBMap\Options\HDDCachePath + " cleared", 3) CreateDirectoryEx(PBMap\Options\HDDCachePath) ProcedureReturn #True Else - MyDebug("Can't clear cache in " + PBMap\Options\HDDCachePath) + MyDebug("Can't clear cache in " + PBMap\Options\HDDCachePath, 3) ProcedureReturn #False EndIf EndProcedure @@ -2347,12 +2377,13 @@ Module PBMap Case #PB_MAP_TILE_CLEANUP *Tile = EventData() key = *Tile\key - ;After a Web tile loading thread, clean the tile structure memory and set the image nb in the cache - ;avoid to have threads accessing vars (and avoid mutex), see GetImageThread() - Protected timg = PBMap\MemCache\Images(key)\Tile\nImage ;Get this new tile image nb - PBMap\MemCache\Images(key)\nImage = timg ;store it in the cache using the key - FreeMemory(PBMap\MemCache\Images(key)\Tile) ;free the data needed for the thread - PBMap\MemCache\Images(key)\Tile = 0 ;clear the data ptr + ; After a Web tile loading thread, clean the tile structure memory and set the image nb in the cache + ; avoid to have threads accessing vars (and avoid mutex), see GetImageThread() + Protected timg = PBMap\MemCache\Images(key)\Tile\nImage ; Get this new tile image nb + PBMap\MemCache\Images(key)\nImage = timg ; Stores it in the cache using the key + FreeMemory(PBMap\MemCache\Images(key)\Tile) ; Frees the data needed for the thread + PBMap\MemCache\Images(key)\Tile = 0 ; Clears the data ptr + PBMap\ThreadsNB - 1 ; The web loading thread is finished PBMap\Redraw = #True EndSelect EndProcedure @@ -2592,9 +2623,9 @@ CompilerIf #PB_Compiler_IsMainFile ;Our main gadget PBMap::InitPBMap(#Window_0) - PBMap::SetOption("ShowDegrees", "0") : Degrees = 0 - PBMap::SetOption("ShowDebugInfos", "0") - PBMap::SetOption("Verbose", "0") + PBMap::SetOption("ShowDegrees", "1") : Degrees = 0 + PBMap::SetOption("ShowDebugInfos", "3") + PBMap::SetOption("Verbose", "1") PBMap::SetOption("ShowScale", "1") PBMap::SetOption("Warning", "1") PBMap::SetOption("ShowMarkersLegend", "1") @@ -2643,9 +2674,9 @@ CompilerIf #PB_Compiler_IsMainFile MessageRequester("PBMap", "Problem while saving.", #PB_MessageRequester_Ok) EndIf Else - MessageRequester("PBMap", "No track to save.", #PB_MessageRequester_Ok) + MessageRequester("PBMap", "No track to save.", #PB_MessageRequester_Ok) EndIf - Case #StringLatitude, #StringLongitude + Case #StringLatitude, #StringLongitude Select EventType() Case #PB_EventType_Focus AddKeyboardShortcut(#Window_0, #PB_Shortcut_Return, #MenuEventLonLatStringEnter) @@ -2737,8 +2768,9 @@ CompilerIf #PB_Compiler_IsMainFile CompilerEndIf ; IDE Options = PureBasic 5.60 (Windows - x64) -; CursorPosition = 2691 -; FirstLine = 2684 +; CursorPosition = 1123 +; FirstLine = 1130 ; Folding = ------------------- ; EnableThread -; EnableXP \ No newline at end of file +; EnableXP +; CompileSourceDirectory \ No newline at end of file From c862f9099ea9c294bbdf487c9d013ecf24dc7ce0 Mon Sep 17 00:00:00 2001 From: djes Date: Thu, 8 Jun 2017 12:27:56 +0200 Subject: [PATCH 02/16] Overload bugfix in progress When several threads are launched and the web server doesn't respond, a form of overload appears. --- PBMap.pb | 88 ++++++++++++++++++++++++++++++-------------------------- 1 file changed, 47 insertions(+), 41 deletions(-) diff --git a/PBMap.pb b/PBMap.pb index facf566..2f2dd01 100644 --- a/PBMap.pb +++ b/PBMap.pb @@ -303,7 +303,7 @@ Module PBMap ;-*** Global variables ;-Show debug infos - Global MyDebugLevel = 3 + Global MyDebugLevel = 0 Global PBMap.PBMap, Null.i, NullPtrMem.i, *NullPtr = @NullPtrMem Global slash.s @@ -881,7 +881,7 @@ Module PBMap PreferenceGroup("OPTIONS") \WheelMouseRelative = ReadPreferenceInteger("WheelMouseRelative", #True) \MaxMemCache = ReadPreferenceInteger("MaxMemCache", 20480) ;20 MiB, about 80 tiles in memory - \MaxThreads = ReadPreferenceInteger("MaxThreads", 20) + \MaxThreads = ReadPreferenceInteger("MaxThreads", 40) \TileLifetime = ReadPreferenceInteger("TileLifetime", 1209600) ;about 2 weeks ; -1 = unlimited \Verbose = ReadPreferenceInteger("Verbose", #False) \Warning = ReadPreferenceInteger("Warning", #False) @@ -1034,17 +1034,17 @@ Module PBMap Procedure.i GetTileFromHDD(CacheFile.s) Protected nImage.i, LifeTime.i, MaxLifeTime.i = PBMap\Options\TileLifetime - If FileSize(CacheFile) <> -1 + If FileSize(CacheFile) > 0 ;<> -1 ;Manage tile file lifetime If MaxLifeTime <> -1 LifeTime = Date() - GetFileDate(CacheFile, #PB_Date_Modified) ;There's a bug with #PB_Date_Created If LifeTime > MaxLifeTime MyDebug(" Deleting too old (" + StrU(LifeTime) + " secs) " + CacheFile, 3) DeleteFile(CacheFile) - ProcedureReturn -1 + ProcedureReturn 0 EndIf EndIf - ;Everything is OK, load the file + ;Everything is OK, loads the file nImage = LoadImage(#PB_Any, CacheFile) If nImage And IsImage(nImage) MyDebug(" Success loading " + CacheFile + " as nImage " + Str(nImage), 3) @@ -1060,23 +1060,27 @@ Module PBMap Else MyDebug(" Failed loading " + CacheFile + " -> Filesize = " + FileSize(CacheFile), 3) EndIf - ProcedureReturn -1 + ProcedureReturn 0 EndProcedure Procedure.i GetTileFromWeb(TileURL.s, CacheFile.s) - Protected *Buffer - Protected nImage.i = -1 - Protected timg + ;Debug TileURL If ReceiveHTTPFile(TileURL, CacheFile) MyDebug(" Loaded from web " + TileURL + " as CacheFile " + CacheFile, 3) - nImage = GetTileFromHDD(CacheFile) + ; Debug TileURL + " OK" + ProcedureReturn GetTileFromHDD(CacheFile) Else MyDebug(" Problem receving from web " + TileURL + " as CacheFile " + CacheFile, 3) + ; Debug TileURL + " NOT OK" + ProcedureReturn -1 EndIf - ; **** IMPORTANT NOTICE (please not remove) + ; **** (OLD) IMPORTANT NOTICE (please not remove) ; I'm (djes) now using Curl (actually, just normal pb) only, as this original catchimage/saveimage method is a double operation (uncompress/recompress PNG) ; and is modifying the original PNG image which could lead to PNG error (Idle has spent hours debunking the 1 bit PNG bug) - ; More than that, the original Purebasic Receive library is still not Proxy enabled. + ; More than that, the original Purebasic Receive library is still not Proxy enabled. + ;Protected *Buffer + ;Protected nImage.i = -1 + ;Protected timg ; *Buffer = ReceiveHTTPMemory(TileURL) ;TODO to thread by using #PB_HTTP_Asynchronous ; If *Buffer ; nImage = CatchImage(#PB_Any, *Buffer, MemorySize(*Buffer)) @@ -1095,15 +1099,13 @@ Module PBMap ; MyDebug(" Problem loading from web " + TileURL, 3) ; EndIf ; **** - ProcedureReturn nImage EndProcedure Procedure GetImageThread(*Tile.Tile) - Protected nImage.i = -1 MyDebug("Thread for image key " + *Tile\key, 3) Repeat - nImage = GetTileFromWeb(*Tile\URL, *Tile\CacheFile) - If nImage <> -1 + *Tile\nImage = GetTileFromWeb(*Tile\URL, *Tile\CacheFile) + If *Tile\nImage <> -1 *Tile\RetryNb = 0 Else Delay(2000) @@ -1111,7 +1113,6 @@ Module PBMap EndIf Until *Tile\RetryNb <= 0 MyDebug(" Thread for image key " + *Tile\key + " finished", 3) - *Tile\nImage = nImage *Tile\RetryNb = -2 ;End of the thread PostEvent(#PB_Event_Gadget, PBMap\Window, PBmap\Gadget, #PB_MAP_TILE_CLEANUP, *Tile) ;To free memory outside the thread EndProcedure @@ -1120,13 +1121,11 @@ Module PBMap Procedure.i GetTile(key.s, URL.s, CacheFile.s) ; Try to find the tile in memory cache. If not found, add it if there's enough room in the cache, try to load the picture from the ; HDD, or launch a web loading thread, and try again on the next drawing loop. - Protected img.i = -1 Protected *timg.ImgMemCach = FindMapElement(PBMap\MemCache\Images(), key) If *timg MyDebug("Key : " + key + " found in memory cache", 3) - img = *timg\nImage - If img <> -1 - MyDebug(" as image " + img, 3) + If *timg\nImage + MyDebug(" as image " + *timg\nImage, 3) ;*** Cache management ; Retrieves the image in the time stack, push it to the end (to say it's the lastly used) ChangeCurrentElement(PBMap\MemCache\ImagesTimeStack(), *timg\TimeStackPtr) @@ -1140,9 +1139,9 @@ Module PBMap ; if cache size exceeds limit, try to delete the oldest tiles used (first in the time stack) Protected CacheSize = MapSize(PBMap\MemCache\Images()) * Pow(PBMap\TileSize, 2) * 4 ; Size of a tile = TileSize * TileSize * 4 bytes (RGBA) Protected CacheLimit = PBMap\Options\MaxMemCache * 1024 - MyDebug("Cache size : " + Str(CacheSize/1024) + " / CacheLimit : " + Str(CacheLimit/1024), 4) + MyDebug("Cache size : " + Str(CacheSize/1024) + " / CacheLimit : " + Str(CacheLimit/1024), 3) If CacheSize > CacheLimit - MyDebug(" Cache full. Trying cache cleaning", 4) + MyDebug(" Cache full. Trying cache cleaning", 3) ResetList(PBMap\MemCache\ImagesTimeStack()) ; Try to free half the cache memory (one pass) While NextElement(PBMap\MemCache\ImagesTimeStack()) And CacheSize > (CacheLimit / 2) ; /2 = half @@ -1152,34 +1151,41 @@ Module PBMap FreeImage(Image) DeleteMapElement(PBMap\MemCache\Images(), CacheMapKey) DeleteElement(PBMap\MemCache\ImagesTimeStack()) - MyDebug(" Delete " + CacheMapKey + " as image nb " + Str(Image), 4) + MyDebug(" Delete " + CacheMapKey + " as image nb " + Str(Image), 3) EndIf CacheSize = MapSize(PBMap\MemCache\Images()) * Pow(PBMap\TileSize, 2) * 4 ; Size of a tile = TileSize * TileSize * 4 bytes (RGBA) Wend - MyDebug(" New cache size : " + Str(CacheSize/1024) + " / CacheLimit : " + Str(CacheLimit/1024), 4) + MyDebug(" New cache size : " + Str(CacheSize/1024) + " / CacheLimit : " + Str(CacheLimit/1024), 3) If CacheSize > CacheLimit - MyDebug(" Cache cleaning unsuccessfull, can't add new tiles.", 4) + MyDebug(" Cache cleaning unsuccessfull, can't add new tiles.", 3) ProcedureReturn 0 EndIf EndIf ; Creates a new cache element - AddMapElement(PBMap\MemCache\Images(), key) - *timg = PBMap\MemCache\Images() - ; Add a new time stack element at the end + *timg = AddMapElement(PBMap\MemCache\Images(), key) + If *timg = 0 + MyDebug(" Can't add a new cache element.", 3) + ProcedureReturn 0 + EndIf + ; add a new time stack element at the End LastElement(PBMap\MemCache\ImagesTimeStack()) ; Stores the time stack ptr *timg\TimeStackPtr = AddElement(PBMap\MemCache\ImagesTimeStack()) + If *timg\TimeStackPtr = 0 + MyDebug(" Can't add a new time stack element.", 3) + DeleteMapElement(PBMap\MemCache\Images()) + ProcedureReturn 0 + EndIf ; Associates the time stack element to the cache element - PBMap\MemCache\ImagesTimeStack()\MapKey = MapKey(PBMap\MemCache\Images()) - *timg\nImage = -1 + PBMap\MemCache\ImagesTimeStack()\MapKey = MapKey(PBMap\MemCache\Images()) MyDebug("Key : " + key + " added in memory cache", 3) ;*** EndIf If *timg\Tile = 0 ; Check if a loading thread is not already running - img = GetTileFromHDD(CacheFile.s) - If img <> -1 + ; Is the file image on HDD ? + *timg\nImage = GetTileFromHDD(CacheFile.s) + If *timg\nImage ; Image found and loaded from HDD - *timg\nImage = img *timg\Alpha = 256 ProcedureReturn *timg EndIf @@ -1188,7 +1194,7 @@ Module PBMap Protected *NewTile.Tile = AllocateMemory(SizeOf(Tile)) If *NewTile With *NewTile - *timg\Tile = *NewTile + *timg\Tile = *NewTile ; There's now a loading thread *timg\Alpha = 0 ;*timg\nImage = -1 ;New tile parameters @@ -1293,7 +1299,7 @@ Module PBMap EndSelect EndWith *timg = GetTile(key, URL, CacheFile) - If *timg And *timg\nImage <> -1 + If *timg And *timg\nImage MovePathCursor(px, py) If *timg\Alpha <= 224 DrawVectorImage(ImageID(*timg\nImage), *timg\Alpha * PBMap\Layers()\Alpha) @@ -2382,8 +2388,8 @@ Module PBMap Protected timg = PBMap\MemCache\Images(key)\Tile\nImage ; Get this new tile image nb PBMap\MemCache\Images(key)\nImage = timg ; Stores it in the cache using the key FreeMemory(PBMap\MemCache\Images(key)\Tile) ; Frees the data needed for the thread - PBMap\MemCache\Images(key)\Tile = 0 ; Clears the data ptr - PBMap\ThreadsNB - 1 ; The web loading thread is finished + PBMap\MemCache\Images(key)\Tile = 0 ; Clears the data ptr, the web loading thread is finished + PBMap\ThreadsNB - 1 PBMap\Redraw = #True EndSelect EndProcedure @@ -2624,7 +2630,7 @@ CompilerIf #PB_Compiler_IsMainFile ;Our main gadget PBMap::InitPBMap(#Window_0) PBMap::SetOption("ShowDegrees", "1") : Degrees = 0 - PBMap::SetOption("ShowDebugInfos", "3") + PBMap::SetOption("ShowDebugInfos", "1") PBMap::SetOption("Verbose", "1") PBMap::SetOption("ShowScale", "1") PBMap::SetOption("Warning", "1") @@ -2768,8 +2774,8 @@ CompilerIf #PB_Compiler_IsMainFile CompilerEndIf ; IDE Options = PureBasic 5.60 (Windows - x64) -; CursorPosition = 1123 -; FirstLine = 1130 +; CursorPosition = 1067 +; FirstLine = 1055 ; Folding = ------------------- ; EnableThread ; EnableXP From bbf5be2efdc066645f0e82330f15d7f9dcf64fd1 Mon Sep 17 00:00:00 2001 From: djes Date: Thu, 8 Jun 2017 15:02:34 +0200 Subject: [PATCH 03/16] New cache mechanism and thread overload fixed --- PBMap.pb | 145 +++++++++++++++++++++++++++++++++---------------------- 1 file changed, 86 insertions(+), 59 deletions(-) diff --git a/PBMap.pb b/PBMap.pb index 2f2dd01..f214443 100644 --- a/PBMap.pb +++ b/PBMap.pb @@ -303,7 +303,7 @@ Module PBMap ;-*** Global variables ;-Show debug infos - Global MyDebugLevel = 0 + Global MyDebugLevel = 5 Global PBMap.PBMap, Null.i, NullPtrMem.i, *NullPtr = @NullPtrMem Global slash.s @@ -1063,17 +1063,17 @@ Module PBMap ProcedureReturn 0 EndProcedure - Procedure.i GetTileFromWeb(TileURL.s, CacheFile.s) - ;Debug TileURL - If ReceiveHTTPFile(TileURL, CacheFile) - MyDebug(" Loaded from web " + TileURL + " as CacheFile " + CacheFile, 3) - ; Debug TileURL + " OK" - ProcedureReturn GetTileFromHDD(CacheFile) - Else - MyDebug(" Problem receving from web " + TileURL + " as CacheFile " + CacheFile, 3) - ; Debug TileURL + " NOT OK" - ProcedureReturn -1 - EndIf +; Procedure.i GetTileFromWeb(TileURL.s, CacheFile.s) +; ;Debug TileURL +; If ReceiveHTTPFile(TileURL, CacheFile, #PB_HTTP_Asynchronous) +; MyDebug(" Loaded from web " + TileURL + " as CacheFile " + CacheFile, 3) +; ; Debug TileURL + " OK" +; ProcedureReturn GetTileFromHDD(CacheFile) +; Else +; MyDebug(" Problem receving from web " + TileURL + " as CacheFile " + CacheFile, 3) +; ; Debug TileURL + " NOT OK" +; ProcedureReturn -1 +; EndIf ; **** (OLD) IMPORTANT NOTICE (please not remove) ; I'm (djes) now using Curl (actually, just normal pb) only, as this original catchimage/saveimage method is a double operation (uncompress/recompress PNG) ; and is modifying the original PNG image which could lead to PNG error (Idle has spent hours debunking the 1 bit PNG bug) @@ -1099,22 +1099,47 @@ Module PBMap ; MyDebug(" Problem loading from web " + TileURL, 3) ; EndIf ; **** - EndProcedure +; EndProcedure Procedure GetImageThread(*Tile.Tile) - MyDebug("Thread for image key " + *Tile\key, 3) - Repeat - *Tile\nImage = GetTileFromWeb(*Tile\URL, *Tile\CacheFile) - If *Tile\nImage <> -1 - *Tile\RetryNb = 0 - Else - Delay(2000) - *Tile\RetryNb - 1 - EndIf - Until *Tile\RetryNb <= 0 - MyDebug(" Thread for image key " + *Tile\key + " finished", 3) - *Tile\RetryNb = -2 ;End of the thread - PostEvent(#PB_Event_Gadget, PBMap\Window, PBmap\Gadget, #PB_MAP_TILE_CLEANUP, *Tile) ;To free memory outside the thread + Protected Download, Progress, Size + MyDebug("Thread starting for image " + *Tile\CacheFile + "(" + *Tile\key + ")", 3) + Download = ReceiveHTTPFile(*Tile\URL, *Tile\CacheFile, #PB_HTTP_Asynchronous) + If Download + Repeat + Progress = HTTPProgress(Download) + Select Progress + Case #PB_Http_Success + Size = FinishHTTP(Download) + MyDebug(" Thread for image " + *Tile\CacheFile + " finished. Size : " + Str(Size), 3) + PostEvent(#PB_Event_Gadget, PBMap\Window, PBmap\Gadget, #PB_MAP_TILE_CLEANUP, *Tile) ;To free memory outside the thread + ProcedureReturn + Case #PB_Http_Failed + MyDebug(" Thread for image " + *Tile\CacheFile + " failed.", 3) + PostEvent(#PB_Event_Gadget, PBMap\Window, PBmap\Gadget, #PB_MAP_TILE_CLEANUP, *Tile) ;To free memory outside the thread + ProcedureReturn + Case #PB_Http_Aborted + MyDebug(" Thread for image " + *Tile\CacheFile + " aborted.", 3) + PostEvent(#PB_Event_Gadget, PBMap\Window, PBmap\Gadget, #PB_MAP_TILE_CLEANUP, *Tile) ;To free memory outside the thread + ProcedureReturn + Default + MyDebug(" Thread for image " + *Tile\CacheFile + " downloading " + Str(Progress) + " bytes", 3) + EndSelect + Delay(500) ; Frees CPU + ForEver + EndIf +; Repeat +; *Tile\nImage = GetTileFromWeb(*Tile\URL, *Tile\CacheFile) +; If *Tile\nImage <> -1 +; *Tile\RetryNb = 0 +; Else +; Delay(2000) +; *Tile\RetryNb - 1 +; EndIf +; Until *Tile\RetryNb <= 0 +; MyDebug(" Thread for image key " + *Tile\key + " finished", 3) +; *Tile\RetryNb = -2 ;End of the thread +; PostEvent(#PB_Event_Gadget, PBMap\Window, PBmap\Gadget, #PB_MAP_TILE_CLEANUP, *Tile) ;To free memory outside the thread EndProcedure ;-*** @@ -1136,35 +1161,37 @@ Module PBMap EndIf Else ;*** Cache management - ; if cache size exceeds limit, try to delete the oldest tiles used (first in the time stack) - Protected CacheSize = MapSize(PBMap\MemCache\Images()) * Pow(PBMap\TileSize, 2) * 4 ; Size of a tile = TileSize * TileSize * 4 bytes (RGBA) - Protected CacheLimit = PBMap\Options\MaxMemCache * 1024 - MyDebug("Cache size : " + Str(CacheSize/1024) + " / CacheLimit : " + Str(CacheLimit/1024), 3) - If CacheSize > CacheLimit - MyDebug(" Cache full. Trying cache cleaning", 3) - ResetList(PBMap\MemCache\ImagesTimeStack()) - ; Try to free half the cache memory (one pass) - While NextElement(PBMap\MemCache\ImagesTimeStack()) And CacheSize > (CacheLimit / 2) ; /2 = half - Protected CacheMapKey.s = PBMap\MemCache\ImagesTimeStack()\MapKey - Protected Image = PBMap\MemCache\Images(CacheMapKey)\nImage - If IsImage(Image) ; Check if the image is valid (is a loading thread running ?) - FreeImage(Image) - DeleteMapElement(PBMap\MemCache\Images(), CacheMapKey) - DeleteElement(PBMap\MemCache\ImagesTimeStack()) - MyDebug(" Delete " + CacheMapKey + " as image nb " + Str(Image), 3) - EndIf - CacheSize = MapSize(PBMap\MemCache\Images()) * Pow(PBMap\TileSize, 2) * 4 ; Size of a tile = TileSize * TileSize * 4 bytes (RGBA) - Wend - MyDebug(" New cache size : " + Str(CacheSize/1024) + " / CacheLimit : " + Str(CacheLimit/1024), 3) - If CacheSize > CacheLimit - MyDebug(" Cache cleaning unsuccessfull, can't add new tiles.", 3) - ProcedureReturn 0 - EndIf + ; If cache size exceeds limit, try to delete the oldest tiles used (first in the time stack) + Protected CacheSize = MapSize(PBMap\MemCache\Images()) * Pow(PBMap\TileSize, 2) * 5 ; Size of a tile = TileSize * TileSize * 4 bytes (RGBA) + Protected CacheLimit = PBMap\Options\MaxMemCache * 1024 + MyDebug("Cache size : " + Str(CacheSize/1024) + " / CacheLimit : " + Str(CacheLimit/1024), 5) + If CacheSize > CacheLimit + MyDebug(" Cache full. Trying cache cleaning", 5) + ResetList(PBMap\MemCache\ImagesTimeStack()) + ; Try to free half the cache memory (one pass) + While NextElement(PBMap\MemCache\ImagesTimeStack()) And CacheSize > (CacheLimit / 2) ; /2 = half + Protected CacheMapKey.s = PBMap\MemCache\ImagesTimeStack()\MapKey + Protected Image = PBMap\MemCache\Images(CacheMapKey)\nImage + If PBMap\MemCache\Images(CacheMapKey)\Tile = 0 ; Check if a loading thread is not already running + If IsImage(Image) ; Check if the image is valid + FreeImage(Image) + EndIf + DeleteMapElement(PBMap\MemCache\Images(), CacheMapKey) + DeleteElement(PBMap\MemCache\ImagesTimeStack()) + MyDebug(" Delete " + CacheMapKey + " as image nb " + Str(Image), 5) + EndIf + CacheSize = MapSize(PBMap\MemCache\Images()) * Pow(PBMap\TileSize, 2) * 4 ; Size of a tile = TileSize * TileSize * 4 bytes (RGBA) + Wend + MyDebug(" New cache size : " + Str(CacheSize/1024) + " / CacheLimit : " + Str(CacheLimit/1024), 5) + If CacheSize > CacheLimit + MyDebug(" Cache cleaning unsuccessfull, can't add new tiles.", 5) + ProcedureReturn 0 + EndIf EndIf ; Creates a new cache element *timg = AddMapElement(PBMap\MemCache\Images(), key) If *timg = 0 - MyDebug(" Can't add a new cache element.", 3) + MyDebug(" Can't add a new cache element.", 5) ProcedureReturn 0 EndIf ; add a new time stack element at the End @@ -1172,16 +1199,16 @@ Module PBMap ; Stores the time stack ptr *timg\TimeStackPtr = AddElement(PBMap\MemCache\ImagesTimeStack()) If *timg\TimeStackPtr = 0 - MyDebug(" Can't add a new time stack element.", 3) + MyDebug(" Can't add a new time stack element.", 5) DeleteMapElement(PBMap\MemCache\Images()) ProcedureReturn 0 EndIf ; Associates the time stack element to the cache element PBMap\MemCache\ImagesTimeStack()\MapKey = MapKey(PBMap\MemCache\Images()) - MyDebug("Key : " + key + " added in memory cache", 3) + MyDebug("Key : " + key + " added in memory cache", 5) ;*** EndIf - If *timg\Tile = 0 ; Check if a loading thread is not already running + If *timg\Tile = 0 ; Checks if a loading thread is not already running ; Is the file image on HDD ? *timg\nImage = GetTileFromHDD(CacheFile.s) If *timg\nImage @@ -1202,7 +1229,7 @@ Module PBMap \URL = URL \CacheFile = CacheFile \RetryNb = 5 - \nImage = -1 + \nImage = 0 \GetImageThread = CreateThread(@GetImageThread(), *NewTile) If \GetImageThread MyDebug(" Creating get image thread nb " + Str(\GetImageThread) + " to get " + CacheFile, 3) @@ -2630,8 +2657,8 @@ CompilerIf #PB_Compiler_IsMainFile ;Our main gadget PBMap::InitPBMap(#Window_0) PBMap::SetOption("ShowDegrees", "1") : Degrees = 0 - PBMap::SetOption("ShowDebugInfos", "1") - PBMap::SetOption("Verbose", "1") + PBMap::SetOption("ShowDebugInfos", "0") + PBMap::SetOption("Verbose", "0") PBMap::SetOption("ShowScale", "1") PBMap::SetOption("Warning", "1") PBMap::SetOption("ShowMarkersLegend", "1") @@ -2774,8 +2801,8 @@ CompilerIf #PB_Compiler_IsMainFile CompilerEndIf ; IDE Options = PureBasic 5.60 (Windows - x64) -; CursorPosition = 1067 -; FirstLine = 1055 +; CursorPosition = 871 +; FirstLine = 858 ; Folding = ------------------- ; EnableThread ; EnableXP From 1de62dfb1698c9d76af81b63aeba6ed988bb7f75 Mon Sep 17 00:00:00 2001 From: djes Date: Fri, 9 Jun 2017 13:49:29 +0200 Subject: [PATCH 04/16] Caching mechanism enhanced + better downloading wip --- PBMap.pb | 222 +++++++++++++++++++++++++++---------------------------- 1 file changed, 110 insertions(+), 112 deletions(-) diff --git a/PBMap.pb b/PBMap.pb index f214443..4d258e3 100644 --- a/PBMap.pb +++ b/PBMap.pb @@ -124,7 +124,7 @@ Module PBMap URL.s CacheFile.s GetImageThread.i - RetryNb.i + Download.i EndStructure Structure BoundingBox @@ -288,6 +288,7 @@ Module PBMap Redraw.i Dragging.i Dirty.i ; To signal that drawing need a refresh + MemoryCacheManagement.i ; To pause web loading threads List TracksList.Tracks() ; To display a GPX track List Markers.Marker() ; To diplay marker @@ -881,7 +882,7 @@ Module PBMap PreferenceGroup("OPTIONS") \WheelMouseRelative = ReadPreferenceInteger("WheelMouseRelative", #True) \MaxMemCache = ReadPreferenceInteger("MaxMemCache", 20480) ;20 MiB, about 80 tiles in memory - \MaxThreads = ReadPreferenceInteger("MaxThreads", 40) + \MaxThreads = ReadPreferenceInteger("MaxThreads", 10) \TileLifetime = ReadPreferenceInteger("TileLifetime", 1209600) ;about 2 weeks ; -1 = unlimited \Verbose = ReadPreferenceInteger("Verbose", #False) \Warning = ReadPreferenceInteger("Warning", #False) @@ -900,7 +901,7 @@ Module PBMap \ColourFocus = ReadPreferenceInteger("ColourFocus", RGBA(255, 255, 0, 255)) \ColourSelected = ReadPreferenceInteger("ColourSelected", RGBA(225, 225, 0, 255)) \ColourTrackDefault = ReadPreferenceInteger("ColourTrackDefault", RGBA(0, 255, 0, 150)) - \TimerInterval = 20 + \TimerInterval = 12 ClosePreferences() EndWith SetOptions() @@ -1030,12 +1031,52 @@ Module PBMap ProcedureReturn PBMap\Layers(Name)\Alpha EndProcedure + Procedure MemoryCacheManagement() + ; If cache size exceeds limit, try to delete the oldest tiles used (first in the time stack) + Protected CacheSize = MapSize(PBMap\MemCache\Images()) * Pow(PBMap\TileSize, 2) * 5 ; Size of a tile = TileSize * TileSize * 4 bytes (RGBA) + Protected CacheLimit = PBMap\Options\MaxMemCache * 1024 + MyDebug("Cache size : " + Str(CacheSize/1024) + " / CacheLimit : " + Str(CacheLimit/1024), 5) + If CacheSize > CacheLimit + PBMap\MemoryCacheManagement = #True + MyDebug(" Cache full. Trying cache cleaning", 5) + ResetList(PBMap\MemCache\ImagesTimeStack()) + ; Try to free half the cache memory (one pass) + While NextElement(PBMap\MemCache\ImagesTimeStack()) And CacheSize > (CacheLimit / 2) ; /2 = half + Protected CacheMapKey.s = PBMap\MemCache\ImagesTimeStack()\MapKey + Protected Image = PBMap\MemCache\Images(CacheMapKey)\nImage + If PBMap\MemCache\Images(CacheMapKey)\Tile = 0 ; Check if a loading thread is not already running + MyDebug(" Delete " + CacheMapKey, 5) + If IsImage(Image) ; Check if the image is valid + FreeImage(Image) + MyDebug(" and free image nb " + Str(Image), 5) + EndIf + DeleteMapElement(PBMap\MemCache\Images(), CacheMapKey) + DeleteElement(PBMap\MemCache\ImagesTimeStack()) + Else + ; If the thread is running, try to abort the download + If PBMap\MemCache\Images(CacheMapKey)\Tile\Download + AbortHTTP(PBMap\MemCache\Images(CacheMapKey)\Tile\Download) + EndIf + EndIf + CacheSize = MapSize(PBMap\MemCache\Images()) * Pow(PBMap\TileSize, 2) * 4 ; Size of a tile = TileSize * TileSize * 4 bytes (RGBA) + Wend + PBMap\MemoryCacheManagement = #False + MyDebug(" New cache size : " + Str(CacheSize/1024) + " / CacheLimit : " + Str(CacheLimit/1024), 5) + If CacheSize > CacheLimit + MyDebug(" Cache cleaning unsuccessfull, can't add new tiles.", 5) + ProcedureReturn 0 + EndIf + EndIf + EndProcedure + ;-*** These are threaded + Threaded nImage.i, LifeTime.i, MaxLifeTime.i + Procedure.i GetTileFromHDD(CacheFile.s) - Protected nImage.i, LifeTime.i, MaxLifeTime.i = PBMap\Options\TileLifetime + MaxLifeTime.i = PBMap\Options\TileLifetime If FileSize(CacheFile) > 0 ;<> -1 - ;Manage tile file lifetime + ; Manage tile file lifetime If MaxLifeTime <> -1 LifeTime = Date() - GetFileDate(CacheFile, #PB_Date_Modified) ;There's a bug with #PB_Date_Created If LifeTime > MaxLifeTime @@ -1063,83 +1104,66 @@ Module PBMap ProcedureReturn 0 EndProcedure -; Procedure.i GetTileFromWeb(TileURL.s, CacheFile.s) -; ;Debug TileURL -; If ReceiveHTTPFile(TileURL, CacheFile, #PB_HTTP_Asynchronous) -; MyDebug(" Loaded from web " + TileURL + " as CacheFile " + CacheFile, 3) -; ; Debug TileURL + " OK" -; ProcedureReturn GetTileFromHDD(CacheFile) -; Else -; MyDebug(" Problem receving from web " + TileURL + " as CacheFile " + CacheFile, 3) -; ; Debug TileURL + " NOT OK" -; ProcedureReturn -1 -; EndIf - ; **** (OLD) IMPORTANT NOTICE (please not remove) - ; I'm (djes) now using Curl (actually, just normal pb) only, as this original catchimage/saveimage method is a double operation (uncompress/recompress PNG) - ; and is modifying the original PNG image which could lead to PNG error (Idle has spent hours debunking the 1 bit PNG bug) - ; More than that, the original Purebasic Receive library is still not Proxy enabled. - ;Protected *Buffer - ;Protected nImage.i = -1 - ;Protected timg - ; *Buffer = ReceiveHTTPMemory(TileURL) ;TODO to thread by using #PB_HTTP_Asynchronous - ; If *Buffer - ; nImage = CatchImage(#PB_Any, *Buffer, MemorySize(*Buffer)) - ; If IsImage(nImage) - ; If SaveImage(nImage, CacheFile, #PB_ImagePlugin_PNG, 0, 32) ;The 32 is needed !!!! - ; MyDebug("Loaded from web " + TileURL + " as CacheFile " + CacheFile, 3) - ; Else - ; MyDebug("Loaded from web " + TileURL + " but cannot save to CacheFile " + CacheFile, 3) - ; EndIf - ; FreeMemory(*Buffer) - ; Else - ; MyDebug("Can't catch image loaded from web " + TileURL, 3) - ; nImage = -1 - ; EndIf - ; Else - ; MyDebug(" Problem loading from web " + TileURL, 3) - ; EndIf - ; **** -; EndProcedure + ; **** OLD IMPORTANT NOTICE (please not remove) + ; This original catchimage/saveimage method is a double operation (uncompress/recompress PNG) + ; and is modifying the original PNG image which could lead to PNG error (Idle has spent hours debunking the 1 bit PNG bug) + ;Protected *Buffer + ;Protected nImage.i = -1 + ;Protected timg + ; *Buffer = ReceiveHTTPMemory(TileURL) ;TODO to thread by using #PB_HTTP_Asynchronous + ; If *Buffer + ; nImage = CatchImage(#PB_Any, *Buffer, MemorySize(*Buffer)) + ; If IsImage(nImage) + ; If SaveImage(nImage, CacheFile, #PB_ImagePlugin_PNG, 0, 32) ;The 32 is needed !!!! + ; MyDebug("Loaded from web " + TileURL + " as CacheFile " + CacheFile, 3) + ; Else + ; MyDebug("Loaded from web " + TileURL + " but cannot save to CacheFile " + CacheFile, 3) + ; EndIf + ; FreeMemory(*Buffer) + ; Else + ; MyDebug("Can't catch image loaded from web " + TileURL, 3) + ; nImage = -1 + ; EndIf + ; Else + ; MyDebug(" Problem loading from web " + TileURL, 3) + ; EndIf + ; **** + + Threaded Progress = 0, Size = 0 Procedure GetImageThread(*Tile.Tile) - Protected Download, Progress, Size - MyDebug("Thread starting for image " + *Tile\CacheFile + "(" + *Tile\key + ")", 3) - Download = ReceiveHTTPFile(*Tile\URL, *Tile\CacheFile, #PB_HTTP_Asynchronous) - If Download + MyDebug("Thread starting for image " + *Tile\CacheFile + "(" + *Tile\key + ")", 5) + *Tile\Download = ReceiveHTTPFile(*Tile\URL, *Tile\CacheFile, #PB_HTTP_Asynchronous) + If *Tile\Download Repeat - Progress = HTTPProgress(Download) - Select Progress - Case #PB_Http_Success - Size = FinishHTTP(Download) - MyDebug(" Thread for image " + *Tile\CacheFile + " finished. Size : " + Str(Size), 3) - PostEvent(#PB_Event_Gadget, PBMap\Window, PBmap\Gadget, #PB_MAP_TILE_CLEANUP, *Tile) ;To free memory outside the thread - ProcedureReturn - Case #PB_Http_Failed - MyDebug(" Thread for image " + *Tile\CacheFile + " failed.", 3) - PostEvent(#PB_Event_Gadget, PBMap\Window, PBmap\Gadget, #PB_MAP_TILE_CLEANUP, *Tile) ;To free memory outside the thread - ProcedureReturn - Case #PB_Http_Aborted - MyDebug(" Thread for image " + *Tile\CacheFile + " aborted.", 3) - PostEvent(#PB_Event_Gadget, PBMap\Window, PBmap\Gadget, #PB_MAP_TILE_CLEANUP, *Tile) ;To free memory outside the thread - ProcedureReturn - Default - MyDebug(" Thread for image " + *Tile\CacheFile + " downloading " + Str(Progress) + " bytes", 3) - EndSelect + If PBMap\MemoryCacheManagement = #False ; Wait until cache cleaning is done + Progress = HTTPProgress(*Tile\Download) + Select Progress + Case #PB_Http_Success + Size = FinishHTTP(*Tile\Download) + MyDebug(" Thread for image " + *Tile\CacheFile + " finished. Size : " + Str(Size), 5) + PostEvent(#PB_Event_Gadget, PBMap\Window, PBmap\Gadget, #PB_MAP_TILE_CLEANUP, *Tile) ;To free memory outside the thread + *Tile\Download = 0 + ProcedureReturn #True + Case #PB_Http_Failed + FinishHTTP(*Tile\Download) + MyDebug(" Thread for image " + *Tile\CacheFile + " failed.", 5) + PostEvent(#PB_Event_Gadget, PBMap\Window, PBmap\Gadget, #PB_MAP_TILE_CLEANUP, *Tile) ;To free memory outside the thread + *Tile\Download = 0 + ProcedureReturn #False + Case #PB_Http_Aborted + FinishHTTP(*Tile\Download) + MyDebug(" Thread for image " + *Tile\CacheFile + " aborted.", 5) + PostEvent(#PB_Event_Gadget, PBMap\Window, PBmap\Gadget, #PB_MAP_TILE_CLEANUP, *Tile) ;To free memory outside the thread + *Tile\Download = 0 + ProcedureReturn #False + Default + MyDebug(" Thread for image " + *Tile\CacheFile + " downloading " + Str(Progress) + " bytes", 5) + EndSelect + EndIf Delay(500) ; Frees CPU ForEver EndIf -; Repeat -; *Tile\nImage = GetTileFromWeb(*Tile\URL, *Tile\CacheFile) -; If *Tile\nImage <> -1 -; *Tile\RetryNb = 0 -; Else -; Delay(2000) -; *Tile\RetryNb - 1 -; EndIf -; Until *Tile\RetryNb <= 0 -; MyDebug(" Thread for image key " + *Tile\key + " finished", 3) -; *Tile\RetryNb = -2 ;End of the thread -; PostEvent(#PB_Event_Gadget, PBMap\Window, PBmap\Gadget, #PB_MAP_TILE_CLEANUP, *Tile) ;To free memory outside the thread EndProcedure ;-*** @@ -1148,9 +1172,9 @@ Module PBMap ; HDD, or launch a web loading thread, and try again on the next drawing loop. Protected *timg.ImgMemCach = FindMapElement(PBMap\MemCache\Images(), key) If *timg - MyDebug("Key : " + key + " found in memory cache", 3) + MyDebug("Key : " + key + " found in memory cache", 5) If *timg\nImage - MyDebug(" as image " + *timg\nImage, 3) + MyDebug(" as image " + *timg\nImage, 5) ;*** Cache management ; Retrieves the image in the time stack, push it to the end (to say it's the lastly used) ChangeCurrentElement(PBMap\MemCache\ImagesTimeStack(), *timg\TimeStackPtr) @@ -1158,36 +1182,10 @@ Module PBMap ;*timg\TimeStackPtr = LastElement(PBMap\MemCache\ImagesTimeStack()) ;*** ProcedureReturn *timg + Else + MyDebug(" but not the image.", 5) EndIf Else - ;*** Cache management - ; If cache size exceeds limit, try to delete the oldest tiles used (first in the time stack) - Protected CacheSize = MapSize(PBMap\MemCache\Images()) * Pow(PBMap\TileSize, 2) * 5 ; Size of a tile = TileSize * TileSize * 4 bytes (RGBA) - Protected CacheLimit = PBMap\Options\MaxMemCache * 1024 - MyDebug("Cache size : " + Str(CacheSize/1024) + " / CacheLimit : " + Str(CacheLimit/1024), 5) - If CacheSize > CacheLimit - MyDebug(" Cache full. Trying cache cleaning", 5) - ResetList(PBMap\MemCache\ImagesTimeStack()) - ; Try to free half the cache memory (one pass) - While NextElement(PBMap\MemCache\ImagesTimeStack()) And CacheSize > (CacheLimit / 2) ; /2 = half - Protected CacheMapKey.s = PBMap\MemCache\ImagesTimeStack()\MapKey - Protected Image = PBMap\MemCache\Images(CacheMapKey)\nImage - If PBMap\MemCache\Images(CacheMapKey)\Tile = 0 ; Check if a loading thread is not already running - If IsImage(Image) ; Check if the image is valid - FreeImage(Image) - EndIf - DeleteMapElement(PBMap\MemCache\Images(), CacheMapKey) - DeleteElement(PBMap\MemCache\ImagesTimeStack()) - MyDebug(" Delete " + CacheMapKey + " as image nb " + Str(Image), 5) - EndIf - CacheSize = MapSize(PBMap\MemCache\Images()) * Pow(PBMap\TileSize, 2) * 4 ; Size of a tile = TileSize * TileSize * 4 bytes (RGBA) - Wend - MyDebug(" New cache size : " + Str(CacheSize/1024) + " / CacheLimit : " + Str(CacheLimit/1024), 5) - If CacheSize > CacheLimit - MyDebug(" Cache cleaning unsuccessfull, can't add new tiles.", 5) - ProcedureReturn 0 - EndIf - EndIf ; Creates a new cache element *timg = AddMapElement(PBMap\MemCache\Images(), key) If *timg = 0 @@ -1228,7 +1226,6 @@ Module PBMap \key = key \URL = URL \CacheFile = CacheFile - \RetryNb = 5 \nImage = 0 \GetImageThread = CreateThread(@GetImageThread(), *NewTile) If \GetImageThread @@ -2424,6 +2421,7 @@ Module PBMap ; Redraws at regular intervals Procedure TimerEvents() If EventTimer() = PBMap\Timer And (PBMap\Redraw Or PBMap\Dirty) + MemoryCacheManagement() Drawing() EndIf EndProcedure @@ -2451,13 +2449,13 @@ Module PBMap Procedure Quit() PBMap\Drawing\End = #True + PBMap\MemoryCacheManagement = #True ; Tells web loading threads to pause ;Wait for loading threads to finish nicely. Passed 2 seconds, kills them. Protected TimeCounter = ElapsedMilliseconds() Repeat ForEach PBMap\MemCache\Images() If PBMap\MemCache\Images()\Tile <> 0 If IsThread(PBMap\MemCache\Images()\Tile\GetImageThread) - PBMap\MemCache\Images()\Tile\RetryNb = 0 If ElapsedMilliseconds() - TimeCounter > 2000 ;Should not occur KillThread(PBMap\MemCache\Images()\Tile\GetImageThread) @@ -2657,8 +2655,8 @@ CompilerIf #PB_Compiler_IsMainFile ;Our main gadget PBMap::InitPBMap(#Window_0) PBMap::SetOption("ShowDegrees", "1") : Degrees = 0 - PBMap::SetOption("ShowDebugInfos", "0") - PBMap::SetOption("Verbose", "0") + PBMap::SetOption("ShowDebugInfos", "1") + PBMap::SetOption("Verbose", "1") PBMap::SetOption("ShowScale", "1") PBMap::SetOption("Warning", "1") PBMap::SetOption("ShowMarkersLegend", "1") @@ -2801,8 +2799,8 @@ CompilerIf #PB_Compiler_IsMainFile CompilerEndIf ; IDE Options = PureBasic 5.60 (Windows - x64) -; CursorPosition = 871 -; FirstLine = 858 +; CursorPosition = 893 +; FirstLine = 894 ; Folding = ------------------- ; EnableThread ; EnableXP From 530273a93457fbfb9ca5c10dcdf81f3211bb604b Mon Sep 17 00:00:00 2001 From: djes Date: Fri, 9 Jun 2017 15:16:08 +0200 Subject: [PATCH 05/16] Added download slots and automatic download cancellation after a delay --- PBMap.pb | 560 +++++++++++++++++++++++++++++-------------------------- 1 file changed, 299 insertions(+), 261 deletions(-) diff --git a/PBMap.pb b/PBMap.pb index 4d258e3..d2fb5a2 100644 --- a/PBMap.pb +++ b/PBMap.pb @@ -1,15 +1,15 @@ -;******************************************************************** +; ******************************************************************** ; Program: PBMap ; Description: Permits the use of tiled maps like ; OpenStreetMap in a handy PureBASIC module ; Author: Thyphoon, djes And Idle ; Date: March, 2017 ; License: PBMap : Free, unrestricted, credit -; appreciated but not required. -; OSM : see http://www.openstreetmap.org/copyright +; appreciated but not required. +; OSM : see http://www.openstreetmap.org/copyright ; Note: Please share improvement ! ; Thanks: Progi1984, yves86 -;******************************************************************** +; ******************************************************************** CompilerIf #PB_Compiler_Thread = #False MessageRequester("Warning !", "You must enable ThreadSafe support in compiler options", #PB_MessageRequester_Ok ) @@ -78,9 +78,9 @@ DeclareModule PBMap Declare SetZoom(Zoom.i, mode.i = #PB_Relative) Declare SetZoomToArea(MinY.d, MaxY.d, MinX.d, MaxX.d) Declare SetZoomToTracks(*Tracks) - Declare NominatimGeoLocationQuery(Address.s, *ReturnPosition = 0) ;Send back the position *ptr.GeographicCoordinates - Declare.i LoadGpxFile(FileName.s) ; - Declare.i SaveGpxFile(FileName.s, *Track) ; + Declare NominatimGeoLocationQuery(Address.s, *ReturnPosition = 0) ; Send back the position *ptr.GeographicCoordinates + Declare.i LoadGpxFile(FileName.s) ; + Declare.i SaveGpxFile(FileName.s, *Track) ; Declare ClearTracks() Declare DeleteTrack(*Ptr) Declare DeleteSelectedTracks() @@ -125,6 +125,7 @@ Module PBMap CacheFile.s GetImageThread.i Download.i + Time.i EndStructure Structure BoundingBox @@ -198,18 +199,19 @@ Module PBMap TimerInterval.i MaxMemCache.i ; in MiB MaxThreads.i ; Maximum simultaneous web loading threads + MaxDownloadSlots.i ; Maximum simultaneous download slots TileLifetime.i Verbose.i ; Maximum debug informations Warning.i ; Warning requesters ShowMarkersNb.i ShowMarkersLegend.i - ;Drawing stuff + ; Drawing stuff StrokeWidthTrackDefault.i - ;Colours + ; Colours ColourFocus.i ColourSelected.i ColourTrackDefault.i - ;HERE specific + ; HERE specific appid.s appcode.s EndStructure @@ -223,7 +225,7 @@ Module PBMap Enabled.i Alpha.d ; 1 : opaque ; 0 : transparent format.s - ;> HERE specific params + ; > HERE specific params APP_ID.s APP_CODE.s ressource.s @@ -232,10 +234,10 @@ Module PBMap scheme.s lg.s lg2.s - ;< - ;> GeoServer specific params + ; < + ; > GeoServer specific params ServerLayerName.s - ;< + ; < EndStructure Structure Box @@ -288,8 +290,11 @@ Module PBMap Redraw.i Dragging.i Dirty.i ; To signal that drawing need a refresh - MemoryCacheManagement.i ; To pause web loading threads + MemoryCacheManagement.i ; To pause web loading threads + DownloadSlots.i ; Actual nb of used download slots + DownloadSlotsMutex.i ; To be sure that only one thread at a time can access to the DownloadSlots var + List TracksList.Tracks() ; To display a GPX track List Markers.Marker() ; To diplay marker EditMarker.l @@ -318,7 +323,7 @@ Module PBMap ;- *** GetText - Translation purpose - ;TODO use this for all text + ; TODO use this for all text IncludeFile "gettext.pbi" ;-*** Misc tools @@ -333,7 +338,7 @@ Module PBMap ;-Error management - ;Shows an error msg and terminates the program + ; Shows an error msg and terminates the program Procedure FatalError(msg.s) If PBMap\Options\Warning MessageRequester("PBMap", msg, #PB_MessageRequester_Ok) @@ -341,31 +346,31 @@ Module PBMap End EndProcedure - ;Shows an error msg + ; Shows an error msg Procedure Error(msg.s) If PBMap\Options\Warning MessageRequester("PBMap", msg, #PB_MessageRequester_Ok) EndIf EndProcedure - ;Send debug infos to stdout (allowing mixed debug infos with curl or other libs) + ; Send debug infos to stdout (allowing mixed debug infos with curl or other libs) Procedure MyDebug(msg.s, DbgLevel = 0) If PBMap\Options\Verbose And DbgLevel >= MyDebugLevel PrintN(msg) - ;Debug msg + ; Debug msg EndIf EndProcedure - ;Creates a full tree - ;by Thomas (ts-soft) Schulz - ;http://www.purebasic.fr/english/viewtopic.php?f=12&t=58657&hilit=createdirectory&view=unread#unread + ; Creates a full tree + ; by Thomas (ts-soft) Schulz + ; http://www.purebasic.fr/english/viewtopic.php?f=12&t=58657&hilit=createdirectory&view=unread#unread CompilerSelect #PB_Compiler_OS CompilerCase #PB_OS_Windows - #FILE_ATTRIBUTE_DEVICE = 64 ;(0x40) - #FILE_ATTRIBUTE_INTEGRITY_STREAM = 32768 ;(0x8000) - #FILE_ATTRIBUTE_NOT_CONTENT_INDEXED = 8192;(0x2000) - #FILE_ATTRIBUTE_NO_SCRUB_DATA = 131072;(0x20000) - #FILE_ATTRIBUTE_VIRTUAL = 65536;(0x10000) + #FILE_ATTRIBUTE_DEVICE = 64 ; (0x40) + #FILE_ATTRIBUTE_INTEGRITY_STREAM = 32768 ; (0x8000) + #FILE_ATTRIBUTE_NOT_CONTENT_INDEXED = 8192; (0x2000) + #FILE_ATTRIBUTE_NO_SCRUB_DATA = 131072; (0x20000) + #FILE_ATTRIBUTE_VIRTUAL = 65536; (0x10000) #FILE_ATTRIBUTE_DONTSETFLAGS = ~(#FILE_ATTRIBUTE_DIRECTORY| #FILE_ATTRIBUTE_SPARSE_FILE| #FILE_ATTRIBUTE_OFFLINE| @@ -403,7 +408,7 @@ Module PBMap EndProcedure Procedure TechnicalImagesCreation() - ;"Loading" image + ; "Loading" image Protected LoadingText$ = "Loading" Protected NothingText$ = "Nothing" PBmap\ImgLoading = CreateImage(#PB_Any, 256, 256) @@ -421,20 +426,20 @@ Module PBMap EndVectorLayer() StopVectorDrawing() EndIf - ;"Nothing" tile + ; "Nothing" tile PBmap\ImgNothing = CreateImage(#PB_Any, 256, 256) If PBmap\ImgNothing StartVectorDrawing(ImageVectorOutput(PBMap\ImgNothing)) - ;BeginVectorLayer() + ; BeginVectorLayer() VectorSourceColor(RGBA(220, 230, 255, 255)) AddPathBox(0, 0, 256, 256) FillPath() - ;MovePathCursor(0, 0) - ;VectorFont(FontID(PBMap\Font), 256 / 20) - ;VectorSourceColor(RGBA(150, 150, 150, 255)) - ;MovePathCursor(0 + (256 - VectorTextWidth(NothingText$)) / 2, 0 + (256 - VectorTextHeight(NothingText$)) / 2) - ;DrawVectorText(NothingText$) - ;EndVectorLayer() + ; MovePathCursor(0, 0) + ; VectorFont(FontID(PBMap\Font), 256 / 20) + ; VectorSourceColor(RGBA(150, 150, 150, 255)) + ; MovePathCursor(0 + (256 - VectorTextWidth(NothingText$)) / 2, 0 + (256 - VectorTextHeight(NothingText$)) / 2) + ; DrawVectorText(NothingText$) + ; EndVectorLayer() StopVectorDrawing() EndIf EndProcedure @@ -445,22 +450,22 @@ Module PBMap ProcedureReturn Result EndProcedure - ;*** Converts coords to tile.decimal - ;Warning, structures used in parameters are not tested + ; *** Converts coords to tile.decimal + ; Warning, structures used in parameters are not tested Procedure LatLon2TileXY(*Location.GeographicCoordinates, *Coords.Coordinates, Zoom) Protected n.d = Pow(2.0, Zoom) Protected LatRad.d = Radian(*Location\Latitude) *Coords\x = n * (Mod( *Location\Longitude + 180.0, 360) / 360.0 ) *Coords\y = n * ( 1.0 - Log(Tan(LatRad) + (1.0/Cos(LatRad))) / #PI ) / 2.0 MyDebug("Latitude : " + StrD(*Location\Latitude) + " ; Longitude : " + StrD(*Location\Longitude), 5) - MyDebug("Coords X : " + Str(*Coords\x) + " ; Y : " + Str(*Coords\y), 5) + MyDebug("Coords X : " + Str(*Coords\x) + " ; Y : " + Str(*Coords\y), 5) EndProcedure - ;*** Converts tile.decimal to coords - ;Warning, structures used in parameters are not tested + ; *** Converts tile.decimal to coords + ; Warning, structures used in parameters are not tested Procedure TileXY2LatLon(*Coords.Coordinates, *Location.GeographicCoordinates, Zoom) Protected n.d = Pow(2.0, Zoom) - ;Ensures the longitude to be in the range [-180;180[ + ; Ensures the longitude to be in the range [-180; 180[ *Location\Longitude = Mod(Mod(*Coords\x / n * 360.0, 360.0) + 360.0, 360.0) - 180 *Location\Latitude = Degree(ATan(SinH(#PI * (1.0 - 2.0 * *Coords\y / n)))) If *Location\Latitude <= -89 @@ -473,7 +478,7 @@ Module PBMap Procedure Pixel2LatLon(*Coords.PixelCoordinates, *Location.GeographicCoordinates, Zoom) Protected n.d = PBMap\TileSize * Pow(2.0, Zoom) - ;Ensures the longitude to be in the range [-180;180[ + ; Ensures the longitude to be in the range [-180; 180[ *Location\Longitude = Mod(Mod(*Coords\x / n * 360.0, 360.0) + 360.0, 360.0) - 180 *Location\Latitude = Degree(ATan(SinH(#PI * (1.0 - 2.0 * *Coords\y / n)))) If *Location\Latitude <= -89 @@ -484,12 +489,12 @@ Module PBMap EndIf EndProcedure - ;Ensures the longitude to be in the range [-180;180[ + ; Ensures the longitude to be in the range [-180; 180[ Procedure.d ClipLongitude(Longitude.d) ProcedureReturn Mod(Mod(Longitude + 180, 360.0) + 360.0, 360.0) - 180 EndProcedure - ;Lat Lon coordinates 2 pixel absolute [0 to 2^Zoom * TileSize [ + ; Lat Lon coordinates 2 pixel absolute [0 to 2^Zoom * TileSize [ Procedure LatLon2Pixel(*Location.GeographicCoordinates, *Pixel.PixelCoordinates, Zoom) Protected tilemax = Pow(2.0, Zoom) * PBMap\TileSize Protected LatRad.d = Radian(*Location\Latitude) @@ -497,7 +502,7 @@ Module PBMap *Pixel\y = tilemax * ( 1.0 - Log(Tan(LatRad) + (1.0/Cos(LatRad))) / #PI ) / 2.0 EndProcedure - ;Lat Lon coordinates 2 pixel relative to the center of view + ; Lat Lon coordinates 2 pixel relative to the center of view Procedure LatLon2PixelRel(*Location.GeographicCoordinates, *Pixel.PixelCoordinates, Zoom) Protected tilemax = Pow(2.0, Zoom) * PBMap\TileSize Protected cx.d = PBMap\Drawing\RadiusX @@ -505,18 +510,18 @@ Module PBMap Protected LatRad.d = Radian(*Location\Latitude) Protected px.d = tilemax * (Mod( *Location\Longitude + 180.0, 360) / 360.0 ) Protected py.d = tilemax * ( 1.0 - Log(Tan(LatRad) + (1.0/Cos(LatRad))) / #PI ) / 2.0 - ;check the x boundaries of the map to adjust the position (coz of the longitude wrapping) + ; check the x boundaries of the map to adjust the position (coz of the longitude wrapping) If dpx - px >= tilemax / 2 - ;Debug "c1" + ; Debug "c1" *Pixel\x = cx + (px - dpx + tilemax) ElseIf px - dpx > tilemax / 2 - ;Debug "c2" + ; Debug "c2" *Pixel\x = cx + (px - dpx - tilemax) ElseIf px - dpx < 0 - ;Debug "c3" + ; Debug "c3" *Pixel\x = cx - (dpx - px) Else - ;Debug "c0" + ; Debug "c0" *Pixel\x = cx + (px - dpx) EndIf *Pixel\y = PBMap\Drawing\RadiusY + (py - PBMap\PixelCoordinates\y) @@ -525,7 +530,7 @@ Module PBMap Procedure.d Pixel2Lon(x) Protected NewX.d = (PBMap\PixelCoordinates\x - PBMap\Drawing\RadiusX + x) / PBMap\TileSize Protected n.d = Pow(2.0, PBMap\Zoom) - ; double mod is to ensure the longitude to be in the range [-180;180[ + ; double mod is to ensure the longitude to be in the range [-180; 180[ ProcedureReturn Mod(Mod(NewX / n * 360.0, 360.0) + 360.0, 360.0) - 180 EndProcedure @@ -538,19 +543,19 @@ Module PBMap ; HaversineAlgorithm ; http://andrew.hedges.name/experiments/haversine/ Procedure.d HaversineInKM(*posA.GeographicCoordinates, *posB.GeographicCoordinates) - Protected eQuatorialEarthRadius.d = 6378.1370;6372.795477598; - Protected dlong.d = (*posB\Longitude - *posA\Longitude); - Protected dlat.d = (*posB\Latitude - *posA\Latitude) ; + Protected eQuatorialEarthRadius.d = 6378.1370; 6372.795477598; + Protected dlong.d = (*posB\Longitude - *posA\Longitude); + Protected dlat.d = (*posB\Latitude - *posA\Latitude) ; Protected alpha.d=dlat/2 Protected beta.d=dlong/2 Protected a.d = Sin(Radian(alpha)) * Sin(Radian(alpha)) + Cos(Radian(*posA\Latitude)) * Cos(Radian(*posB\Latitude)) * Sin(Radian(beta)) * Sin(Radian(beta)) - Protected c.d = ASin(Min(1,Sqr(a))); + Protected c.d = ASin(Min(1,Sqr(a))); Protected distance.d = 2*eQuatorialEarthRadius * c - ProcedureReturn distance ; + ProcedureReturn distance ; EndProcedure Procedure.d HaversineInM(*posA.GeographicCoordinates, *posB.GeographicCoordinates) - ProcedureReturn (1000 * HaversineInKM(@*posA,@*posB)); + ProcedureReturn (1000 * HaversineInKM(@*posA,@*posB)); EndProcedure ; No more used, see LatLon2PixelRel @@ -560,15 +565,15 @@ Module PBMap Protected x1.l,y1.l 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 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 x2 = (PBMap\GeographicCoordinates\Longitude+180)*(mapWidth/360) ; convert from degrees To radians - latRad = PBMap\GeographicCoordinates\Latitude*#PI/180; + latRad = PBMap\GeographicCoordinates\Latitude*#PI/180; mercN = Log(Tan((#PI/4)+(latRad/2))) - y2 = (mapHeight/2)-(mapWidth*mercN/(2*#PI)); + y2 = (mapHeight/2)-(mapWidth*mercN/(2*#PI)); *Pixel\x=PBMap\Drawing\RadiusX - (x2-x1) *Pixel\y=PBMap\Drawing\RadiusY - (y2-y1) EndProcedure @@ -610,24 +615,24 @@ Module PBMap EndIf EndProcedure - ;TODO : best cleaning of the string from bad behaviour + ; TODO : best cleaning of the string from bad behaviour Procedure.s StringCheck(String.s) ProcedureReturn Trim(RemoveString(RemoveString(RemoveString(RemoveString(RemoveString(RemoveString(RemoveString(RemoveString(RemoveString(RemoveString(String, Chr(0)), Chr(32)), Chr(39)), Chr(33)), Chr(34)), "@"), "/"), "\"), "$"), "%")) EndProcedure Procedure.i ColourString2Value(Value.s) - ;TODO : better string check + ; TODO : better string check Protected Col.s = RemoveString(Value, " ") If Left(Col, 1) = "$" Protected r.i, g.i, b.i, a.i = 255 Select Len(Col) - Case 4 ;RGB (eg : "$9BC" + Case 4 ; RGB (eg : "$9BC" r = Val("$"+Mid(Col, 2, 1)) : g = Val("$"+Mid(Col, 3, 1)) : b = Val("$"+Mid(Col, 4, 1)) - Case 5 ;RGBA (eg : "$9BC5") + Case 5 ; RGBA (eg : "$9BC5") r = Val("$"+Mid(Col, 2, 1)) : g = Val("$"+Mid(Col, 3, 1)) : b = Val("$"+Mid(Col, 4, 1)) : a = Val("$"+Mid(Col, 5, 1)) - Case 7 ;RRGGBB (eg : "$95B4C2") + Case 7 ; RRGGBB (eg : "$95B4C2") r = Val("$"+Mid(Col, 2, 2)) : g = Val("$"+Mid(Col, 4, 2)) : b = Val("$"+Mid(Col, 6, 2)) - Case 9 ;RRGGBBAA (eg : "$95B4C249") + Case 9 ; RRGGBBAA (eg : "$95B4C249") r = Val("$"+Mid(Col, 2, 2)) : g = Val("$"+Mid(Col, 4, 2)) : b = Val("$"+Mid(Col, 6, 2)) : a = Val("$"+Mid(Col, 8, 2)) EndSelect ProcedureReturn RGBA(r, g, b, a) @@ -651,7 +656,7 @@ Module PBMap OpenConsole() EndIf CreateDirectoryEx(\HDDCachePath) - If \DefaultOSMServer <> "" And IsLayer("OSM") = #False ;First time creation of the basis OSM layer + If \DefaultOSMServer <> "" And IsLayer("OSM") = #False ; First time creation of the basis OSM layer AddOSMServerLayer("OSM", 1, \DefaultOSMServer) EndIf EndWith @@ -687,6 +692,8 @@ Module PBMap PBMap\Options\MaxMemCache = Val(Value) Case "maxthreads" PBMap\Options\MaxThreads = Val(Value) + Case "maxdownloadslots" + PBMap\Options\MaxDownloadSlots = Val(Value) Case "tilelifetime" PBMap\Options\TileLifetime = Val(Value) Case "verbose" @@ -756,6 +763,8 @@ Module PBMap ProcedureReturn StrU(\MaxMemCache) Case "maxthreads" ProcedureReturn StrU(\MaxThreads) + Case "maxdownloadslots" + ProcedureReturn StrU(\MaxDownloadSlots) Case "tilelifetime" ProcedureReturn StrU(\TileLifetime) Case "verbose" @@ -794,7 +803,7 @@ Module PBMap EndWith EndProcedure - ;By default, save options in the user's home directory + ; By default, save options in the user's home directory Procedure SaveOptions(PreferencesFile.s = "PBMap.prefs") If PreferencesFile = "PBMap.prefs" CreatePreferences(GetHomeDirectory() + "PBMap.prefs") @@ -818,6 +827,7 @@ Module PBMap WritePreferenceInteger("WheelMouseRelative", \WheelMouseRelative) WritePreferenceInteger("MaxMemCache", \MaxMemCache) WritePreferenceInteger("MaxThreads", \MaxThreads) + WritePreferenceInteger("MaxDownloadSlots", \MaxDownloadSlots) WritePreferenceInteger("TileLifetime", \TileLifetime) WritePreferenceInteger("Verbose", \Verbose) WritePreferenceInteger("Warning", \Warning) @@ -832,7 +842,7 @@ Module PBMap WritePreferenceInteger("ShowMarkersLegend", \ShowMarkersLegend) PreferenceGroup("DRAWING") WritePreferenceInteger("StrokeWidthTrackDefault", \StrokeWidthTrackDefault) - ;Colours; + ; Colours; WritePreferenceInteger("ColourFocus", \ColourFocus) WritePreferenceInteger("ColourSelected", \ColourSelected) WritePreferenceInteger("ColourTrackDefault", \ColourTrackDefault) @@ -846,22 +856,22 @@ Module PBMap Else OpenPreferences(PreferencesFile) EndIf - ;Use this to create and customize your preferences file for the first time - ; CreatePreferences(GetHomeDirectory() + "PBMap.prefs") - ; ;Or this to modify - ; ;OpenPreferences(GetHomeDirectory() + "PBMap.prefs") - ; ;Or this - ; ;RunProgram("notepad.exe", GetHomeDirectory() + "PBMap.prefs", GetHomeDirectory()) - ; PreferenceGroup("PROXY") - ; WritePreferenceInteger("Proxy", #True) - ; WritePreferenceString("ProxyURL", "myproxy.fr") - ; WritePreferenceString("ProxyPort", "myproxyport") - ; WritePreferenceString("ProxyUser", "myproxyname") - ; WritePreferenceString("ProxyPass", "myproxypass") ;TODO !Warning! !not encoded! - ; PreferenceGroup("HERE") - ; WritePreferenceString("APP_ID", "myhereid") ;TODO !Warning! !not encoded! - ; WritePreferenceString("APP_CODE", "myherecode") ;TODO !Warning! !not encoded! - ; ClosePreferences() + ; Use this to create and customize your preferences file for the first time + ; CreatePreferences(GetHomeDirectory() + "PBMap.prefs") + ; ; Or this to modify + ; ; OpenPreferences(GetHomeDirectory() + "PBMap.prefs") + ; ; Or this + ; ; RunProgram("notepad.exe", GetHomeDirectory() + "PBMap.prefs", GetHomeDirectory()) + ; PreferenceGroup("PROXY") + ; WritePreferenceInteger("Proxy", #True) + ; WritePreferenceString("ProxyURL", "myproxy.fr") + ; WritePreferenceString("ProxyPort", "myproxyport") + ; WritePreferenceString("ProxyUser", "myproxyname") + ; WritePreferenceString("ProxyPass", "myproxypass") ; TODO !Warning! !not encoded! + ; PreferenceGroup("HERE") + ; WritePreferenceString("APP_ID", "myhereid") ; TODO !Warning! !not encoded! + ; WritePreferenceString("APP_CODE", "myherecode") ; TODO !Warning! !not encoded! + ; ClosePreferences() With PBMap\Options PreferenceGroup("PROXY") \Proxy = ReadPreferenceInteger("Proxy", #False) @@ -869,11 +879,11 @@ Module PBMap \ProxyURL = ReadPreferenceString("ProxyURL", "") ; = InputRequester("ProxyServer", "Do you use a Proxy Server? Then enter the full url:", "") \ProxyPort = ReadPreferenceString("ProxyPort", "") ; = InputRequester("ProxyPort" , "Do you use a specific port? Then enter it", "") \ProxyUser = ReadPreferenceString("ProxyUser", "") ; = InputRequester("ProxyUser" , "Do you use a user name? Then enter it", "") - \ProxyPassword = ReadPreferenceString("ProxyPass", "") ; = InputRequester("ProxyPass", "Do you use a password ? Then enter it", "") ;TODO + \ProxyPassword = ReadPreferenceString("ProxyPass", "") ; = InputRequester("ProxyPass", "Do you use a password ? Then enter it", "") ; TODO EndIf PreferenceGroup("HERE") - \appid = ReadPreferenceString("APP_ID", "") ; = InputRequester("Here App ID", "Do you use HERE ? Enter app ID", "") ;TODO - \appcode = ReadPreferenceString("APP_CODE", "") ; = InputRequester("Here App Code", "Do you use HERE ? Enter app Code", "") ;TODO + \appid = ReadPreferenceString("APP_ID", "") ; = InputRequester("Here App ID", "Do you use HERE ? Enter app ID", "") ; TODO + \appcode = ReadPreferenceString("APP_CODE", "") ; = InputRequester("Here App Code", "Do you use HERE ? Enter app Code", "") ; TODO PreferenceGroup("URL") \DefaultOSMServer = ReadPreferenceString("DefaultOSMServer", "http://tile.openstreetmap.org/") @@ -881,9 +891,10 @@ Module PBMap \HDDCachePath = ReadPreferenceString("TilesCachePath", GetTemporaryDirectory() + "PBMap" + slash) PreferenceGroup("OPTIONS") \WheelMouseRelative = ReadPreferenceInteger("WheelMouseRelative", #True) - \MaxMemCache = ReadPreferenceInteger("MaxMemCache", 20480) ;20 MiB, about 80 tiles in memory - \MaxThreads = ReadPreferenceInteger("MaxThreads", 10) - \TileLifetime = ReadPreferenceInteger("TileLifetime", 1209600) ;about 2 weeks ; -1 = unlimited + \MaxMemCache = ReadPreferenceInteger("MaxMemCache", 20480) ; 20 MiB, about 80 tiles in memory + \MaxThreads = ReadPreferenceInteger("MaxThreads", 40) + \MaxDownloadSlots = ReadPreferenceInteger("MaxDownloadSlots", 2) + \TileLifetime = ReadPreferenceInteger("TileLifetime", 1209600) ; about 2 weeks ;-1 = unlimited \Verbose = ReadPreferenceInteger("Verbose", #False) \Warning = ReadPreferenceInteger("Warning", #False) \ShowDegrees = ReadPreferenceInteger("ShowDegrees", #False) @@ -909,7 +920,7 @@ Module PBMap ;-*** Layers - ;Add a layer to a list (to get things ordered) and to a map (to access things easily) + ; Add a layer to a list (to get things ordered) and to a map (to access things easily) Procedure.i AddLayer(Name.s, Order.i, Alpha.d) Protected *Ptr = 0 *Ptr = AddMapElement(PBMap\Layers(), Name) @@ -943,13 +954,13 @@ Module PBMap EndProcedure ; "Here" layer - ;see there for parameters : https://developer.here.com/rest-apis/documentation/enterprise-map-tile/topics/resource-base-maptile.html - ;you could use base.maps.api.here.com or aerial.maps.api.here.com or traffic.maps.api.here.com or pano.maps.api.here.com. - ;use *.cit.map.api.com For Customer Integration Testing (see https://developer.here.com/rest-apis/documentation/enterprise-Map-tile/common/request-cit-environment-rest.html) + ; see there for parameters : https://developer.here.com/rest-apis/documentation/enterprise-map-tile/topics/resource-base-maptile.html + ; you could use base.maps.api.here.com or aerial.maps.api.here.com or traffic.maps.api.here.com or pano.maps.api.here.com. + ; use *.cit.map.api.com For Customer Integration Testing (see https://developer.here.com/rest-apis/documentation/enterprise-Map-tile/common/request-cit-environment-rest.html) Procedure.i AddHereServerLayer(LayerName.s, Order.i, APP_ID.s = "", APP_CODE.s = "", ServerURL.s = "aerial.maps.api.here.com", path.s = "/maptile/2.1/", ressource.s = "maptile", id.s = "newest", scheme.s = "satellite.day", format.s = "jpg", lg.s = "eng", lg2.s = "eng", param.s = "") Protected *Ptr.Layer = AddLayer(LayerName, Order, 1) If *Ptr - With *Ptr ;PBMap\Layers() + With *Ptr ; PBMap\Layers() \ServerURL = ServerURL \path = path \ressource = ressource @@ -977,12 +988,12 @@ Module PBMap EndIf EndProcedure - ;GeoServer / geowebcache - google maps service - ;template 'http://localhost:8080/geowebcache/service/gmaps?layers=layer-name&zoom={Z}&x={X}&y={Y}&format=image/png' + ; GeoServer / geowebcache - google maps service + ; template 'http://localhost:8080/geowebcache/service/gmaps?layers=layer-name&zoom={Z}&x={X}&y={Y}&format=image/png' Procedure.i AddGeoServerLayer(LayerName.s, Order.i, ServerLayerName.s, ServerURL.s = "http://localhost:8080/", path.s = "geowebcache/service/gmaps", format.s = "image/png") Protected *Ptr.Layer = AddLayer(LayerName, Order, 1) If *Ptr - With *Ptr ;PBMap\Layers() + With *Ptr ; PBMap\Layers() \ServerURL = ServerURL \path = path \LayerType = 2 ; GeoServer @@ -1004,10 +1015,10 @@ Module PBMap Procedure DeleteLayer(Name.s) FindMapElement(PBMap\Layers(), Name) Protected *Ptr = PBMap\Layers() - ;Free the list element + ; Free the list element ChangeCurrentElement(PBMap\LayersList(), *Ptr) DeleteElement(PBMap\LayersList()) - ;Free the map element + ; Free the map element DeleteMapElement(PBMap\Layers()) PBMap\Redraw = #True EndProcedure @@ -1031,6 +1042,8 @@ Module PBMap ProcedureReturn PBMap\Layers(Name)\Alpha EndProcedure + ;-*** + Procedure MemoryCacheManagement() ; If cache size exceeds limit, try to delete the oldest tiles used (first in the time stack) Protected CacheSize = MapSize(PBMap\MemCache\Images()) * Pow(PBMap\TileSize, 2) * 5 ; Size of a tile = TileSize * TileSize * 4 bytes (RGBA) @@ -1075,17 +1088,17 @@ Module PBMap Procedure.i GetTileFromHDD(CacheFile.s) MaxLifeTime.i = PBMap\Options\TileLifetime - If FileSize(CacheFile) > 0 ;<> -1 + If FileSize(CacheFile) > 0 ; <> -1 ; Manage tile file lifetime If MaxLifeTime <> -1 - LifeTime = Date() - GetFileDate(CacheFile, #PB_Date_Modified) ;There's a bug with #PB_Date_Created + LifeTime = Date() - GetFileDate(CacheFile, #PB_Date_Modified) ; There's a bug with #PB_Date_Created If LifeTime > MaxLifeTime MyDebug(" Deleting too old (" + StrU(LifeTime) + " secs) " + CacheFile, 3) DeleteFile(CacheFile) ProcedureReturn 0 EndIf EndIf - ;Everything is OK, loads the file + ; Everything is OK, loads the file nImage = LoadImage(#PB_Any, CacheFile) If nImage And IsImage(nImage) MyDebug(" Success loading " + CacheFile + " as nImage " + Str(nImage), 3) @@ -1107,32 +1120,46 @@ Module PBMap ; **** OLD IMPORTANT NOTICE (please not remove) ; This original catchimage/saveimage method is a double operation (uncompress/recompress PNG) ; and is modifying the original PNG image which could lead to PNG error (Idle has spent hours debunking the 1 bit PNG bug) - ;Protected *Buffer - ;Protected nImage.i = -1 - ;Protected timg - ; *Buffer = ReceiveHTTPMemory(TileURL) ;TODO to thread by using #PB_HTTP_Asynchronous - ; If *Buffer - ; nImage = CatchImage(#PB_Any, *Buffer, MemorySize(*Buffer)) - ; If IsImage(nImage) - ; If SaveImage(nImage, CacheFile, #PB_ImagePlugin_PNG, 0, 32) ;The 32 is needed !!!! - ; MyDebug("Loaded from web " + TileURL + " as CacheFile " + CacheFile, 3) - ; Else - ; MyDebug("Loaded from web " + TileURL + " but cannot save to CacheFile " + CacheFile, 3) - ; EndIf - ; FreeMemory(*Buffer) - ; Else - ; MyDebug("Can't catch image loaded from web " + TileURL, 3) - ; nImage = -1 - ; EndIf - ; Else - ; MyDebug(" Problem loading from web " + TileURL, 3) - ; EndIf + ; Protected *Buffer + ; Protected nImage.i = -1 + ; Protected timg + ; *Buffer = ReceiveHTTPMemory(TileURL) ; TODO to thread by using #PB_HTTP_Asynchronous + ; If *Buffer + ; nImage = CatchImage(#PB_Any, *Buffer, MemorySize(*Buffer)) + ; If IsImage(nImage) + ; If SaveImage(nImage, CacheFile, #PB_ImagePlugin_PNG, 0, 32) ; The 32 is needed !!!! + ; MyDebug("Loaded from web " + TileURL + " as CacheFile " + CacheFile, 3) + ; Else + ; MyDebug("Loaded from web " + TileURL + " but cannot save to CacheFile " + CacheFile, 3) + ; EndIf + ; FreeMemory(*Buffer) + ; Else + ; MyDebug("Can't catch image loaded from web " + TileURL, 3) + ; nImage = -1 + ; EndIf + ; Else + ; MyDebug(" Problem loading from web " + TileURL, 3) + ; EndIf ; **** Threaded Progress = 0, Size = 0 Procedure GetImageThread(*Tile.Tile) MyDebug("Thread starting for image " + *Tile\CacheFile + "(" + *Tile\key + ")", 5) + ; Waits for a free download slot + LockMutex(PBMap\DownloadSlotsMutex) + While PBMap\DownloadSlots >= PBMap\Options\MaxDownloadSlots + UnlockMutex(PBMap\DownloadSlotsMutex) + If ElapsedMilliseconds() - *Tile\Time > 10000 + MyDebug(" Thread for image " + *Tile\CacheFile + " canceled after 10 seconds waiting for a slot.", 5) + PostEvent(#PB_Event_Gadget, PBMap\Window, PBmap\Gadget, #PB_MAP_TILE_CLEANUP, *Tile) ; To free memory outside the thread + ProcedureReturn #False + EndIf + Delay(500) + LockMutex(PBMap\DownloadSlotsMutex) + Wend + PBMap\DownloadSlots + 1 + UnlockMutex(PBMap\DownloadSlotsMutex) *Tile\Download = ReceiveHTTPFile(*Tile\URL, *Tile\CacheFile, #PB_HTTP_Asynchronous) If *Tile\Download Repeat @@ -1142,23 +1169,24 @@ Module PBMap Case #PB_Http_Success Size = FinishHTTP(*Tile\Download) MyDebug(" Thread for image " + *Tile\CacheFile + " finished. Size : " + Str(Size), 5) - PostEvent(#PB_Event_Gadget, PBMap\Window, PBmap\Gadget, #PB_MAP_TILE_CLEANUP, *Tile) ;To free memory outside the thread - *Tile\Download = 0 + PostEvent(#PB_Event_Gadget, PBMap\Window, PBmap\Gadget, #PB_MAP_TILE_CLEANUP, *Tile) ; To free memory outside the thread ProcedureReturn #True Case #PB_Http_Failed FinishHTTP(*Tile\Download) MyDebug(" Thread for image " + *Tile\CacheFile + " failed.", 5) - PostEvent(#PB_Event_Gadget, PBMap\Window, PBmap\Gadget, #PB_MAP_TILE_CLEANUP, *Tile) ;To free memory outside the thread - *Tile\Download = 0 + PostEvent(#PB_Event_Gadget, PBMap\Window, PBmap\Gadget, #PB_MAP_TILE_CLEANUP, *Tile) ; To free memory outside the thread ProcedureReturn #False Case #PB_Http_Aborted FinishHTTP(*Tile\Download) MyDebug(" Thread for image " + *Tile\CacheFile + " aborted.", 5) - PostEvent(#PB_Event_Gadget, PBMap\Window, PBmap\Gadget, #PB_MAP_TILE_CLEANUP, *Tile) ;To free memory outside the thread - *Tile\Download = 0 + PostEvent(#PB_Event_Gadget, PBMap\Window, PBmap\Gadget, #PB_MAP_TILE_CLEANUP, *Tile) ; To free memory outside the thread ProcedureReturn #False Default MyDebug(" Thread for image " + *Tile\CacheFile + " downloading " + Str(Progress) + " bytes", 5) + If ElapsedMilliseconds() - *Tile\Time > 60000 + MyDebug(" Thread for image " + *Tile\CacheFile + " canceled after 60 seconds.", 5) + AbortHTTP(*Tile\Download) + EndIf EndSelect EndIf Delay(500) ; Frees CPU @@ -1175,12 +1203,12 @@ Module PBMap MyDebug("Key : " + key + " found in memory cache", 5) If *timg\nImage MyDebug(" as image " + *timg\nImage, 5) - ;*** Cache management + ; *** Cache management ; Retrieves the image in the time stack, push it to the end (to say it's the lastly used) ChangeCurrentElement(PBMap\MemCache\ImagesTimeStack(), *timg\TimeStackPtr) MoveElement(PBMap\MemCache\ImagesTimeStack(), #PB_List_Last) - ;*timg\TimeStackPtr = LastElement(PBMap\MemCache\ImagesTimeStack()) - ;*** + ; *timg\TimeStackPtr = LastElement(PBMap\MemCache\ImagesTimeStack()) + ; *** ProcedureReturn *timg Else MyDebug(" but not the image.", 5) @@ -1204,7 +1232,7 @@ Module PBMap ; Associates the time stack element to the cache element PBMap\MemCache\ImagesTimeStack()\MapKey = MapKey(PBMap\MemCache\Images()) MyDebug("Key : " + key + " added in memory cache", 5) - ;*** + ; *** EndIf If *timg\Tile = 0 ; Checks if a loading thread is not already running ; Is the file image on HDD ? @@ -1221,12 +1249,13 @@ Module PBMap With *NewTile *timg\Tile = *NewTile ; There's now a loading thread *timg\Alpha = 0 - ;*timg\nImage = -1 - ;New tile parameters + ; *timg\nImage = -1 + ; New tile parameters \key = key \URL = URL \CacheFile = CacheFile - \nImage = 0 + \nImage = 0 + \Time = ElapsedMilliseconds() \GetImageThread = CreateThread(@GetImageThread(), *NewTile) If \GetImageThread MyDebug(" Creating get image thread nb " + Str(\GetImageThread) + " to get " + CacheFile, 3) @@ -1248,14 +1277,14 @@ Module PBMap Procedure DrawTiles(*Drawing.DrawingParameters, LayerName.s) Protected x.i, y.i,kq.q - Protected tx = Int(*Drawing\TileCoordinates\x) ;Don't forget the Int() ! + Protected tx = Int(*Drawing\TileCoordinates\x) ; Don't forget the Int() ! Protected ty = Int(*Drawing\TileCoordinates\y) - Protected nx = *Drawing\RadiusX / PBMap\TileSize ;How many tiles around the point + Protected nx = *Drawing\RadiusX / PBMap\TileSize ; How many tiles around the point Protected ny = *Drawing\RadiusY / PBMap\TileSize Protected px, py, *timg.ImgMemCach, tilex, tiley, key.s Protected URL.s, CacheFile.s Protected tilemax = 1< 0 BeginVectorLayer() ForEach PBMap\TracksList() If ListSize(\Track()) > 0 - ;Check visibility + ; Check visibility \Visible = #False ForEach \Track() If IsInDrawingPixelBoundaries(*Drawing, @PBMap\TracksList()\Track()) @@ -1523,7 +1552,7 @@ Module PBMap EndIf Next If \Visible - ;Draw tracks + ; Draw tracks ForEach \Track() LatLon2PixelRel(@PBMap\TracksList()\Track(), @Pixel, PBMap\Zoom) If ListIndex(\Track()) = 0 @@ -1532,10 +1561,10 @@ Module PBMap AddPathLine(Pixel\x, Pixel\y) EndIf Next - ; \BoundingBox\x = PathBoundsX() - ; \BoundingBox\y = PathBoundsY() - ; \BoundingBox\w = PathBoundsWidth() - ; \BoundingBox\h = PathBoundsHeight() + ; \BoundingBox\x = PathBoundsX() + ; \BoundingBox\y = PathBoundsY() + ; \BoundingBox\w = PathBoundsWidth() + ; \BoundingBox\h = PathBoundsHeight() If \Focus VectorSourceColor(PBMap\Options\ColourFocus) ElseIf \Selected @@ -1548,14 +1577,14 @@ Module PBMap EndIf Next EndVectorLayer() - ;Draw distances + ; Draw distances If PBMap\Options\ShowTrackKms And PBMap\Zoom > 10 BeginVectorLayer() ForEach PBMap\TracksList() If \Visible km = 0 : memKm = -1 ForEach PBMap\TracksList()\Track() - ;Test Distance + ; Test Distance If ListIndex(\Track()) = 0 Location\Latitude = \Track()\Latitude Location\Longitude = \Track()\Longitude @@ -1704,7 +1733,7 @@ Module PBMap EndProcedure Procedure MarkerEdit(*Marker.Marker) - If *Marker\EditWindow = 0 ;Check that this marker has no already opened window + If *Marker\EditWindow = 0 ; Check that this marker has no already opened window Protected WindowMarkerEdit = OpenWindow(#PB_Any, WindowX(PBMap\Window) + WindowWidth(PBMap\Window) / 2 - 150, WindowY(PBMap\Window)+ WindowHeight(PBMap\Window) / 2 + 50, 300, 100, "Marker Edit", #PB_Window_SystemMenu | #PB_Window_TitleBar) StickyWindow(WindowMarkerEdit, #True) TextGadget(#PB_Any, 2, 2, 80, 25, gettext("Identifier")) @@ -1727,8 +1756,8 @@ Module PBMap AddPathLine(-8, -16, #PB_Path_Relative) AddPathCircle(8, 0, 8, 180, 0, #PB_Path_Relative) AddPathLine(-8, 16, #PB_Path_Relative) - ;FillPath(#PB_Path_Preserve) - ;ClipPath(#PB_Path_Preserve) + ; FillPath(#PB_Path_Preserve) + ; ClipPath(#PB_Path_Preserve) AddPathCircle(0, -16, 5, 0, 360, #PB_Path_Relative) VectorSourceColor(*Marker\Color) FillPath(#PB_Path_Preserve) @@ -1755,7 +1784,7 @@ Module PBMap EndIf If PBMap\Options\ShowMarkersLegend And *Marker\Legend <> "" VectorFont(FontID(PBMap\Font), 13) - ;dessin d'un cadre avec fond transparent + ; dessin d'un cadre avec fond transparent Protected Height = VectorParagraphHeight(*Marker\Legend, 100, 100) Protected Width.l If Height < 20 ; une ligne @@ -1832,7 +1861,7 @@ Module PBMap Protected NW.Coordinates, SE.Coordinates PBMap\Dirty = #False PBMap\Redraw = #False - ;*** Precalc some values + ; *** Precalc some values *Drawing\RadiusX = GadgetWidth(PBMap\Gadget) / 2 *Drawing\RadiusY = GadgetHeight(PBMap\Gadget) / 2 *Drawing\GeographicCoordinates\Latitude = PBMap\GeographicCoordinates\Latitude @@ -1842,10 +1871,10 @@ Module PBMap ; Pixel shift, aka position in the tile Px = *Drawing\TileCoordinates\x Py = *Drawing\TileCoordinates\y - *Drawing\DeltaX = Px * ts - (Int(Px) * ts) ;Don't forget the Int() ! + *Drawing\DeltaX = Px * ts - (Int(Px) * ts) ; Don't forget the Int() ! *Drawing\DeltaY = Py * ts - (Int(Py) * ts) - ;Drawing boundaries - nx = *Drawing\RadiusX / ts ;How many tiles around the point + ; Drawing boundaries + nx = *Drawing\RadiusX / ts ; How many tiles around the point ny = *Drawing\RadiusY / ts NW\x = Px - nx - 1 NW\y = Py - ny - 1 @@ -1853,17 +1882,17 @@ Module PBMap SE\y = Py + ny + 2 TileXY2LatLon(@NW, *Drawing\Bounds\NorthWest, PBMap\Zoom) TileXY2LatLon(@SE, *Drawing\Bounds\SouthEast, PBMap\Zoom) - ;*Drawing\Width = (SE\x / Pow(2, PBMap\Zoom) * 360.0) - (NW\x / Pow(2, PBMap\Zoom) * 360.0) ;Calculus without clipping - ;*Drawing\Height = *Drawing\Bounds\NorthWest\Latitude - *Drawing\Bounds\SouthEast\Latitude - ;*** + ; *Drawing\Width = (SE\x / Pow(2, PBMap\Zoom) * 360.0) - (NW\x / Pow(2, PBMap\Zoom) * 360.0) ; Calculus without clipping + ; *Drawing\Height = *Drawing\Bounds\NorthWest\Latitude - *Drawing\Bounds\SouthEast\Latitude + ; *** ; Main drawing stuff StartVectorDrawing(CanvasVectorOutput(PBMap\Gadget)) - ;Clearscreen + ; Clearscreen VectorSourceColor(RGBA(150, 150, 150, 255)) FillVectorOutput() - ;TODO add in layers of tiles ;this way we can cache them as 0 base 1.n layers + ; TODO add in layers of tiles ; this way we can cache them as 0 base 1.n layers ; such as for openseamap tiles which are overlaid. not that efficent from here though. - ;Draws layers based on their number + ; Draws layers based on their number ForEach PBMap\LayersList() If PBMap\LayersList()\Enabled DrawTiles(*Drawing, PBMap\LayersList()\Name) @@ -1893,7 +1922,7 @@ Module PBMap Procedure Refresh() PBMap\Redraw = #True - ;Drawing() + ; Drawing() EndProcedure ;-*** Misc functions @@ -1901,7 +1930,7 @@ Module PBMap Procedure.d GetMouseLongitude() Protected MouseX.d = (PBMap\PixelCoordinates\x - PBMap\Drawing\RadiusX + GetGadgetAttribute(PBMap\Gadget, #PB_Canvas_MouseX)) / PBMap\TileSize Protected n.d = Pow(2.0, PBMap\Zoom) - ; double mod is to ensure the longitude to be in the range [-180;180[ + ; double mod is to ensure the longitude to be in the range [-180; 180[ ProcedureReturn Mod(Mod(MouseX / n * 360.0, 360.0) + 360.0, 360.0) - 180 EndProcedure @@ -1946,26 +1975,26 @@ Module PBMap EndProcedure Procedure SetZoomToArea(MinY.d, MaxY.d, MinX.d, MaxX.d) - ;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 DeltaX.d = MaxX - MinX ;assumption ! In original code DeltaX have no source + ; 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 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%. + 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%. Protected ry1.d = Log((Sin(Radian(MinY)) + 1) / Cos(Radian(MinY))) Protected ry2.d = Log((Sin(Radian(MaxY)) + 1) / Cos(Radian(MaxY))) Protected ryc.d = (ry1 + ry2) / 2 Protected centerY.d = Degree(ATan(SinH(ryc))) Protected resolutionHorizontal.d = DeltaX / (PBMap\Drawing\RadiusX * 2) - Protected vy0.d = Log(Tan(#PI*(0.25 + centerY/360))); - Protected vy1.d = Log(Tan(#PI*(0.25 + MaxY/360))) ; - Protected viewHeightHalf.d = PBMap\Drawing\RadiusY ; + Protected vy0.d = Log(Tan(#PI*(0.25 + centerY/360))); + Protected vy1.d = Log(Tan(#PI*(0.25 + MaxY/360))) ; + Protected viewHeightHalf.d = PBMap\Drawing\RadiusY ; Protected zoomFactorPowered.d = viewHeightHalf / (40.7436654315252*(vy1 - vy0)) Protected resolutionVertical.d = 360.0 / (zoomFactorPowered * PBMap\TileSize) If resolutionHorizontal<>0 And resolutionVertical<>0 Protected resolution.d = Max(resolutionHorizontal, resolutionVertical)* paddingFactor Protected zoom.d = Log(360 / (resolution * PBMap\TileSize))/Log(2) - Protected lon.d = centerX; - Protected lat.d = centerY; + Protected lon.d = centerX; + Protected lat.d = centerY; SetLocation(lat, lon, Round(zoom,#PB_Round_Down)) Else SetLocation(PBMap\GeographicCoordinates\Latitude, PBMap\GeographicCoordinates\Longitude, 15) @@ -2038,7 +2067,7 @@ Module PBMap Procedure SetMapScaleUnit(ScaleUnit.i = PBMAP::#SCALE_KM) PBMap\Options\ScaleUnit = ScaleUnit PBMap\Redraw = #True - ;Drawing() + ; Drawing() EndProcedure ; User mode @@ -2054,9 +2083,9 @@ Module PBMap ProcedureReturn PBMap\Mode EndProcedure - ;Zoom on x, y pixel position from the center + ; Zoom on x, y pixel position from the center Procedure SetZoomOnPixel(x, y, zoom) - ;*** First : Zoom + ; *** First : Zoom PBMap\Zoom + zoom If PBMap\Zoom > PBMap\ZoomMax : PBMap\Zoom = PBMap\ZoomMax : ProcedureReturn : EndIf If PBMap\Zoom < PBMap\ZoomMin : PBMap\Zoom = PBMap\ZoomMin : ProcedureReturn : EndIf @@ -2077,12 +2106,12 @@ Module PBMap EndIf EndProcedure - ;Zoom on x, y position relative to the canvas gadget + ; Zoom on x, y position relative to the canvas gadget Procedure SetZoomOnPixelRel(x, y, zoom) SetZoomOnPixel(x - PBMap\Drawing\RadiusX, y - PBMap\Drawing\RadiusY, zoom) EndProcedure - ;Go to x, y position relative to the canvas gadget left up + ; Go to x, y position relative to the canvas gadget left up Procedure GotoPixelRel(x, y) LatLon2Pixel(@PBMap\GeographicCoordinates, @PBMap\PixelCoordinates, PBMap\Zoom) PBMap\PixelCoordinates\x + x - PBMap\Drawing\RadiusX @@ -2096,7 +2125,7 @@ Module PBMap EndIf EndProcedure - ;Go to x, y position relative to the canvas gadget + ; Go to x, y position relative to the canvas gadget Procedure GotoPixel(x, y) PBMap\PixelCoordinates\x = x PBMap\PixelCoordinates\y = y @@ -2131,16 +2160,16 @@ Module PBMap URLEncoder(Address) + "?format=json&addressdetails=0&polygon=0&limit=1" Protected JSONFileName.s = PBMap\Options\HDDCachePath + "nominatimresponse.json" - ; Protected *Buffer = CurlReceiveHTTPToMemory("http://nominatim.openstreetmap.org/search/Unter%20den%20Linden%201%20Berlin?format=json&addressdetails=1&limit=1&polygon_svg=1", PBMap\Options\ProxyURL, PBMap\Options\ProxyPort, PBMap\Options\ProxyUser, PBMap\Options\ProxyPassword) - ; Debug *Buffer - ; Debug MemorySize(*Buffer) - ; Protected JSon.s = PeekS(*Buffer, MemorySize(*Buffer), #PB_UTF8) + ; Protected *Buffer = CurlReceiveHTTPToMemory("http://nominatim.openstreetmap.org/search/Unter%20den%20Linden%201%20Berlin?format=json&addressdetails=1&limit=1&polygon_svg=1", PBMap\Options\ProxyURL, PBMap\Options\ProxyPort, PBMap\Options\ProxyUser, PBMap\Options\ProxyPassword) + ; Debug *Buffer + ; Debug MemorySize(*Buffer) + ; Protected JSon.s = PeekS(*Buffer, MemorySize(*Buffer), #PB_UTF8) If PBMap\Options\Proxy HTTPProxy(PBMap\Options\ProxyURL + ":" + PBMap\Options\ProxyPort, PBMap\Options\ProxyUser, PBMap\Options\ProxyPassword) EndIf Size = ReceiveHTTPFile(Query, JSONFileName) If LoadJSON(0, JSONFileName) = 0 - ;Demivec's code + ; Demivec's code MyDebug( JSONErrorMessage() + " at position " + JSONErrorPosition() + " in line " + JSONErrorLine() + " of JSON web Data", 1) @@ -2160,7 +2189,7 @@ Module PBMap EndIf If lat <> "" And lon <> "" SetZoomToArea(bbox\SouthEast\Latitude, bbox\NorthWest\Latitude, bbox\NorthWest\Longitude, bbox\SouthEast\Longitude) - ;SetLocation(Position\Latitude, Position\Longitude) + ; SetLocation(Position\Latitude, Position\Longitude) EndIf EndIf EndProcedure @@ -2193,11 +2222,11 @@ Module PBMap CanvasMouseX = GetGadgetAttribute(PBMap\Gadget, #PB_Canvas_MouseX) - PBMap\Drawing\RadiusX CanvasMouseY = GetGadgetAttribute(PBMap\Gadget, #PB_Canvas_MouseY) - PBMap\Drawing\RadiusY ; rotation wip - ; StartVectorDrawing(CanvasVectorOutput(PBMap\Gadget)) - ; RotateCoordinates(0, 0, PBMap\Angle) - ; CanvasMouseX = ConvertCoordinateX(MouseX, MouseY, #PB_Coordinate_Device, #PB_Coordinate_User) - ; CanvasMouseY = ConvertCoordinateY(MouseX, MouseY, #PB_Coordinate_Device, #PB_Coordinate_User) - ; StopVectorDrawing() + ; StartVectorDrawing(CanvasVectorOutput(PBMap\Gadget)) + ; RotateCoordinates(0, 0, PBMap\Angle) + ; CanvasMouseX = ConvertCoordinateX(MouseX, MouseY, #PB_Coordinate_Device, #PB_Coordinate_User) + ; CanvasMouseY = ConvertCoordinateY(MouseX, MouseY, #PB_Coordinate_Device, #PB_Coordinate_User) + ; StopVectorDrawing() Select EventType() Case #PB_EventType_Focus PBMap\Drawing\RadiusX = GadgetWidth(PBMap\Gadget) / 2 @@ -2249,19 +2278,19 @@ Module PBMap LatLon2Pixel(@PBMap\GeographicCoordinates, @PBMap\PixelCoordinates, PBMap\Zoom) MouseX = PBMap\PixelCoordinates\x + CanvasMouseX MouseY = PBMap\PixelCoordinates\y + CanvasMouseY - ;Clip MouseX to the map range (in X, the map is infinite) + ; Clip MouseX to the map range (in X, the map is infinite) MouseX = Mod(Mod(MouseX, MapWidth) + MapWidth, MapWidth) Touch = #False - ;Check if the mouse touch a marker + ; Check if the mouse touch a marker ForEach PBMap\Markers() LatLon2Pixel(@PBMap\Markers()\GeographicCoordinates, @MarkerCoords, PBMap\Zoom) If Distance(MarkerCoords\x, MarkerCoords\y, MouseX, MouseY) < 8 If PBMap\Mode = #MODE_DEFAULT Or PBMap\Mode = #MODE_SELECT - ;Jump to the marker + ; Jump to the marker Touch = #True SetLocation(PBMap\Markers()\GeographicCoordinates\Latitude, PBMap\Markers()\GeographicCoordinates\Longitude) ElseIf PBMap\Mode = #MODE_EDIT - ;Edit the legend + ; Edit the legend MarkerEdit(@PBMap\Markers()) EndIf Break @@ -2272,37 +2301,37 @@ Module PBMap EndIf Case #PB_EventType_MouseWheel If PBMap\Options\WheelMouseRelative - ;Relative zoom (centered on the mouse) + ; Relative zoom (centered on the mouse) SetZoomOnPixel(CanvasMouseX, CanvasMouseY, GetGadgetAttribute(PBMap\Gadget, #PB_Canvas_WheelDelta)) Else - ;Absolute zoom (centered on the center of the map) + ; Absolute zoom (centered on the center of the map) SetZoom(GetGadgetAttribute(PBMap\Gadget, #PB_Canvas_WheelDelta), #PB_Relative) EndIf Case #PB_EventType_LeftButtonDown - ;LatLon2Pixel(@PBMap\GeographicCoordinates, @PBMap\PixelCoordinates, PBMap\Zoom) + ; LatLon2Pixel(@PBMap\GeographicCoordinates, @PBMap\PixelCoordinates, PBMap\Zoom) PBMap\Dragging = #True - ;Mem cursor Coord + ; Memorize cursor Coord PBMap\MoveStartingPoint\x = CanvasMouseX PBMap\MoveStartingPoint\y = CanvasMouseY - ;Clip MouseX to the map range (in X, the map is infinite) + ; Clip MouseX to the map range (in X, the map is infinite) PBMap\MoveStartingPoint\x = Mod(Mod(PBMap\MoveStartingPoint\x, MapWidth) + MapWidth, MapWidth) If PBMap\Mode = #MODE_DEFAULT Or PBMap\Mode = #MODE_SELECT PBMap\EditMarker = #False - ;Check if we select marker(s) + ; Check if we select marker(s) ForEach PBMap\Markers() If CtrlKey = #False - PBMap\Markers()\Selected = #False ;If no CTRL key, deselect everything and select only the focused marker + PBMap\Markers()\Selected = #False ; If no CTRL key, deselect everything and select only the focused marker EndIf If PBMap\Markers()\Focus PBMap\Markers()\Selected = #True - PBMap\EditMarker = #True;ListIndex(PBMap\Markers()) + PBMap\EditMarker = #True; ListIndex(PBMap\Markers()) PBMap\Markers()\Focus = #False EndIf Next - ;Check if we select track(s) + ; Check if we select track(s) ForEach PBMap\TracksList() If CtrlKey = #False - PBMap\TracksList()\Selected = #False ;If no CTRL key, deselect everything and select only the focused track + PBMap\TracksList()\Selected = #False ; If no CTRL key, deselect everything and select only the focused track EndIf If PBMap\TracksList()\Focus PBMap\TracksList()\Selected = #True @@ -2313,12 +2342,12 @@ Module PBMap Case #PB_EventType_MouseMove ; Drag If PBMap\Dragging - ; If PBMap\MoveStartingPoint\x <> - 1 + ; If PBMap\MoveStartingPoint\x <> - 1 MouseX = CanvasMouseX - PBMap\MoveStartingPoint\x MouseY = CanvasMouseY - PBMap\MoveStartingPoint\y PBMap\MoveStartingPoint\x = CanvasMouseX PBMap\MoveStartingPoint\y = CanvasMouseY - ;Move selected markers + ; Move selected markers If PBMap\EditMarker And (PBMap\Mode = #MODE_DEFAULT Or PBMap\Mode = #MODE_SELECT) ForEach PBMap\Markers() If PBMap\Markers()\Selected @@ -2329,14 +2358,14 @@ Module PBMap EndIf Next ElseIf PBMap\Mode = #MODE_DEFAULT Or PBMap\Mode = #MODE_HAND - ;Move map only - LatLon2Pixel(@PBMap\GeographicCoordinates, @PBMap\PixelCoordinates, PBMap\Zoom) ;This line could be removed as the coordinates don't have to change but I want to be sure we rely only on geographic coordinates + ; Move map only + LatLon2Pixel(@PBMap\GeographicCoordinates, @PBMap\PixelCoordinates, PBMap\Zoom) ; This line could be removed as the coordinates don't have to change but I want to be sure we rely only on geographic coordinates PBMap\PixelCoordinates\x - MouseX - ;Ensures that pixel position stay in the range [0..2^Zoom*PBMap\TileSize[ coz of the wrapping of the map + ; Ensures that pixel position stay in the range [0..2^Zoom*PBMap\TileSize[ coz of the wrapping of the map PBMap\PixelCoordinates\x = Mod(Mod(PBMap\PixelCoordinates\x, MapWidth) + MapWidth, MapWidth) PBMap\PixelCoordinates\y - MouseY Pixel2LatLon(@PBMap\PixelCoordinates, @PBMap\GeographicCoordinates, PBMap\Zoom) - ;If CallBackLocation send Location to function + ; If CallBackLocation send Location to function If PBMap\CallBackLocation > 0 CallFunctionFast(PBMap\CallBackLocation, @PBMap\GeographicCoordinates) EndIf @@ -2347,30 +2376,30 @@ Module PBMap LatLon2Pixel(@PBMap\GeographicCoordinates, @PBMap\PixelCoordinates, PBMap\Zoom) MouseX = PBMap\PixelCoordinates\x + CanvasMouseX MouseY = PBMap\PixelCoordinates\y + CanvasMouseY - ;Clip MouseX to the map range (in X, the map is infinite) + ; Clip MouseX to the map range (in X, the map is infinite) MouseX = Mod(Mod(MouseX, MapWidth) + MapWidth, MapWidth) If PBMap\Mode = #MODE_DEFAULT Or PBMap\Mode = #MODE_SELECT Or PBMap\Mode = #MODE_EDIT - ;Check if mouse touch markers + ; Check if mouse touch markers ForEach PBMap\Markers() LatLon2Pixel(@PBMap\Markers()\GeographicCoordinates, @MarkerCoords, PBMap\Zoom) If Distance(MarkerCoords\x, MarkerCoords\y, MouseX, MouseY) < 8 PBMap\Markers()\Focus = #True PBMap\Redraw = #True ElseIf PBMap\Markers()\Focus - ;If CtrlKey = #False + ; If CtrlKey = #False PBMap\Markers()\Focus = #False PBMap\Redraw = #True EndIf Next - ;Check if mouse touch tracks + ; Check if mouse touch tracks With PBMap\TracksList() - ;Trace Track + ; Trace Track If ListSize(PBMap\TracksList()) > 0 ForEach PBMap\TracksList() If ListSize(\Track()) > 0 If \Visible StartVectorDrawing(CanvasVectorOutput(PBMap\Gadget)) - ;Simulates track drawing + ; Simulates track drawing ForEach \Track() LatLon2Pixel(@PBMap\TracksList()\Track(), @Pixel, PBMap\Zoom) If ListIndex(\Track()) = 0 @@ -2395,7 +2424,7 @@ Module PBMap EndIf EndIf Case #PB_EventType_LeftButtonUp - ; PBMap\MoveStartingPoint\x = - 1 + ; PBMap\MoveStartingPoint\x = - 1 PBMap\Dragging = #False PBMap\Redraw = #True Case #PB_MAP_REDRAW @@ -2408,7 +2437,11 @@ Module PBMap *Tile = EventData() key = *Tile\key ; After a Web tile loading thread, clean the tile structure memory and set the image nb in the cache - ; avoid to have threads accessing vars (and avoid mutex), see GetImageThread() + ; avoid to have threads accessing vars (and avoid some mutex), see GetImageThread() + *Tile\Download = 0 + LockMutex(PBMap\DownloadSlotsMutex) + PBMap\DownloadSlots - 1 + UnlockMutex(PBMap\DownloadSlotsMutex) Protected timg = PBMap\MemCache\Images(key)\Tile\nImage ; Get this new tile image nb PBMap\MemCache\Images(key)\nImage = timg ; Stores it in the cache using the key FreeMemory(PBMap\MemCache\Images(key)\Tile) ; Frees the data needed for the thread @@ -2421,7 +2454,7 @@ Module PBMap ; Redraws at regular intervals Procedure TimerEvents() If EventTimer() = PBMap\Timer And (PBMap\Redraw Or PBMap\Dirty) - MemoryCacheManagement() + ; MemoryCacheManagement() Drawing() EndIf EndProcedure @@ -2439,7 +2472,7 @@ Module PBMap ; Creates a canvas and attach our map Procedure MapGadget(Gadget.i, X.i, Y.i, Width.i, Height.i) If Gadget = #PB_Any - PBMap\Gadget = CanvasGadget(PBMap\Gadget, X, Y, Width, Height, #PB_Canvas_Keyboard) ;#PB_Canvas_Keyboard has to be set for mousewheel to work on windows + PBMap\Gadget = CanvasGadget(PBMap\Gadget, X, Y, Width, Height, #PB_Canvas_Keyboard) ; #PB_Canvas_Keyboard has to be set for mousewheel to work on windows Else PBMap\Gadget = Gadget CanvasGadget(PBMap\Gadget, X, Y, Width, Height, #PB_Canvas_Keyboard) @@ -2450,14 +2483,14 @@ Module PBMap Procedure Quit() PBMap\Drawing\End = #True PBMap\MemoryCacheManagement = #True ; Tells web loading threads to pause - ;Wait for loading threads to finish nicely. Passed 2 seconds, kills them. + ; Wait for loading threads to finish nicely. Passed 2 seconds, kills them. Protected TimeCounter = ElapsedMilliseconds() Repeat ForEach PBMap\MemCache\Images() If PBMap\MemCache\Images()\Tile <> 0 If IsThread(PBMap\MemCache\Images()\Tile\GetImageThread) If ElapsedMilliseconds() - TimeCounter > 2000 - ;Should not occur + ; Should not occur KillThread(PBMap\MemCache\Images()\Tile\GetImageThread) EndIf Else @@ -2484,6 +2517,11 @@ Module PBMap PBMap\Window = Window PBMap\Timer = 1 PBMap\Mode = #MODE_DEFAULT + PBMap\DownloadSlotsMutex = CreateMutex() + If PBMap\DownloadSlotsMutex = #False + MyDebug("Cannot create a mutex", 0) + End + EndIf LoadOptions() TechnicalImagesCreation() SetLocation(0, 0) @@ -2491,11 +2529,11 @@ Module PBMap EndModule -;**************************************************************** -; +; **************************************************************** +; ;- Example of application -; -;**************************************************************** +; +; **************************************************************** CompilerIf #PB_Compiler_IsMainFile InitNetwork() @@ -2507,8 +2545,8 @@ CompilerIf #PB_Compiler_IsMainFile #Gdt_Right #Gdt_Up #Gdt_Down - ;#Gdt_RotateLeft - ;#Gdt_RotateRight + ; #Gdt_RotateLeft + ; #Gdt_RotateRight #Button_4 #Button_5 #Combo_0 @@ -2532,7 +2570,7 @@ CompilerIf #PB_Compiler_IsMainFile #StringGeoLocationQuery EndEnumeration - ;Menu events + ; Menu events Enumeration #MenuEventLonLatStringEnter #MenuEventGeoLocationStringEnter @@ -2549,7 +2587,7 @@ CompilerIf #PB_Compiler_IsMainFile ProcedureReturn 0 EndProcedure - ;This callback demonstration procedure will receive relative coords from canvas + ; This callback demonstration procedure will receive relative coords from canvas Procedure MyMarker(x.i, y.i, Focus = #False, Selected = #False) Protected color = RGBA(0, 255, 0, 255) MovePathCursor(x, y) @@ -2580,8 +2618,8 @@ CompilerIf #PB_Compiler_IsMainFile ResizeGadget(#Text_1,WindowWidth(#Window_0)-170,#PB_Ignore,#PB_Ignore,#PB_Ignore) ResizeGadget(#Gdt_Left, WindowWidth(#Window_0) - 150 ,#PB_Ignore,#PB_Ignore,#PB_Ignore) ResizeGadget(#Gdt_Right,WindowWidth(#Window_0) - 90 ,#PB_Ignore,#PB_Ignore,#PB_Ignore) - ;ResizeGadget(#Gdt_RotateLeft, WindowWidth(#Window_0) - 150 ,#PB_Ignore,#PB_Ignore,#PB_Ignore) - ;ResizeGadget(#Gdt_RotateRight,WindowWidth(#Window_0) - 90 ,#PB_Ignore,#PB_Ignore,#PB_Ignore) + ; ResizeGadget(#Gdt_RotateLeft, WindowWidth(#Window_0) - 150 ,#PB_Ignore,#PB_Ignore,#PB_Ignore) + ; ResizeGadget(#Gdt_RotateRight,WindowWidth(#Window_0) - 90 ,#PB_Ignore,#PB_Ignore,#PB_Ignore) ResizeGadget(#Gdt_Up, WindowWidth(#Window_0) - 120 ,#PB_Ignore,#PB_Ignore,#PB_Ignore) ResizeGadget(#Gdt_Down, WindowWidth(#Window_0) - 120 ,#PB_Ignore,#PB_Ignore,#PB_Ignore) ResizeGadget(#Text_2,WindowWidth(#Window_0)-170,#PB_Ignore,#PB_Ignore,#PB_Ignore) @@ -2613,8 +2651,8 @@ CompilerIf #PB_Compiler_IsMainFile LoadFont(2, "Arial", 8) TextGadget(#Text_1, 530, 10, 60, 15, "Movements") - ;ButtonGadget(#Gdt_RotateLeft, 550, 070, 30, 30, "LRot") : SetGadgetFont(#Gdt_RotateLeft, FontID(2)) - ;ButtonGadget(#Gdt_RotateRight, 610, 070, 30, 30, "RRot") : SetGadgetFont(#Gdt_RotateRight, FontID(2)) + ; ButtonGadget(#Gdt_RotateLeft, 550, 070, 30, 30, "LRot") : SetGadgetFont(#Gdt_RotateLeft, FontID(2)) + ; ButtonGadget(#Gdt_RotateRight, 610, 070, 30, 30, "RRot") : SetGadgetFont(#Gdt_RotateRight, FontID(2)) ButtonGadget(#Gdt_Left, 550, 60, 30, 30, Chr($25C4)) : SetGadgetFont(#Gdt_Left, FontID(0)) ButtonGadget(#Gdt_Right, 610, 60, 30, 30, Chr($25BA)) : SetGadgetFont(#Gdt_Right, FontID(0)) ButtonGadget(#Gdt_Up, 580, 030, 30, 30, Chr($25B2)) : SetGadgetFont(#Gdt_Up, FontID(0)) @@ -2639,20 +2677,20 @@ CompilerIf #PB_Compiler_IsMainFile StringGadget(#StringGeoLocationQuery, 530, 530, 150, 20, "") SetActiveGadget(#StringGeoLocationQuery) AddKeyboardShortcut(#Window_0, #PB_Shortcut_Return, #MenuEventGeoLocationStringEnter) - ;*** TODO : code to remove when the SetActiveGadget(-1) will be fixed + ; *** TODO : code to remove when the SetActiveGadget(-1) will be fixed CompilerIf #PB_Compiler_OS = #PB_OS_Linux Define Dummy = ButtonGadget(#PB_Any, 0, 0, 1, 1, "Dummy") HideGadget(Dummy, 1) CompilerElse Define Dummy = -1 CompilerEndIf - ;*** + ; *** Define Event.i, Gadget.i, Quit.b = #False Define pfValue.d Define Degrees = 1 Define *Track - ;Our main gadget + ; Our main gadget PBMap::InitPBMap(#Window_0) PBMap::SetOption("ShowDegrees", "1") : Degrees = 0 PBMap::SetOption("ShowDebugInfos", "1") @@ -2673,7 +2711,7 @@ CompilerIf #PB_Compiler_IsMainFile Event = WaitWindowEvent() Select Event Case #PB_Event_CloseWindow : Quit = 1 - Case #PB_Event_Gadget ;{ + Case #PB_Event_Gadget ; { Gadget = EventGadget() Select Gadget Case #Gdt_Up @@ -2684,12 +2722,12 @@ CompilerIf #PB_Compiler_IsMainFile PBMap::SetLocation(0, 10* -360 / Pow(2, PBMap::GetZoom() + 8), 0, #PB_Relative) Case #Gdt_Right PBMap::SetLocation(0, 10* 360 / Pow(2, PBMap::GetZoom() + 8), 0, #PB_Relative) - ;Case #Gdt_RotateLeft - ; PBMAP::SetAngle(-5,#PB_Relative) - ; PBMap::Refresh() - ;Case #Gdt_RotateRight - ; PBMAP::SetAngle(5,#PB_Relative) - ; PBMap::Refresh() + ; Case #Gdt_RotateLeft + ; PBMAP::SetAngle(-5,#PB_Relative) + ; PBMap::Refresh() + ; Case #Gdt_RotateRight + ; PBMAP::SetAngle(5,#PB_Relative) + ; PBMap::Refresh() Case #Button_4 PBMap::SetZoom(1) Case #Button_5 @@ -2776,16 +2814,16 @@ CompilerIf #PB_Compiler_IsMainFile Case #PB_Event_SizeWindow ResizeAll() Case #PB_Event_Menu - ;Receive "enter" key events + ; Receive "enter" key events Select EventMenu() Case #MenuEventGeoLocationStringEnter If GetGadgetText(#StringGeoLocationQuery) <> "" PBMap::NominatimGeoLocationQuery(GetGadgetText(#StringGeoLocationQuery)) PBMap::Refresh() EndIf - ;*** TODO : code to change when the SetActiveGadget(-1) will be fixed + ; *** TODO : code to change when the SetActiveGadget(-1) will be fixed SetActiveGadget(Dummy) - ;*** + ; *** Case #MenuEventLonLatStringEnter PBMap::SetLocation(ValD(GetGadgetText(#StringLatitude)), ValD(GetGadgetText(#StringLongitude))) ; Change the PBMap coordinates PBMap::Refresh() @@ -2799,8 +2837,8 @@ CompilerIf #PB_Compiler_IsMainFile CompilerEndIf ; IDE Options = PureBasic 5.60 (Windows - x64) -; CursorPosition = 893 -; FirstLine = 894 +; CursorPosition = 1162 +; FirstLine = 1143 ; Folding = ------------------- ; EnableThread ; EnableXP From bbb66d20b6330b335a99b9968addfd06d19a0ecf Mon Sep 17 00:00:00 2001 From: djes Date: Fri, 9 Jun 2017 16:08:39 +0200 Subject: [PATCH 06/16] Little bugfix --- PBMap.pb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/PBMap.pb b/PBMap.pb index d2fb5a2..5cd659d 100644 --- a/PBMap.pb +++ b/PBMap.pb @@ -1272,7 +1272,7 @@ Module PBMap MyDebug(" Error, maximum threads nb reached", 3) EndIf EndIf - ProcedureReturn *timg + ProcedureReturn 0 EndProcedure Procedure DrawTiles(*Drawing.DrawingParameters, LayerName.s) @@ -2837,8 +2837,8 @@ CompilerIf #PB_Compiler_IsMainFile CompilerEndIf ; IDE Options = PureBasic 5.60 (Windows - x64) -; CursorPosition = 1162 -; FirstLine = 1143 +; CursorPosition = 1241 +; FirstLine = 1233 ; Folding = ------------------- ; EnableThread ; EnableXP From 1b903ffdc6cfcb2719ea25dfb6b8943bcbecb9db Mon Sep 17 00:00:00 2001 From: djes Date: Fri, 9 Jun 2017 16:58:58 +0200 Subject: [PATCH 07/16] One more lil bugfix --- PBMap.pb | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/PBMap.pb b/PBMap.pb index 5cd659d..3e1b8d8 100644 --- a/PBMap.pb +++ b/PBMap.pb @@ -1246,10 +1246,7 @@ Module PBMap If PBMap\ThreadsNB < PBMap\Options\MaxThreads Protected *NewTile.Tile = AllocateMemory(SizeOf(Tile)) If *NewTile - With *NewTile - *timg\Tile = *NewTile ; There's now a loading thread - *timg\Alpha = 0 - ; *timg\nImage = -1 + With *NewTile ; New tile parameters \key = key \URL = URL @@ -1258,6 +1255,9 @@ Module PBMap \Time = ElapsedMilliseconds() \GetImageThread = CreateThread(@GetImageThread(), *NewTile) If \GetImageThread + *timg\Tile = *NewTile ; There's now a loading thread + *timg\Alpha = 0 + ; *timg\nImage = 0 MyDebug(" Creating get image thread nb " + Str(\GetImageThread) + " to get " + CacheFile, 3) PBMap\ThreadsNB + 1 Else @@ -2837,8 +2837,8 @@ CompilerIf #PB_Compiler_IsMainFile CompilerEndIf ; IDE Options = PureBasic 5.60 (Windows - x64) -; CursorPosition = 1241 -; FirstLine = 1233 +; CursorPosition = 1259 +; FirstLine = 1229 ; Folding = ------------------- ; EnableThread ; EnableXP From bb405afca97b57c8d05e64d47d32a42b19aab2d7 Mon Sep 17 00:00:00 2001 From: djes Date: Mon, 12 Jun 2017 12:32:51 +0200 Subject: [PATCH 08/16] Download slots bugfix --- PBMap.pb | 42 +++++++++++++++++++++++++----------------- 1 file changed, 25 insertions(+), 17 deletions(-) diff --git a/PBMap.pb b/PBMap.pb index 3e1b8d8..931101b 100644 --- a/PBMap.pb +++ b/PBMap.pb @@ -294,7 +294,7 @@ Module PBMap MemoryCacheManagement.i ; To pause web loading threads DownloadSlots.i ; Actual nb of used download slots DownloadSlotsMutex.i ; To be sure that only one thread at a time can access to the DownloadSlots var - + List TracksList.Tracks() ; To display a GPX track List Markers.Marker() ; To diplay marker EditMarker.l @@ -1089,13 +1089,13 @@ Module PBMap Procedure.i GetTileFromHDD(CacheFile.s) MaxLifeTime.i = PBMap\Options\TileLifetime If FileSize(CacheFile) > 0 ; <> -1 - ; Manage tile file lifetime + ; Manage tile file lifetime If MaxLifeTime <> -1 LifeTime = Date() - GetFileDate(CacheFile, #PB_Date_Modified) ; There's a bug with #PB_Date_Created If LifeTime > MaxLifeTime MyDebug(" Deleting too old (" + StrU(LifeTime) + " secs) " + CacheFile, 3) DeleteFile(CacheFile) - ProcedureReturn 0 + ProcedureReturn #False EndIf EndIf ; Everything is OK, loads the file @@ -1155,6 +1155,7 @@ Module PBMap PostEvent(#PB_Event_Gadget, PBMap\Window, PBmap\Gadget, #PB_MAP_TILE_CLEANUP, *Tile) ; To free memory outside the thread ProcedureReturn #False EndIf + MyDebug(" Thread for image " + *Tile\CacheFile + " waiting a download slot", 5) Delay(500) LockMutex(PBMap\DownloadSlotsMutex) Wend @@ -1169,16 +1170,25 @@ Module PBMap Case #PB_Http_Success Size = FinishHTTP(*Tile\Download) MyDebug(" Thread for image " + *Tile\CacheFile + " finished. Size : " + Str(Size), 5) + LockMutex(PBMap\DownloadSlotsMutex) + PBMap\DownloadSlots - 1 + UnlockMutex(PBMap\DownloadSlotsMutex) PostEvent(#PB_Event_Gadget, PBMap\Window, PBmap\Gadget, #PB_MAP_TILE_CLEANUP, *Tile) ; To free memory outside the thread ProcedureReturn #True Case #PB_Http_Failed FinishHTTP(*Tile\Download) MyDebug(" Thread for image " + *Tile\CacheFile + " failed.", 5) + LockMutex(PBMap\DownloadSlotsMutex) + PBMap\DownloadSlots - 1 + UnlockMutex(PBMap\DownloadSlotsMutex) PostEvent(#PB_Event_Gadget, PBMap\Window, PBmap\Gadget, #PB_MAP_TILE_CLEANUP, *Tile) ; To free memory outside the thread ProcedureReturn #False Case #PB_Http_Aborted FinishHTTP(*Tile\Download) MyDebug(" Thread for image " + *Tile\CacheFile + " aborted.", 5) + LockMutex(PBMap\DownloadSlotsMutex) + PBMap\DownloadSlots - 1 + UnlockMutex(PBMap\DownloadSlotsMutex) PostEvent(#PB_Event_Gadget, PBMap\Window, PBmap\Gadget, #PB_MAP_TILE_CLEANUP, *Tile) ; To free memory outside the thread ProcedureReturn #False Default @@ -1200,9 +1210,9 @@ Module PBMap ; HDD, or launch a web loading thread, and try again on the next drawing loop. Protected *timg.ImgMemCach = FindMapElement(PBMap\MemCache\Images(), key) If *timg - MyDebug("Key : " + key + " found in memory cache", 5) + MyDebug("Key : " + key + " found in memory cache", 4) If *timg\nImage - MyDebug(" as image " + *timg\nImage, 5) + MyDebug(" as image " + *timg\nImage, 4) ; *** Cache management ; Retrieves the image in the time stack, push it to the end (to say it's the lastly used) ChangeCurrentElement(PBMap\MemCache\ImagesTimeStack(), *timg\TimeStackPtr) @@ -1211,13 +1221,13 @@ Module PBMap ; *** ProcedureReturn *timg Else - MyDebug(" but not the image.", 5) + MyDebug(" but not the image.", 4) EndIf Else ; Creates a new cache element *timg = AddMapElement(PBMap\MemCache\Images(), key) If *timg = 0 - MyDebug(" Can't add a new cache element.", 5) + MyDebug(" Can't add a new cache element.", 4) ProcedureReturn 0 EndIf ; add a new time stack element at the End @@ -1225,17 +1235,17 @@ Module PBMap ; Stores the time stack ptr *timg\TimeStackPtr = AddElement(PBMap\MemCache\ImagesTimeStack()) If *timg\TimeStackPtr = 0 - MyDebug(" Can't add a new time stack element.", 5) + MyDebug(" Can't add a new time stack element.", 4) DeleteMapElement(PBMap\MemCache\Images()) ProcedureReturn 0 EndIf ; Associates the time stack element to the cache element PBMap\MemCache\ImagesTimeStack()\MapKey = MapKey(PBMap\MemCache\Images()) - MyDebug("Key : " + key + " added in memory cache", 5) + MyDebug("Key : " + key + " added in memory cache", 4) ; *** EndIf If *timg\Tile = 0 ; Checks if a loading thread is not already running - ; Is the file image on HDD ? + ; Is the file image on HDD ? *timg\nImage = GetTileFromHDD(CacheFile.s) If *timg\nImage ; Image found and loaded from HDD @@ -2439,9 +2449,6 @@ Module PBMap ; After a Web tile loading thread, clean the tile structure memory and set the image nb in the cache ; avoid to have threads accessing vars (and avoid some mutex), see GetImageThread() *Tile\Download = 0 - LockMutex(PBMap\DownloadSlotsMutex) - PBMap\DownloadSlots - 1 - UnlockMutex(PBMap\DownloadSlotsMutex) Protected timg = PBMap\MemCache\Images(key)\Tile\nImage ; Get this new tile image nb PBMap\MemCache\Images(key)\nImage = timg ; Stores it in the cache using the key FreeMemory(PBMap\MemCache\Images(key)\Tile) ; Frees the data needed for the thread @@ -2483,7 +2490,7 @@ Module PBMap Procedure Quit() PBMap\Drawing\End = #True PBMap\MemoryCacheManagement = #True ; Tells web loading threads to pause - ; Wait for loading threads to finish nicely. Passed 2 seconds, kills them. + ; Wait for loading threads to finish nicely. Passed 2 seconds, kills them. Protected TimeCounter = ElapsedMilliseconds() Repeat ForEach PBMap\MemCache\Images() @@ -2837,9 +2844,10 @@ CompilerIf #PB_Compiler_IsMainFile CompilerEndIf ; IDE Options = PureBasic 5.60 (Windows - x64) -; CursorPosition = 1259 -; FirstLine = 1229 +; CursorPosition = 1107 +; FirstLine = 1104 ; Folding = ------------------- ; EnableThread ; EnableXP -; CompileSourceDirectory \ No newline at end of file +; CompileSourceDirectory +; Watchlist = PBMap::PBMap\DownloadSlots \ No newline at end of file From 61503c3e98a2ce5a7522bef3d41f2829c192dc63 Mon Sep 17 00:00:00 2001 From: djes Date: Mon, 12 Jun 2017 20:37:08 +0200 Subject: [PATCH 09/16] Several bugfix --- PBMap.pb | 114 ++++++++++++++++++++++++++++++++----------------------- 1 file changed, 66 insertions(+), 48 deletions(-) diff --git a/PBMap.pb b/PBMap.pb index 931101b..d88e8aa 100644 --- a/PBMap.pb +++ b/PBMap.pb @@ -126,6 +126,7 @@ Module PBMap GetImageThread.i Download.i Time.i + Size.i EndStructure Structure BoundingBox @@ -309,7 +310,7 @@ Module PBMap ;-*** Global variables ;-Show debug infos - Global MyDebugLevel = 5 + Global MyDebugLevel = 3 Global PBMap.PBMap, Null.i, NullPtrMem.i, *NullPtr = @NullPtrMem Global slash.s @@ -1046,7 +1047,7 @@ Module PBMap Procedure MemoryCacheManagement() ; If cache size exceeds limit, try to delete the oldest tiles used (first in the time stack) - Protected CacheSize = MapSize(PBMap\MemCache\Images()) * Pow(PBMap\TileSize, 2) * 5 ; Size of a tile = TileSize * TileSize * 4 bytes (RGBA) + Protected CacheSize = MapSize(PBMap\MemCache\Images()) * Pow(PBMap\TileSize, 2) * 4 ; Size of a tile = TileSize * TileSize * 4 bytes (RGBA) Protected CacheLimit = PBMap\Options\MaxMemCache * 1024 MyDebug("Cache size : " + Str(CacheSize/1024) + " / CacheLimit : " + Str(CacheLimit/1024), 5) If CacheSize > CacheLimit @@ -1056,16 +1057,21 @@ Module PBMap ; Try to free half the cache memory (one pass) While NextElement(PBMap\MemCache\ImagesTimeStack()) And CacheSize > (CacheLimit / 2) ; /2 = half Protected CacheMapKey.s = PBMap\MemCache\ImagesTimeStack()\MapKey - Protected Image = PBMap\MemCache\Images(CacheMapKey)\nImage - If PBMap\MemCache\Images(CacheMapKey)\Tile = 0 ; Check if a loading thread is not already running + ;Protected Image = PBMap\MemCache\Images(CacheMapKey)\nImage + ; Is the loading over + If PBMap\MemCache\Images(CacheMapKey)\Tile = -1 MyDebug(" Delete " + CacheMapKey, 5) - If IsImage(Image) ; Check if the image is valid - FreeImage(Image) - MyDebug(" and free image nb " + Str(Image), 5) + If IsImage(PBMap\MemCache\Images(CacheMapKey)\nImage) + FreeImage(PBMap\MemCache\Images(CacheMapKey)\nImage) + MyDebug(" and free image nb " + Str(PBMap\MemCache\Images(CacheMapKey)\nImage), 5) EndIf DeleteMapElement(PBMap\MemCache\Images(), CacheMapKey) - DeleteElement(PBMap\MemCache\ImagesTimeStack()) - Else + DeleteElement(PBMap\MemCache\ImagesTimeStack(), 1) + ElseIf PBMap\MemCache\Images(CacheMapKey)\Tile = 0 + MyDebug(" Delete " + CacheMapKey, 5) + DeleteMapElement(PBMap\MemCache\Images(), CacheMapKey) + DeleteElement(PBMap\MemCache\ImagesTimeStack(), 1) + ElseIf PBMap\MemCache\Images(CacheMapKey)\Tile > 0 ; If the thread is running, try to abort the download If PBMap\MemCache\Images(CacheMapKey)\Tile\Download AbortHTTP(PBMap\MemCache\Images(CacheMapKey)\Tile\Download) @@ -1077,19 +1083,17 @@ Module PBMap MyDebug(" New cache size : " + Str(CacheSize/1024) + " / CacheLimit : " + Str(CacheLimit/1024), 5) If CacheSize > CacheLimit MyDebug(" Cache cleaning unsuccessfull, can't add new tiles.", 5) - ProcedureReturn 0 + ProcedureReturn #False EndIf EndIf + ProcedureReturn #True EndProcedure - - ;-*** These are threaded - - Threaded nImage.i, LifeTime.i, MaxLifeTime.i - + Procedure.i GetTileFromHDD(CacheFile.s) + Protected nImage.i, LifeTime.i, MaxLifeTime.i MaxLifeTime.i = PBMap\Options\TileLifetime If FileSize(CacheFile) > 0 ; <> -1 - ; Manage tile file lifetime + ; Manage tile file lifetime If MaxLifeTime <> -1 LifeTime = Date() - GetFileDate(CacheFile, #PB_Date_Modified) ; There's a bug with #PB_Date_Created If LifeTime > MaxLifeTime @@ -1114,7 +1118,7 @@ Module PBMap Else MyDebug(" Failed loading " + CacheFile + " -> Filesize = " + FileSize(CacheFile), 3) EndIf - ProcedureReturn 0 + ProcedureReturn #False EndProcedure ; **** OLD IMPORTANT NOTICE (please not remove) @@ -1142,6 +1146,8 @@ Module PBMap ; EndIf ; **** + ;-*** These are threaded + Threaded Progress = 0, Size = 0 Procedure GetImageThread(*Tile.Tile) @@ -1164,11 +1170,11 @@ Module PBMap *Tile\Download = ReceiveHTTPFile(*Tile\URL, *Tile\CacheFile, #PB_HTTP_Asynchronous) If *Tile\Download Repeat - If PBMap\MemoryCacheManagement = #False ; Wait until cache cleaning is done + ;If PBMap\MemoryCacheManagement = #False ; Wait until cache cleaning is done Progress = HTTPProgress(*Tile\Download) Select Progress Case #PB_Http_Success - Size = FinishHTTP(*Tile\Download) + *Tile\Size = FinishHTTP(*Tile\Download) ; \Size signals that the download is OK MyDebug(" Thread for image " + *Tile\CacheFile + " finished. Size : " + Str(Size), 5) LockMutex(PBMap\DownloadSlotsMutex) PBMap\DownloadSlots - 1 @@ -1177,6 +1183,7 @@ Module PBMap ProcedureReturn #True Case #PB_Http_Failed FinishHTTP(*Tile\Download) + *Tile\Size = 0 ; \Size = 0 signals that the download has failed MyDebug(" Thread for image " + *Tile\CacheFile + " failed.", 5) LockMutex(PBMap\DownloadSlotsMutex) PBMap\DownloadSlots - 1 @@ -1185,6 +1192,7 @@ Module PBMap ProcedureReturn #False Case #PB_Http_Aborted FinishHTTP(*Tile\Download) + *Tile\Size = 0 ; \Size = 0 signals that the download has failed MyDebug(" Thread for image " + *Tile\CacheFile + " aborted.", 5) LockMutex(PBMap\DownloadSlotsMutex) PBMap\DownloadSlots - 1 @@ -1193,26 +1201,29 @@ Module PBMap ProcedureReturn #False Default MyDebug(" Thread for image " + *Tile\CacheFile + " downloading " + Str(Progress) + " bytes", 5) - If ElapsedMilliseconds() - *Tile\Time > 60000 - MyDebug(" Thread for image " + *Tile\CacheFile + " canceled after 60 seconds.", 5) + If ElapsedMilliseconds() - *Tile\Time > 10000 + MyDebug(" Thread for image " + *Tile\CacheFile + " canceled after 10 seconds.", 5) AbortHTTP(*Tile\Download) EndIf EndSelect - EndIf + ;EndIf Delay(500) ; Frees CPU ForEver EndIf EndProcedure + ;-*** Procedure.i GetTile(key.s, URL.s, CacheFile.s) - ; Try to find the tile in memory cache. If not found, add it if there's enough room in the cache, try to load the picture from the - ; HDD, or launch a web loading thread, and try again on the next drawing loop. + ; Try to find the tile in memory cache Protected *timg.ImgMemCach = FindMapElement(PBMap\MemCache\Images(), key) If *timg MyDebug("Key : " + key + " found in memory cache", 4) - If *timg\nImage + ; Is the associated image already been loaded in memory ? + If *timg\nImage And IsImage(*timg\nImage) + ; Yes, returns the image's nb MyDebug(" as image " + *timg\nImage, 4) + *timg\Tile = -1 ; *** Cache management ; Retrieves the image in the time stack, push it to the end (to say it's the lastly used) ChangeCurrentElement(PBMap\MemCache\ImagesTimeStack(), *timg\TimeStackPtr) @@ -1221,14 +1232,15 @@ Module PBMap ; *** ProcedureReturn *timg Else + ; No, will load it below MyDebug(" but not the image.", 4) EndIf Else - ; Creates a new cache element + ; The tile has not been found in the cache, so creates a new cache element *timg = AddMapElement(PBMap\MemCache\Images(), key) If *timg = 0 MyDebug(" Can't add a new cache element.", 4) - ProcedureReturn 0 + ProcedureReturn #False EndIf ; add a new time stack element at the End LastElement(PBMap\MemCache\ImagesTimeStack()) @@ -1237,22 +1249,27 @@ Module PBMap If *timg\TimeStackPtr = 0 MyDebug(" Can't add a new time stack element.", 4) DeleteMapElement(PBMap\MemCache\Images()) - ProcedureReturn 0 + ProcedureReturn #False EndIf ; Associates the time stack element to the cache element PBMap\MemCache\ImagesTimeStack()\MapKey = MapKey(PBMap\MemCache\Images()) MyDebug("Key : " + key + " added in memory cache", 4) ; *** EndIf - If *timg\Tile = 0 ; Checks if a loading thread is not already running - ; Is the file image on HDD ? + ; Is this tile not loading ? + If *timg\Tile <= 0 + ; Is the file image on HDD ? *timg\nImage = GetTileFromHDD(CacheFile.s) If *timg\nImage ; Image found and loaded from HDD *timg\Alpha = 256 + *timg\Tile = -1 ProcedureReturn *timg EndIf - ; Image not found on HDD, launch a new web loading thread + EndIf + ; If there's not this tile in memory and no web loading thread + If *timg\Tile = 0 + ; Launch a new one If PBMap\ThreadsNB < PBMap\Options\MaxThreads Protected *NewTile.Tile = AllocateMemory(SizeOf(Tile)) If *NewTile @@ -1267,7 +1284,6 @@ Module PBMap If \GetImageThread *timg\Tile = *NewTile ; There's now a loading thread *timg\Alpha = 0 - ; *timg\nImage = 0 MyDebug(" Creating get image thread nb " + Str(\GetImageThread) + " to get " + CacheFile, 3) PBMap\ThreadsNB + 1 Else @@ -1282,7 +1298,7 @@ Module PBMap MyDebug(" Error, maximum threads nb reached", 3) EndIf EndIf - ProcedureReturn 0 + ProcedureReturn #False EndProcedure Procedure DrawTiles(*Drawing.DrawingParameters, LayerName.s) @@ -1362,7 +1378,7 @@ Module PBMap EndSelect EndWith *timg = GetTile(key, URL, CacheFile) - If *timg And *timg\nImage + If *timg And *timg\nImage And IsImage(*timg\nImage) MovePathCursor(px, py) If *timg\Alpha <= 224 DrawVectorImage(ImageID(*timg\nImage), *timg\Alpha * PBMap\Layers()\Alpha) @@ -1840,7 +1856,7 @@ Module PBMap MovePathCursor(50, 70) Protected ThreadCounter = 0 ForEach PBMap\MemCache\Images() - If PBMap\MemCache\Images()\Tile <> 0 + If PBMap\MemCache\Images()\Tile > 0 If IsThread(PBMap\MemCache\Images()\Tile\GetImageThread) ThreadCounter + 1 EndIf @@ -2438,21 +2454,23 @@ Module PBMap PBMap\Dragging = #False PBMap\Redraw = #True Case #PB_MAP_REDRAW - Debug "Redraw" PBMap\Redraw = #True Case #PB_MAP_RETRY - Debug "Reload" PBMap\Redraw = #True Case #PB_MAP_TILE_CLEANUP *Tile = EventData() key = *Tile\key - ; After a Web tile loading thread, clean the tile structure memory and set the image nb in the cache - ; avoid to have threads accessing vars (and avoid some mutex), see GetImageThread() + ; After a Web tile loading thread, clean the tile structure memory, see GetImageThread() *Tile\Download = 0 - Protected timg = PBMap\MemCache\Images(key)\Tile\nImage ; Get this new tile image nb - PBMap\MemCache\Images(key)\nImage = timg ; Stores it in the cache using the key - FreeMemory(PBMap\MemCache\Images(key)\Tile) ; Frees the data needed for the thread - PBMap\MemCache\Images(key)\Tile = 0 ; Clears the data ptr, the web loading thread is finished + If *Tile\Size ; <> 0 + FreeMemory(PBMap\MemCache\Images(key)\Tile) ; Frees the data needed for the thread + PBMap\MemCache\Images(key)\Tile = -1 ; Clears the data ptr, and says that the web loading thread has finished successfully + Else + FreeMemory(PBMap\MemCache\Images(key)\Tile) ; Frees the data needed for the thread + PBMap\MemCache\Images(key)\Tile = 0 ; Clears the data ptr, and says that the web loading thread has finished unsuccessfully + EndIf + ;Protected timg = PBMap\MemCache\Images(key)\Tile\nImage ; Get this new tile image nb + ;PBMap\MemCache\Images(key)\nImage = timg ; Stores it in the cache using the key PBMap\ThreadsNB - 1 PBMap\Redraw = #True EndSelect @@ -2461,7 +2479,7 @@ Module PBMap ; Redraws at regular intervals Procedure TimerEvents() If EventTimer() = PBMap\Timer And (PBMap\Redraw Or PBMap\Dirty) - ; MemoryCacheManagement() + MemoryCacheManagement() Drawing() EndIf EndProcedure @@ -2490,11 +2508,11 @@ Module PBMap Procedure Quit() PBMap\Drawing\End = #True PBMap\MemoryCacheManagement = #True ; Tells web loading threads to pause - ; Wait for loading threads to finish nicely. Passed 2 seconds, kills them. + ; Wait for loading threads to finish nicely. Passed 2 seconds, kills them. Protected TimeCounter = ElapsedMilliseconds() Repeat ForEach PBMap\MemCache\Images() - If PBMap\MemCache\Images()\Tile <> 0 + If PBMap\MemCache\Images()\Tile > 0 If IsThread(PBMap\MemCache\Images()\Tile\GetImageThread) If ElapsedMilliseconds() - TimeCounter > 2000 ; Should not occur @@ -2844,8 +2862,8 @@ CompilerIf #PB_Compiler_IsMainFile CompilerEndIf ; IDE Options = PureBasic 5.60 (Windows - x64) -; CursorPosition = 1107 -; FirstLine = 1104 +; CursorPosition = 1047 +; FirstLine = 1047 ; Folding = ------------------- ; EnableThread ; EnableXP From da8c3e90011f9befcd2e8203b69aa8699a64cd5b Mon Sep 17 00:00:00 2001 From: djes Date: Tue, 13 Jun 2017 21:04:59 +0200 Subject: [PATCH 10/16] semaphores test --- PBMap.pb | 138 +++++++++++++++++++++++++++++++++---------------------- 1 file changed, 83 insertions(+), 55 deletions(-) diff --git a/PBMap.pb b/PBMap.pb index d88e8aa..4fe9cae 100644 --- a/PBMap.pb +++ b/PBMap.pb @@ -123,7 +123,7 @@ Module PBMap key.s URL.s CacheFile.s - GetImageThread.i + *GetImageThread Download.i Time.i Size.i @@ -292,7 +292,12 @@ Module PBMap Dragging.i Dirty.i ; To signal that drawing need a refresh - MemoryCacheManagement.i ; To pause web loading threads + *MemoryCacheManagementThread + ResourceAccessSemaphore.i ; To pause web loading threads + ReadCountAccessSemaphore.i + ServiceQueueSemaphore.i + ReadCount.i + DownloadSlots.i ; Actual nb of used download slots DownloadSlotsMutex.i ; To be sure that only one thread at a time can access to the DownloadSlots var @@ -1045,13 +1050,18 @@ Module PBMap ;-*** - Procedure MemoryCacheManagement() + Procedure MemoryCacheManagement(*Void) + With PBMap + WaitSemaphore(\ServiceQueueSemaphore) ;serviceQueue.P(); // wait in line to be serviced + WaitSemaphore(\ResourceAccessSemaphore) ;resourceAccess.P(); // request exclusive access to resource + SignalSemaphore(\ServiceQueueSemaphore) ;serviceQueue.V(); // let next in line be serviced + EndWith ; If cache size exceeds limit, try to delete the oldest tiles used (first in the time stack) Protected CacheSize = MapSize(PBMap\MemCache\Images()) * Pow(PBMap\TileSize, 2) * 4 ; Size of a tile = TileSize * TileSize * 4 bytes (RGBA) Protected CacheLimit = PBMap\Options\MaxMemCache * 1024 MyDebug("Cache size : " + Str(CacheSize/1024) + " / CacheLimit : " + Str(CacheLimit/1024), 5) - If CacheSize > CacheLimit - PBMap\MemoryCacheManagement = #True + If CacheSize > CacheLimit + ;PBMap\MemoryCacheManagement = #True MyDebug(" Cache full. Trying cache cleaning", 5) ResetList(PBMap\MemCache\ImagesTimeStack()) ; Try to free half the cache memory (one pass) @@ -1061,9 +1071,10 @@ Module PBMap ; Is the loading over If PBMap\MemCache\Images(CacheMapKey)\Tile = -1 MyDebug(" Delete " + CacheMapKey, 5) - If IsImage(PBMap\MemCache\Images(CacheMapKey)\nImage) + If PBMap\MemCache\Images(CacheMapKey)\nImage;IsImage(PBMap\MemCache\Images(CacheMapKey)\nImage) FreeImage(PBMap\MemCache\Images(CacheMapKey)\nImage) MyDebug(" and free image nb " + Str(PBMap\MemCache\Images(CacheMapKey)\nImage), 5) + PBMap\MemCache\Images(CacheMapKey)\nImage = 0 EndIf DeleteMapElement(PBMap\MemCache\Images(), CacheMapKey) DeleteElement(PBMap\MemCache\ImagesTimeStack(), 1) @@ -1079,14 +1090,13 @@ Module PBMap EndIf CacheSize = MapSize(PBMap\MemCache\Images()) * Pow(PBMap\TileSize, 2) * 4 ; Size of a tile = TileSize * TileSize * 4 bytes (RGBA) Wend - PBMap\MemoryCacheManagement = #False + ;PBMap\MemoryCacheManagement = #False MyDebug(" New cache size : " + Str(CacheSize/1024) + " / CacheLimit : " + Str(CacheLimit/1024), 5) If CacheSize > CacheLimit MyDebug(" Cache cleaning unsuccessfull, can't add new tiles.", 5) - ProcedureReturn #False EndIf EndIf - ProcedureReturn #True + SignalSemaphore(PBMap\ResourceAccessSemaphore) ; resourceAccess.V(); // release resource access for next reader/writer EndProcedure Procedure.i GetTileFromHDD(CacheFile.s) @@ -1104,7 +1114,7 @@ Module PBMap EndIf ; Everything is OK, loads the file nImage = LoadImage(#PB_Any, CacheFile) - If nImage And IsImage(nImage) + If nImage MyDebug(" Success loading " + CacheFile + " as nImage " + Str(nImage), 3) ProcedureReturn nImage Else @@ -1148,15 +1158,26 @@ Module PBMap ;-*** These are threaded - Threaded Progress = 0, Size = 0 + Threaded Progress = 0, Size = 0, Quit.i = #False Procedure GetImageThread(*Tile.Tile) + With PBMap + WaitSemaphore(\ServiceQueueSemaphore) ;serviceQueue.P(); // wait in line to be serviced + WaitSemaphore(\ReadCountAccessSemaphore) ;readCountAccess.P(); // request exclusive access to readCount + If \ReadCount = 0 ;If (readCount == 0) // If there are no readers already reading: + WaitSemaphore(\ResourceAccessSemaphore) ; resourceAccess.P(); // request resource access for readers (writers blocked) + EndIf + \ReadCount + 1 ;readCount++; // update count of active readers + SignalSemaphore(\ServiceQueueSemaphore) ;serviceQueue.V(); // let next in line be serviced + SignalSemaphore(\ReadCountAccessSemaphore) ;readCountAccess.V(); // release access to readCount + EndWith MyDebug("Thread starting for image " + *Tile\CacheFile + "(" + *Tile\key + ")", 5) ; Waits for a free download slot LockMutex(PBMap\DownloadSlotsMutex) While PBMap\DownloadSlots >= PBMap\Options\MaxDownloadSlots UnlockMutex(PBMap\DownloadSlotsMutex) If ElapsedMilliseconds() - *Tile\Time > 10000 + *Tile\Size = 0 ; \Size = 0 signals that the download has failed MyDebug(" Thread for image " + *Tile\CacheFile + " canceled after 10 seconds waiting for a slot.", 5) PostEvent(#PB_Event_Gadget, PBMap\Window, PBmap\Gadget, #PB_MAP_TILE_CLEANUP, *Tile) ; To free memory outside the thread ProcedureReturn #False @@ -1170,57 +1191,57 @@ Module PBMap *Tile\Download = ReceiveHTTPFile(*Tile\URL, *Tile\CacheFile, #PB_HTTP_Asynchronous) If *Tile\Download Repeat - ;If PBMap\MemoryCacheManagement = #False ; Wait until cache cleaning is done - Progress = HTTPProgress(*Tile\Download) - Select Progress - Case #PB_Http_Success - *Tile\Size = FinishHTTP(*Tile\Download) ; \Size signals that the download is OK - MyDebug(" Thread for image " + *Tile\CacheFile + " finished. Size : " + Str(Size), 5) - LockMutex(PBMap\DownloadSlotsMutex) - PBMap\DownloadSlots - 1 - UnlockMutex(PBMap\DownloadSlotsMutex) - PostEvent(#PB_Event_Gadget, PBMap\Window, PBmap\Gadget, #PB_MAP_TILE_CLEANUP, *Tile) ; To free memory outside the thread - ProcedureReturn #True - Case #PB_Http_Failed - FinishHTTP(*Tile\Download) - *Tile\Size = 0 ; \Size = 0 signals that the download has failed - MyDebug(" Thread for image " + *Tile\CacheFile + " failed.", 5) - LockMutex(PBMap\DownloadSlotsMutex) - PBMap\DownloadSlots - 1 - UnlockMutex(PBMap\DownloadSlotsMutex) - PostEvent(#PB_Event_Gadget, PBMap\Window, PBmap\Gadget, #PB_MAP_TILE_CLEANUP, *Tile) ; To free memory outside the thread - ProcedureReturn #False - Case #PB_Http_Aborted - FinishHTTP(*Tile\Download) - *Tile\Size = 0 ; \Size = 0 signals that the download has failed - MyDebug(" Thread for image " + *Tile\CacheFile + " aborted.", 5) - LockMutex(PBMap\DownloadSlotsMutex) - PBMap\DownloadSlots - 1 - UnlockMutex(PBMap\DownloadSlotsMutex) - PostEvent(#PB_Event_Gadget, PBMap\Window, PBmap\Gadget, #PB_MAP_TILE_CLEANUP, *Tile) ; To free memory outside the thread - ProcedureReturn #False - Default - MyDebug(" Thread for image " + *Tile\CacheFile + " downloading " + Str(Progress) + " bytes", 5) - If ElapsedMilliseconds() - *Tile\Time > 10000 - MyDebug(" Thread for image " + *Tile\CacheFile + " canceled after 10 seconds.", 5) - AbortHTTP(*Tile\Download) - EndIf - EndSelect + ;If PBMap\MemoryCacheManagement = #False ; Wait until cache cleaning is done ;TODO + Progress = HTTPProgress(*Tile\Download) + Select Progress + Case #PB_Http_Success + *Tile\Size = FinishHTTP(*Tile\Download) ; \Size signals that the download is OK + MyDebug(" Thread for image " + *Tile\CacheFile + " finished. Size : " + Str(Size), 5) + Quit = #True + Case #PB_Http_Failed + FinishHTTP(*Tile\Download) + *Tile\Size = 0 ; \Size = 0 signals that the download has failed + MyDebug(" Thread for image " + *Tile\CacheFile + " failed.", 5) + Quit = #True + Case #PB_Http_Aborted + FinishHTTP(*Tile\Download) + *Tile\Size = 0 ; \Size = 0 signals that the download has failed + MyDebug(" Thread for image " + *Tile\CacheFile + " aborted.", 5) + Quit = #True + Default + MyDebug(" Thread for image " + *Tile\CacheFile + " downloading " + Str(Progress) + " bytes", 5) + If ElapsedMilliseconds() - *Tile\Time > 10000 + MyDebug(" Thread for image " + *Tile\CacheFile + " canceled after 10 seconds.", 5) + AbortHTTP(*Tile\Download) + EndIf + EndSelect ;EndIf Delay(500) ; Frees CPU - ForEver + Until Quit + LockMutex(PBMap\DownloadSlotsMutex) + PBMap\DownloadSlots - 1 + UnlockMutex(PBMap\DownloadSlotsMutex) + PostEvent(#PB_Event_Gadget, PBMap\Window, PBmap\Gadget, #PB_MAP_TILE_CLEANUP, *Tile) ; To free memory outside the thread EndIf + With PBMap + WaitSemaphore(\ReadCountAccessSemaphore) ;readCountAccess.P(); // request exclusive access to readCount + \ReadCount - 1 ;readCount--; // update count of active readers + If \ReadCount = 0 ;If (readCount == 0) // If there are no readers left: + SignalSemaphore(\ResourceAccessSemaphore) ; resourceAccess.V(); // release resource access for all + EndIf + SignalSemaphore(\ReadCountAccessSemaphore) ;readCountAccess.V(); + EndWith EndProcedure ;-*** - Procedure.i GetTile(key.s, URL.s, CacheFile.s) + Procedure.i GetTile(key.s, URL.s, CacheFile.s) ; Try to find the tile in memory cache Protected *timg.ImgMemCach = FindMapElement(PBMap\MemCache\Images(), key) If *timg MyDebug("Key : " + key + " found in memory cache", 4) ; Is the associated image already been loaded in memory ? - If *timg\nImage And IsImage(*timg\nImage) + If *timg\nImage ; Yes, returns the image's nb MyDebug(" as image " + *timg\nImage, 4) *timg\Tile = -1 @@ -1378,7 +1399,7 @@ Module PBMap EndSelect EndWith *timg = GetTile(key, URL, CacheFile) - If *timg And *timg\nImage And IsImage(*timg\nImage) + If *timg And *timg\nImage MovePathCursor(px, py) If *timg\Alpha <= 224 DrawVectorImage(ImageID(*timg\nImage), *timg\Alpha * PBMap\Layers()\Alpha) @@ -2457,11 +2478,14 @@ Module PBMap PBMap\Redraw = #True Case #PB_MAP_RETRY PBMap\Redraw = #True + ;- Tile cleanup Case #PB_MAP_TILE_CLEANUP *Tile = EventData() key = *Tile\key ; After a Web tile loading thread, clean the tile structure memory, see GetImageThread() *Tile\Download = 0 + ;Debug key + " cleanup event" + If *Tile\Size ; <> 0 FreeMemory(PBMap\MemCache\Images(key)\Tile) ; Frees the data needed for the thread PBMap\MemCache\Images(key)\Tile = -1 ; Clears the data ptr, and says that the web loading thread has finished successfully @@ -2469,6 +2493,7 @@ Module PBMap FreeMemory(PBMap\MemCache\Images(key)\Tile) ; Frees the data needed for the thread PBMap\MemCache\Images(key)\Tile = 0 ; Clears the data ptr, and says that the web loading thread has finished unsuccessfully EndIf + ;Debug "=" + Str(PBMap\MemCache\Images(key)\Tile) ;Protected timg = PBMap\MemCache\Images(key)\Tile\nImage ; Get this new tile image nb ;PBMap\MemCache\Images(key)\nImage = timg ; Stores it in the cache using the key PBMap\ThreadsNB - 1 @@ -2479,8 +2504,8 @@ Module PBMap ; Redraws at regular intervals Procedure TimerEvents() If EventTimer() = PBMap\Timer And (PBMap\Redraw Or PBMap\Dirty) - MemoryCacheManagement() Drawing() + PBMap\MemoryCacheManagementThread = CreateThread(@MemoryCacheManagement(), Null) EndIf EndProcedure @@ -2507,7 +2532,7 @@ Module PBMap Procedure Quit() PBMap\Drawing\End = #True - PBMap\MemoryCacheManagement = #True ; Tells web loading threads to pause + ;PBMap\MemoryCacheManagement = #True ; Tells web loading threads to pause ; Wait for loading threads to finish nicely. Passed 2 seconds, kills them. Protected TimeCounter = ElapsedMilliseconds() Repeat @@ -2543,6 +2568,9 @@ Module PBMap PBMap\Timer = 1 PBMap\Mode = #MODE_DEFAULT PBMap\DownloadSlotsMutex = CreateMutex() + PBMap\ResourceAccessSemaphore = CreateSemaphore(1) + PBMap\ReadCountAccessSemaphore = CreateSemaphore(1) + PBMap\ServiceQueueSemaphore = CreateSemaphore(1) If PBMap\DownloadSlotsMutex = #False MyDebug("Cannot create a mutex", 0) End @@ -2862,8 +2890,8 @@ CompilerIf #PB_Compiler_IsMainFile CompilerEndIf ; IDE Options = PureBasic 5.60 (Windows - x64) -; CursorPosition = 1047 -; FirstLine = 1047 +; CursorPosition = 1231 +; FirstLine = 1151 ; Folding = ------------------- ; EnableThread ; EnableXP From 7d351f4f92d5e7576dc4f15f970d63e387625606 Mon Sep 17 00:00:00 2001 From: djes Date: Wed, 14 Jun 2017 10:39:03 +0200 Subject: [PATCH 11/16] Threads and cache cleaning now mutually excluded --- PBMap.pb | 240 ++++++++++++++++++++++++++++--------------------------- 1 file changed, 122 insertions(+), 118 deletions(-) diff --git a/PBMap.pb b/PBMap.pb index 4fe9cae..e81b9f5 100644 --- a/PBMap.pb +++ b/PBMap.pb @@ -47,6 +47,7 @@ DeclareModule PBMap #PB_MAP_TILE_CLEANUP = #PB_EventType_FirstCustomValue + 3 Declare InitPBMap(window) + Declare SetDebugLevel(level.i) Declare SetOption(Option.s, Value.s) Declare.s GetOption(Option.s) Declare LoadOptions(PreferencesFile.s = "PBMap.prefs") @@ -123,7 +124,7 @@ Module PBMap key.s URL.s CacheFile.s - *GetImageThread + GetImageThread.i Download.i Time.i Size.i @@ -292,15 +293,12 @@ Module PBMap Dragging.i Dirty.i ; To signal that drawing need a refresh - *MemoryCacheManagementThread - ResourceAccessSemaphore.i ; To pause web loading threads - ReadCountAccessSemaphore.i - ServiceQueueSemaphore.i - ReadCount.i - + MemoryCacheAccessNB.i ; Count the access to the memory cache. =0 no access ; >0 download threads ; -1 cleaning + MemoryCacheAccessNBMutex.i ; Memorycache access variable mutual exclusion DownloadSlots.i ; Actual nb of used download slots DownloadSlotsMutex.i ; To be sure that only one thread at a time can access to the DownloadSlots var + List TracksList.Tracks() ; To display a GPX track List Markers.Marker() ; To diplay marker EditMarker.l @@ -315,7 +313,7 @@ Module PBMap ;-*** Global variables ;-Show debug infos - Global MyDebugLevel = 3 + Global MyDebugLevel = 5 Global PBMap.PBMap, Null.i, NullPtrMem.i, *NullPtr = @NullPtrMem Global slash.s @@ -358,10 +356,15 @@ Module PBMap MessageRequester("PBMap", msg, #PB_MessageRequester_Ok) EndIf EndProcedure + + ; Set the debug level allowing more or less debug infos + Procedure SetDebugLevel(level.i) + MyDebugLevel = level + EndProcedure ; Send debug infos to stdout (allowing mixed debug infos with curl or other libs) Procedure MyDebug(msg.s, DbgLevel = 0) - If PBMap\Options\Verbose And DbgLevel >= MyDebugLevel + If PBMap\Options\Verbose And DbgLevel <= MyDebugLevel PrintN(msg) ; Debug msg EndIf @@ -1050,60 +1053,63 @@ Module PBMap ;-*** - Procedure MemoryCacheManagement(*Void) - With PBMap - WaitSemaphore(\ServiceQueueSemaphore) ;serviceQueue.P(); // wait in line to be serviced - WaitSemaphore(\ResourceAccessSemaphore) ;resourceAccess.P(); // request exclusive access to resource - SignalSemaphore(\ServiceQueueSemaphore) ;serviceQueue.V(); // let next in line be serviced - EndWith - ; If cache size exceeds limit, try to delete the oldest tiles used (first in the time stack) - Protected CacheSize = MapSize(PBMap\MemCache\Images()) * Pow(PBMap\TileSize, 2) * 4 ; Size of a tile = TileSize * TileSize * 4 bytes (RGBA) - Protected CacheLimit = PBMap\Options\MaxMemCache * 1024 - MyDebug("Cache size : " + Str(CacheSize/1024) + " / CacheLimit : " + Str(CacheLimit/1024), 5) - If CacheSize > CacheLimit - ;PBMap\MemoryCacheManagement = #True - MyDebug(" Cache full. Trying cache cleaning", 5) - ResetList(PBMap\MemCache\ImagesTimeStack()) - ; Try to free half the cache memory (one pass) - While NextElement(PBMap\MemCache\ImagesTimeStack()) And CacheSize > (CacheLimit / 2) ; /2 = half - Protected CacheMapKey.s = PBMap\MemCache\ImagesTimeStack()\MapKey - ;Protected Image = PBMap\MemCache\Images(CacheMapKey)\nImage - ; Is the loading over - If PBMap\MemCache\Images(CacheMapKey)\Tile = -1 - MyDebug(" Delete " + CacheMapKey, 5) - If PBMap\MemCache\Images(CacheMapKey)\nImage;IsImage(PBMap\MemCache\Images(CacheMapKey)\nImage) - FreeImage(PBMap\MemCache\Images(CacheMapKey)\nImage) - MyDebug(" and free image nb " + Str(PBMap\MemCache\Images(CacheMapKey)\nImage), 5) - PBMap\MemCache\Images(CacheMapKey)\nImage = 0 - EndIf - DeleteMapElement(PBMap\MemCache\Images(), CacheMapKey) - DeleteElement(PBMap\MemCache\ImagesTimeStack(), 1) - ElseIf PBMap\MemCache\Images(CacheMapKey)\Tile = 0 - MyDebug(" Delete " + CacheMapKey, 5) - DeleteMapElement(PBMap\MemCache\Images(), CacheMapKey) - DeleteElement(PBMap\MemCache\ImagesTimeStack(), 1) - ElseIf PBMap\MemCache\Images(CacheMapKey)\Tile > 0 - ; If the thread is running, try to abort the download - If PBMap\MemCache\Images(CacheMapKey)\Tile\Download - AbortHTTP(PBMap\MemCache\Images(CacheMapKey)\Tile\Download) + Procedure MemoryCacheManagement() + ; MemoryCache access management + LockMutex(PBMap\MemoryCacheAccessNBMutex) + ; If MemoryCache is not being used by a download thread + If PBMap\MemoryCacheAccessNB = 0 + PBMap\MemoryCacheAccessNB = -1 ; Not really useful as the download thread are now blocked by the mutex, and this procedure is synchronous + UnlockMutex(PBMap\MemoryCacheAccessNBMutex) + ; If cache size exceeds limit, try to delete the oldest tiles used (first in the time stack) + Protected CacheSize = MapSize(PBMap\MemCache\Images()) * Pow(PBMap\TileSize, 2) * 4 ; Size of a tile = TileSize * TileSize * 4 bytes (RGBA) + Protected CacheLimit = PBMap\Options\MaxMemCache * 1024 + MyDebug("Cache size : " + Str(CacheSize/1024) + " / CacheLimit : " + Str(CacheLimit/1024), 5) + If CacheSize > CacheLimit + MyDebug(" Cache full. Trying cache cleaning", 5) + ResetList(PBMap\MemCache\ImagesTimeStack()) + ; Try to free half the cache memory (one pass) + While NextElement(PBMap\MemCache\ImagesTimeStack()) And CacheSize > (CacheLimit / 2) ; /2 = half + Protected CacheMapKey.s = PBMap\MemCache\ImagesTimeStack()\MapKey + ;Protected Image = PBMap\MemCache\Images(CacheMapKey)\nImage + ; Is the loading over + If PBMap\MemCache\Images(CacheMapKey)\Tile = -1 + MyDebug(" Delete " + CacheMapKey, 5) + If PBMap\MemCache\Images(CacheMapKey)\nImage;IsImage(PBMap\MemCache\Images(CacheMapKey)\nImage) + FreeImage(PBMap\MemCache\Images(CacheMapKey)\nImage) + MyDebug(" and free image nb " + Str(PBMap\MemCache\Images(CacheMapKey)\nImage), 5) + PBMap\MemCache\Images(CacheMapKey)\nImage = 0 + EndIf + DeleteMapElement(PBMap\MemCache\Images(), CacheMapKey) + DeleteElement(PBMap\MemCache\ImagesTimeStack(), 1) + ElseIf PBMap\MemCache\Images(CacheMapKey)\Tile = 0 + MyDebug(" Delete " + CacheMapKey, 5) + DeleteMapElement(PBMap\MemCache\Images(), CacheMapKey) + DeleteElement(PBMap\MemCache\ImagesTimeStack(), 1) + ElseIf PBMap\MemCache\Images(CacheMapKey)\Tile > 0 + ; If the thread is running, try to abort the download + If PBMap\MemCache\Images(CacheMapKey)\Tile\Download + AbortHTTP(PBMap\MemCache\Images(CacheMapKey)\Tile\Download) + EndIf EndIf + CacheSize = MapSize(PBMap\MemCache\Images()) * Pow(PBMap\TileSize, 2) * 4 ; Size of a tile = TileSize * TileSize * 4 bytes (RGBA) + Wend + MyDebug(" New cache size : " + Str(CacheSize/1024) + " / CacheLimit : " + Str(CacheLimit/1024), 5) + If CacheSize > CacheLimit + MyDebug(" Cache cleaning unsuccessfull, can't add new tiles.", 5) EndIf - CacheSize = MapSize(PBMap\MemCache\Images()) * Pow(PBMap\TileSize, 2) * 4 ; Size of a tile = TileSize * TileSize * 4 bytes (RGBA) - Wend - ;PBMap\MemoryCacheManagement = #False - MyDebug(" New cache size : " + Str(CacheSize/1024) + " / CacheLimit : " + Str(CacheLimit/1024), 5) - If CacheSize > CacheLimit - MyDebug(" Cache cleaning unsuccessfull, can't add new tiles.", 5) EndIf + ; We're no more accessing MemoryCache + LockMutex(PBMap\MemoryCacheAccessNBMutex) + PBMap\MemoryCacheAccessNB = 0 ; Not really useful as the download thread are now blocked EndIf - SignalSemaphore(PBMap\ResourceAccessSemaphore) ; resourceAccess.V(); // release resource access for next reader/writer + UnlockMutex(PBMap\MemoryCacheAccessNBMutex) EndProcedure - + Procedure.i GetTileFromHDD(CacheFile.s) Protected nImage.i, LifeTime.i, MaxLifeTime.i MaxLifeTime.i = PBMap\Options\TileLifetime If FileSize(CacheFile) > 0 ; <> -1 - ; Manage tile file lifetime + ; Manage tile file lifetime If MaxLifeTime <> -1 LifeTime = Date() - GetFileDate(CacheFile, #PB_Date_Modified) ; There's a bug with #PB_Date_Created If LifeTime > MaxLifeTime @@ -1156,23 +1162,13 @@ Module PBMap ; EndIf ; **** - ;-*** These are threaded + ;-*** These are threaded - Threaded Progress = 0, Size = 0, Quit.i = #False + Threaded Progress = 0, Size = 0, Quit = #False Procedure GetImageThread(*Tile.Tile) - With PBMap - WaitSemaphore(\ServiceQueueSemaphore) ;serviceQueue.P(); // wait in line to be serviced - WaitSemaphore(\ReadCountAccessSemaphore) ;readCountAccess.P(); // request exclusive access to readCount - If \ReadCount = 0 ;If (readCount == 0) // If there are no readers already reading: - WaitSemaphore(\ResourceAccessSemaphore) ; resourceAccess.P(); // request resource access for readers (writers blocked) - EndIf - \ReadCount + 1 ;readCount++; // update count of active readers - SignalSemaphore(\ServiceQueueSemaphore) ;serviceQueue.V(); // let next in line be serviced - SignalSemaphore(\ReadCountAccessSemaphore) ;readCountAccess.V(); // release access to readCount - EndWith MyDebug("Thread starting for image " + *Tile\CacheFile + "(" + *Tile\key + ")", 5) - ; Waits for a free download slot + ;*** Waits for a free download slot LockMutex(PBMap\DownloadSlotsMutex) While PBMap\DownloadSlots >= PBMap\Options\MaxDownloadSlots UnlockMutex(PBMap\DownloadSlotsMutex) @@ -1183,11 +1179,23 @@ Module PBMap ProcedureReturn #False EndIf MyDebug(" Thread for image " + *Tile\CacheFile + " waiting a download slot", 5) - Delay(500) + Delay(20) LockMutex(PBMap\DownloadSlotsMutex) Wend PBMap\DownloadSlots + 1 UnlockMutex(PBMap\DownloadSlotsMutex) + ;*** + ; MemoryCache access management + LockMutex(PBMap\MemoryCacheAccessNBMutex) + ; If MemoryCache is currently being cleaned, wait + While PBMap\MemoryCacheAccessNB = -1 + UnlockMutex(PBMap\MemoryCacheAccessNBMutex) + Delay(20) + LockMutex(PBMap\MemoryCacheAccessNBMutex) + Wend + ; We're accessing MemoryCache + PBMap\MemoryCacheAccessNB + 1 + UnlockMutex(PBMap\MemoryCacheAccessNBMutex) *Tile\Download = ReceiveHTTPFile(*Tile\URL, *Tile\CacheFile, #PB_HTTP_Asynchronous) If *Tile\Download Repeat @@ -1215,27 +1223,23 @@ Module PBMap AbortHTTP(*Tile\Download) EndIf EndSelect - ;EndIf - Delay(500) ; Frees CPU + Delay(200) ; Frees CPU Until Quit - LockMutex(PBMap\DownloadSlotsMutex) - PBMap\DownloadSlots - 1 - UnlockMutex(PBMap\DownloadSlotsMutex) - PostEvent(#PB_Event_Gadget, PBMap\Window, PBmap\Gadget, #PB_MAP_TILE_CLEANUP, *Tile) ; To free memory outside the thread EndIf - With PBMap - WaitSemaphore(\ReadCountAccessSemaphore) ;readCountAccess.P(); // request exclusive access to readCount - \ReadCount - 1 ;readCount--; // update count of active readers - If \ReadCount = 0 ;If (readCount == 0) // If there are no readers left: - SignalSemaphore(\ResourceAccessSemaphore) ; resourceAccess.V(); // release resource access for all - EndIf - SignalSemaphore(\ReadCountAccessSemaphore) ;readCountAccess.V(); - EndWith + ; End of the memory cache access + LockMutex(PBMap\MemoryCacheAccessNBMutex) + PBMap\MemoryCacheAccessNB - 1 + UnlockMutex(PBMap\MemoryCacheAccessNBMutex) + ; Frees a download slot + LockMutex(PBMap\DownloadSlotsMutex) + PBMap\DownloadSlots - 1 + UnlockMutex(PBMap\DownloadSlotsMutex) + PostEvent(#PB_Event_Gadget, PBMap\Window, PBmap\Gadget, #PB_MAP_TILE_CLEANUP, *Tile) ; To free memory outside the thread EndProcedure ;-*** - Procedure.i GetTile(key.s, URL.s, CacheFile.s) + Procedure.i GetTile(key.s, URL.s, CacheFile.s) ; Try to find the tile in memory cache Protected *timg.ImgMemCach = FindMapElement(PBMap\MemCache\Images(), key) If *timg @@ -2478,24 +2482,19 @@ Module PBMap PBMap\Redraw = #True Case #PB_MAP_RETRY PBMap\Redraw = #True - ;- Tile cleanup + ;- Tile web loading thread cleanup + ; After a Web tile loading thread, clean the tile structure memory, see GetImageThread() Case #PB_MAP_TILE_CLEANUP *Tile = EventData() - key = *Tile\key - ; After a Web tile loading thread, clean the tile structure memory, see GetImageThread() + key = *Tile\key *Tile\Download = 0 - ;Debug key + " cleanup event" - If *Tile\Size ; <> 0 - FreeMemory(PBMap\MemCache\Images(key)\Tile) ; Frees the data needed for the thread + FreeMemory(*Tile) ; Frees the data needed for the thread (*tile=PBMap\MemCache\Images(key)\Tile) PBMap\MemCache\Images(key)\Tile = -1 ; Clears the data ptr, and says that the web loading thread has finished successfully Else - FreeMemory(PBMap\MemCache\Images(key)\Tile) ; Frees the data needed for the thread + FreeMemory(*Tile) ; Frees the data needed for the thread (*tile=PBMap\MemCache\Images(key)\Tile) PBMap\MemCache\Images(key)\Tile = 0 ; Clears the data ptr, and says that the web loading thread has finished unsuccessfully EndIf - ;Debug "=" + Str(PBMap\MemCache\Images(key)\Tile) - ;Protected timg = PBMap\MemCache\Images(key)\Tile\nImage ; Get this new tile image nb - ;PBMap\MemCache\Images(key)\nImage = timg ; Stores it in the cache using the key PBMap\ThreadsNB - 1 PBMap\Redraw = #True EndSelect @@ -2504,8 +2503,8 @@ Module PBMap ; Redraws at regular intervals Procedure TimerEvents() If EventTimer() = PBMap\Timer And (PBMap\Redraw Or PBMap\Dirty) + MemoryCacheManagement() Drawing() - PBMap\MemoryCacheManagementThread = CreateThread(@MemoryCacheManagement(), Null) EndIf EndProcedure @@ -2532,12 +2531,11 @@ Module PBMap Procedure Quit() PBMap\Drawing\End = #True - ;PBMap\MemoryCacheManagement = #True ; Tells web loading threads to pause ; Wait for loading threads to finish nicely. Passed 2 seconds, kills them. Protected TimeCounter = ElapsedMilliseconds() Repeat ForEach PBMap\MemCache\Images() - If PBMap\MemCache\Images()\Tile > 0 + If PBMap\MemCache\Images()\Tile > 0 If IsThread(PBMap\MemCache\Images()\Tile\GetImageThread) If ElapsedMilliseconds() - TimeCounter > 2000 ; Should not occur @@ -2556,25 +2554,30 @@ Module PBMap EndProcedure Procedure InitPBMap(Window) - Protected Result.i - PBMap\ZoomMin = 1 - PBMap\ZoomMax = 18 - PBMap\Dragging = #False - PBMap\TileSize = 256 - PBMap\Dirty = #False - PBMap\EditMarker = #False - PBMap\Font = LoadFont(#PB_Any, "Arial", 20, #PB_Font_Bold) - PBMap\Window = Window - PBMap\Timer = 1 - PBMap\Mode = #MODE_DEFAULT - PBMap\DownloadSlotsMutex = CreateMutex() - PBMap\ResourceAccessSemaphore = CreateSemaphore(1) - PBMap\ReadCountAccessSemaphore = CreateSemaphore(1) - PBMap\ServiceQueueSemaphore = CreateSemaphore(1) - If PBMap\DownloadSlotsMutex = #False - MyDebug("Cannot create a mutex", 0) - End - EndIf + With PBMap + Protected Result.i + \ZoomMin = 1 + \ZoomMax = 18 + \Dragging = #False + \TileSize = 256 + \Dirty = #False + \EditMarker = #False + \Font = LoadFont(#PB_Any, "Arial", 20, #PB_Font_Bold) + \Window = Window + \Timer = 1 + \Mode = #MODE_DEFAULT + \DownloadSlotsMutex = CreateMutex() + If \DownloadSlotsMutex = #False + MyDebug("Cannot create a mutex", 0) + End + EndIf + \MemoryCacheAccessNB = 0 + \MemoryCacheAccessNBMutex = CreateMutex() + If \MemoryCacheAccessNBMutex = #False + MyDebug("Cannot create a mutex", 0) + End + EndIf + EndWith LoadOptions() TechnicalImagesCreation() SetLocation(0, 0) @@ -2747,7 +2750,8 @@ CompilerIf #PB_Compiler_IsMainFile PBMap::InitPBMap(#Window_0) PBMap::SetOption("ShowDegrees", "1") : Degrees = 0 PBMap::SetOption("ShowDebugInfos", "1") - PBMap::SetOption("Verbose", "1") + PBMap::SetDebugLevel(4) + PBMap::SetOption("Verbose", "0") PBMap::SetOption("ShowScale", "1") PBMap::SetOption("Warning", "1") PBMap::SetOption("ShowMarkersLegend", "1") @@ -2890,8 +2894,8 @@ CompilerIf #PB_Compiler_IsMainFile CompilerEndIf ; IDE Options = PureBasic 5.60 (Windows - x64) -; CursorPosition = 1231 -; FirstLine = 1151 +; CursorPosition = 2751 +; FirstLine = 2738 ; Folding = ------------------- ; EnableThread ; EnableXP From b11176a46fa06432c15c6f97b678c5ea79fd4e9a Mon Sep 17 00:00:00 2001 From: djes Date: Wed, 14 Jun 2017 10:58:48 +0200 Subject: [PATCH 12/16] Ensures that there's no loading threads while cleaning Should be changed, as the feeling is less good, memory consumption could get huge, and unuseful threads may continue instead of being stopped. --- PBMap.pb | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/PBMap.pb b/PBMap.pb index e81b9f5..ddbfd0f 100644 --- a/PBMap.pb +++ b/PBMap.pb @@ -1059,7 +1059,7 @@ Module PBMap ; If MemoryCache is not being used by a download thread If PBMap\MemoryCacheAccessNB = 0 PBMap\MemoryCacheAccessNB = -1 ; Not really useful as the download thread are now blocked by the mutex, and this procedure is synchronous - UnlockMutex(PBMap\MemoryCacheAccessNBMutex) + ;UnlockMutex(PBMap\MemoryCacheAccessNBMutex) ; If cache size exceeds limit, try to delete the oldest tiles used (first in the time stack) Protected CacheSize = MapSize(PBMap\MemCache\Images()) * Pow(PBMap\TileSize, 2) * 4 ; Size of a tile = TileSize * TileSize * 4 bytes (RGBA) Protected CacheLimit = PBMap\Options\MaxMemCache * 1024 @@ -1099,7 +1099,7 @@ Module PBMap EndIf EndIf ; We're no more accessing MemoryCache - LockMutex(PBMap\MemoryCacheAccessNBMutex) + ;LockMutex(PBMap\MemoryCacheAccessNBMutex) PBMap\MemoryCacheAccessNB = 0 ; Not really useful as the download thread are now blocked EndIf UnlockMutex(PBMap\MemoryCacheAccessNBMutex) @@ -1287,7 +1287,7 @@ Module PBMap *timg\nImage = GetTileFromHDD(CacheFile.s) If *timg\nImage ; Image found and loaded from HDD - *timg\Alpha = 256 + *timg\Alpha = 0 *timg\Tile = -1 ProcedureReturn *timg EndIf @@ -2894,8 +2894,8 @@ CompilerIf #PB_Compiler_IsMainFile CompilerEndIf ; IDE Options = PureBasic 5.60 (Windows - x64) -; CursorPosition = 2751 -; FirstLine = 2738 +; CursorPosition = 2510 +; FirstLine = 2503 ; Folding = ------------------- ; EnableThread ; EnableXP From 55bbe10378d0a223310662422641cb78e5c8e037 Mon Sep 17 00:00:00 2001 From: djes Date: Thu, 15 Jun 2017 12:24:23 +0200 Subject: [PATCH 13/16] Better thread/download management --- PBMap.pb | 159 +++++++++++++++++++++++++++++++------------------------ 1 file changed, 89 insertions(+), 70 deletions(-) diff --git a/PBMap.pb b/PBMap.pb index ddbfd0f..8a2805b 100644 --- a/PBMap.pb +++ b/PBMap.pb @@ -128,6 +128,7 @@ Module PBMap Download.i Time.i Size.i + Mutex.i EndStructure Structure BoundingBox @@ -155,6 +156,7 @@ Module PBMap Structure ImgMemCach nImage.i + Size.i *Tile.Tile *TimeStackPtr Alpha.i @@ -298,7 +300,6 @@ Module PBMap DownloadSlots.i ; Actual nb of used download slots DownloadSlotsMutex.i ; To be sure that only one thread at a time can access to the DownloadSlots var - List TracksList.Tracks() ; To display a GPX track List Markers.Marker() ; To diplay marker EditMarker.l @@ -1056,7 +1057,7 @@ Module PBMap Procedure MemoryCacheManagement() ; MemoryCache access management LockMutex(PBMap\MemoryCacheAccessNBMutex) - ; If MemoryCache is not being used by a download thread + ; If MemoryCache is not being used by any download thread If PBMap\MemoryCacheAccessNB = 0 PBMap\MemoryCacheAccessNB = -1 ; Not really useful as the download thread are now blocked by the mutex, and this procedure is synchronous ;UnlockMutex(PBMap\MemoryCacheAccessNBMutex) @@ -1109,7 +1110,7 @@ Module PBMap Protected nImage.i, LifeTime.i, MaxLifeTime.i MaxLifeTime.i = PBMap\Options\TileLifetime If FileSize(CacheFile) > 0 ; <> -1 - ; Manage tile file lifetime + ; Manage tile file lifetime If MaxLifeTime <> -1 LifeTime = Date() - GetFileDate(CacheFile, #PB_Date_Modified) ; There's a bug with #PB_Date_Created If LifeTime > MaxLifeTime @@ -1164,62 +1165,74 @@ Module PBMap ;-*** These are threaded - Threaded Progress = 0, Size = 0, Quit = #False + Threaded Progress = 0, Quit = #False Procedure GetImageThread(*Tile.Tile) - MyDebug("Thread starting for image " + *Tile\CacheFile + "(" + *Tile\key + ")", 5) - ;*** Waits for a free download slot + MyDebug("Thread nb " + Str(*Tile\GetImageThread) + " " + *Tile\key + " starting for image " + *Tile\CacheFile, 5) LockMutex(PBMap\DownloadSlotsMutex) - While PBMap\DownloadSlots >= PBMap\Options\MaxDownloadSlots + ; Is there's no free download slot, abort + If PBMap\DownloadSlots >= PBMap\Options\MaxDownloadSlots + MyDebug(" Thread nb " + Str(*Tile\GetImageThread) + " " + *Tile\key + " for image " + *Tile\CacheFile + " canceled because no free download slot.", 5) + *Tile\Size = 0 ; \Size = 0 signals that the download has failed UnlockMutex(PBMap\DownloadSlotsMutex) - If ElapsedMilliseconds() - *Tile\Time > 10000 - *Tile\Size = 0 ; \Size = 0 signals that the download has failed - MyDebug(" Thread for image " + *Tile\CacheFile + " canceled after 10 seconds waiting for a slot.", 5) - PostEvent(#PB_Event_Gadget, PBMap\Window, PBmap\Gadget, #PB_MAP_TILE_CLEANUP, *Tile) ; To free memory outside the thread - ProcedureReturn #False - EndIf - MyDebug(" Thread for image " + *Tile\CacheFile + " waiting a download slot", 5) - Delay(20) - LockMutex(PBMap\DownloadSlotsMutex) - Wend + PostEvent(#PB_Event_Gadget, PBMap\Window, PBmap\Gadget, #PB_MAP_TILE_CLEANUP, *Tile) ; To free memory outside the thread + ProcedureReturn + EndIf PBMap\DownloadSlots + 1 UnlockMutex(PBMap\DownloadSlotsMutex) - ;*** + ; *** Waits for a free download slot + ; LockMutex(PBMap\DownloadSlotsMutex) + ; While PBMap\DownloadSlots >= PBMap\Options\MaxDownloadSlots + ; UnlockMutex(PBMap\DownloadSlotsMutex) + ; If ElapsedMilliseconds() - *Tile\Time > 10000 + ; *Tile\Size = 0 ; \Size = 0 signals that the download has failed + ; MyDebug(" Thread for image " + *Tile\CacheFile + " canceled after 10 seconds waiting for a slot.", 5) + ; PostEvent(#PB_Event_Gadget, PBMap\Window, PBmap\Gadget, #PB_MAP_TILE_CLEANUP, *Tile) ; To free memory outside the thread + ; ProcedureReturn #False + ; EndIf + ; MyDebug(" Thread for image " + *Tile\CacheFile + " waiting a download slot", 5) + ; Delay(20) + ; LockMutex(PBMap\DownloadSlotsMutex) + ; Wend + ; PBMap\DownloadSlots + 1 + ; UnlockMutex(PBMap\DownloadSlotsMutex) + ; *** ; MemoryCache access management LockMutex(PBMap\MemoryCacheAccessNBMutex) - ; If MemoryCache is currently being cleaned, wait - While PBMap\MemoryCacheAccessNB = -1 + ; If MemoryCache is currently being cleaned, abort + If PBMap\MemoryCacheAccessNB = -1 + MyDebug(" Thread nb " + Str(*Tile\GetImageThread) + " " + *Tile\key + " for image " + *Tile\CacheFile + " canceled because of cleaning.", 5) + *Tile\Size = 0 ; \Size = 0 signals that the download has failed UnlockMutex(PBMap\MemoryCacheAccessNBMutex) - Delay(20) - LockMutex(PBMap\MemoryCacheAccessNBMutex) - Wend + PostEvent(#PB_Event_Gadget, PBMap\Window, PBmap\Gadget, #PB_MAP_TILE_CLEANUP, *Tile) ; To free memory outside the thread + ProcedureReturn + EndIf ; We're accessing MemoryCache PBMap\MemoryCacheAccessNB + 1 UnlockMutex(PBMap\MemoryCacheAccessNBMutex) *Tile\Download = ReceiveHTTPFile(*Tile\URL, *Tile\CacheFile, #PB_HTTP_Asynchronous) If *Tile\Download Repeat - ;If PBMap\MemoryCacheManagement = #False ; Wait until cache cleaning is done ;TODO Progress = HTTPProgress(*Tile\Download) Select Progress Case #PB_Http_Success *Tile\Size = FinishHTTP(*Tile\Download) ; \Size signals that the download is OK - MyDebug(" Thread for image " + *Tile\CacheFile + " finished. Size : " + Str(Size), 5) + MyDebug(" Thread nb " + Str(*Tile\GetImageThread) + " " + *Tile\key + " for image " + *Tile\CacheFile + " finished. Size : " + Str(*Tile\Size), 5) Quit = #True Case #PB_Http_Failed FinishHTTP(*Tile\Download) *Tile\Size = 0 ; \Size = 0 signals that the download has failed - MyDebug(" Thread for image " + *Tile\CacheFile + " failed.", 5) + MyDebug(" Thread nb " + Str(*Tile\GetImageThread) + " " + *Tile\key + " for image " + *Tile\CacheFile + " failed.", 5) Quit = #True Case #PB_Http_Aborted FinishHTTP(*Tile\Download) *Tile\Size = 0 ; \Size = 0 signals that the download has failed - MyDebug(" Thread for image " + *Tile\CacheFile + " aborted.", 5) + MyDebug(" Thread nb " + Str(*Tile\GetImageThread) + " " + *Tile\key + " for image " + *Tile\CacheFile + " aborted.", 5) Quit = #True Default - MyDebug(" Thread for image " + *Tile\CacheFile + " downloading " + Str(Progress) + " bytes", 5) + MyDebug(" Thread nb " + Str(*Tile\GetImageThread) + " " + *Tile\key + " for image " + *Tile\CacheFile + " downloading " + Str(Progress) + " bytes", 5) If ElapsedMilliseconds() - *Tile\Time > 10000 - MyDebug(" Thread for image " + *Tile\CacheFile + " canceled after 10 seconds.", 5) + MyDebug(" Thread nb " + Str(*Tile\GetImageThread) + " " + *Tile\key + " for image " + *Tile\CacheFile + " canceled after 10 seconds.", 5) AbortHTTP(*Tile\Download) EndIf EndSelect @@ -1240,6 +1253,8 @@ Module PBMap ;-*** Procedure.i GetTile(key.s, URL.s, CacheFile.s) + ; MemoryCache access management + LockMutex(PBMap\MemoryCacheAccessNBMutex) ; Try to find the tile in memory cache Protected *timg.ImgMemCach = FindMapElement(PBMap\MemCache\Images(), key) If *timg @@ -1248,16 +1263,16 @@ Module PBMap If *timg\nImage ; Yes, returns the image's nb MyDebug(" as image " + *timg\nImage, 4) - *timg\Tile = -1 ; *** Cache management ; Retrieves the image in the time stack, push it to the end (to say it's the lastly used) ChangeCurrentElement(PBMap\MemCache\ImagesTimeStack(), *timg\TimeStackPtr) MoveElement(PBMap\MemCache\ImagesTimeStack(), #PB_List_Last) ; *timg\TimeStackPtr = LastElement(PBMap\MemCache\ImagesTimeStack()) ; *** + UnlockMutex(PBMap\MemoryCacheAccessNBMutex) ProcedureReturn *timg Else - ; No, will load it below + ; No, try to load it from HD (see below) MyDebug(" but not the image.", 4) EndIf Else @@ -1265,6 +1280,7 @@ Module PBMap *timg = AddMapElement(PBMap\MemCache\Images(), key) If *timg = 0 MyDebug(" Can't add a new cache element.", 4) + UnlockMutex(PBMap\MemoryCacheAccessNBMutex) ProcedureReturn #False EndIf ; add a new time stack element at the End @@ -1274,55 +1290,56 @@ Module PBMap If *timg\TimeStackPtr = 0 MyDebug(" Can't add a new time stack element.", 4) DeleteMapElement(PBMap\MemCache\Images()) + UnlockMutex(PBMap\MemoryCacheAccessNBMutex) ProcedureReturn #False EndIf ; Associates the time stack element to the cache element PBMap\MemCache\ImagesTimeStack()\MapKey = MapKey(PBMap\MemCache\Images()) MyDebug("Key : " + key + " added in memory cache", 4) - ; *** EndIf - ; Is this tile not loading ? + ; If there's no active download thread for this tile If *timg\Tile <= 0 - ; Is the file image on HDD ? + ; Try To load it from HD *timg\nImage = GetTileFromHDD(CacheFile.s) If *timg\nImage ; Image found and loaded from HDD *timg\Alpha = 0 - *timg\Tile = -1 + UnlockMutex(PBMap\MemoryCacheAccessNBMutex) ProcedureReturn *timg EndIf - EndIf - ; If there's not this tile in memory and no web loading thread - If *timg\Tile = 0 - ; Launch a new one - If PBMap\ThreadsNB < PBMap\Options\MaxThreads - Protected *NewTile.Tile = AllocateMemory(SizeOf(Tile)) - If *NewTile - With *NewTile - ; New tile parameters - \key = key - \URL = URL - \CacheFile = CacheFile - \nImage = 0 - \Time = ElapsedMilliseconds() - \GetImageThread = CreateThread(@GetImageThread(), *NewTile) - If \GetImageThread - *timg\Tile = *NewTile ; There's now a loading thread - *timg\Alpha = 0 - MyDebug(" Creating get image thread nb " + Str(\GetImageThread) + " to get " + CacheFile, 3) - PBMap\ThreadsNB + 1 - Else - MyDebug(" Can't create get image thread to get " + CacheFile, 3) - FreeMemory(*NewTile) - EndIf - EndWith - Else - MyDebug(" Error, can't allocate memory for a new tile loading thread", 3) + ; If GetTileFromHDD failed, will load it (again?) from the web (see below) + If *timg\nImage = 0 + ; Launch a new web loading thread + If PBMap\ThreadsNB < PBMap\Options\MaxThreads + Protected *NewTile.Tile = AllocateMemory(SizeOf(Tile)) + If *NewTile + With *NewTile + ; New tile parameters + \key = key + \URL = URL + \CacheFile = CacheFile + \nImage = 0 + \Time = ElapsedMilliseconds() + \GetImageThread = CreateThread(@GetImageThread(), *NewTile) + If \GetImageThread + *timg\Tile = *NewTile ; There's now a loading thread + *timg\Alpha = 0 + MyDebug(" Creating get image thread nb " + Str(\GetImageThread) + " to get " + CacheFile + " (key = " + key, 3) + PBMap\ThreadsNB + 1 + Else + MyDebug(" Can't create get image thread to get " + CacheFile, 3) + FreeMemory(*NewTile) + EndIf + EndWith + Else + MyDebug(" Error, can't allocate memory for a new tile loading thread", 3) + EndIf + Else + MyDebug(" Error, maximum threads nb reached", 3) EndIf - Else - MyDebug(" Error, maximum threads nb reached", 3) EndIf EndIf + UnlockMutex(PBMap\MemoryCacheAccessNBMutex) ProcedureReturn #False EndProcedure @@ -2488,12 +2505,14 @@ Module PBMap *Tile = EventData() key = *Tile\key *Tile\Download = 0 + PBMap\MemCache\Images(key)\Tile = *Tile\Size If *Tile\Size ; <> 0 + ; Web loading thread has finished successfully FreeMemory(*Tile) ; Frees the data needed for the thread (*tile=PBMap\MemCache\Images(key)\Tile) - PBMap\MemCache\Images(key)\Tile = -1 ; Clears the data ptr, and says that the web loading thread has finished successfully + PBMap\MemCache\Images(key)\Tile = -1 Else FreeMemory(*Tile) ; Frees the data needed for the thread (*tile=PBMap\MemCache\Images(key)\Tile) - PBMap\MemCache\Images(key)\Tile = 0 ; Clears the data ptr, and says that the web loading thread has finished unsuccessfully + PBMap\MemCache\Images(key)\Tile = 0 EndIf PBMap\ThreadsNB - 1 PBMap\Redraw = #True @@ -2750,8 +2769,8 @@ CompilerIf #PB_Compiler_IsMainFile PBMap::InitPBMap(#Window_0) PBMap::SetOption("ShowDegrees", "1") : Degrees = 0 PBMap::SetOption("ShowDebugInfos", "1") - PBMap::SetDebugLevel(4) - PBMap::SetOption("Verbose", "0") + PBMap::SetDebugLevel(5) + PBMap::SetOption("Verbose", "1") PBMap::SetOption("ShowScale", "1") PBMap::SetOption("Warning", "1") PBMap::SetOption("ShowMarkersLegend", "1") @@ -2894,8 +2913,8 @@ CompilerIf #PB_Compiler_IsMainFile CompilerEndIf ; IDE Options = PureBasic 5.60 (Windows - x64) -; CursorPosition = 2510 -; FirstLine = 2503 +; CursorPosition = 1181 +; FirstLine = 1156 ; Folding = ------------------- ; EnableThread ; EnableXP From e67076802b85db1e71da9ba4375a0b027122c8a1 Mon Sep 17 00:00:00 2001 From: djes Date: Thu, 15 Jun 2017 15:15:02 +0200 Subject: [PATCH 14/16] Latest strange image drawing bugs killed --- PBMap.pb | 254 +++++++++++++++++++++++-------------------------------- 1 file changed, 105 insertions(+), 149 deletions(-) diff --git a/PBMap.pb b/PBMap.pb index 8a2805b..b90bf51 100644 --- a/PBMap.pb +++ b/PBMap.pb @@ -298,7 +298,6 @@ Module PBMap MemoryCacheAccessNB.i ; Count the access to the memory cache. =0 no access ; >0 download threads ; -1 cleaning MemoryCacheAccessNBMutex.i ; Memorycache access variable mutual exclusion DownloadSlots.i ; Actual nb of used download slots - DownloadSlotsMutex.i ; To be sure that only one thread at a time can access to the DownloadSlots var List TracksList.Tracks() ; To display a GPX track List Markers.Marker() ; To diplay marker @@ -1053,72 +1052,50 @@ Module PBMap EndProcedure ;-*** - + ; If cache size exceeds limit, try to delete the oldest tiles used (first in the time stack) Procedure MemoryCacheManagement() - ; MemoryCache access management - LockMutex(PBMap\MemoryCacheAccessNBMutex) - ; If MemoryCache is not being used by any download thread - If PBMap\MemoryCacheAccessNB = 0 - PBMap\MemoryCacheAccessNB = -1 ; Not really useful as the download thread are now blocked by the mutex, and this procedure is synchronous - ;UnlockMutex(PBMap\MemoryCacheAccessNBMutex) - ; If cache size exceeds limit, try to delete the oldest tiles used (first in the time stack) - Protected CacheSize = MapSize(PBMap\MemCache\Images()) * Pow(PBMap\TileSize, 2) * 4 ; Size of a tile = TileSize * TileSize * 4 bytes (RGBA) - Protected CacheLimit = PBMap\Options\MaxMemCache * 1024 - MyDebug("Cache size : " + Str(CacheSize/1024) + " / CacheLimit : " + Str(CacheLimit/1024), 5) - If CacheSize > CacheLimit - MyDebug(" Cache full. Trying cache cleaning", 5) - ResetList(PBMap\MemCache\ImagesTimeStack()) - ; Try to free half the cache memory (one pass) - While NextElement(PBMap\MemCache\ImagesTimeStack()) And CacheSize > (CacheLimit / 2) ; /2 = half - Protected CacheMapKey.s = PBMap\MemCache\ImagesTimeStack()\MapKey - ;Protected Image = PBMap\MemCache\Images(CacheMapKey)\nImage - ; Is the loading over - If PBMap\MemCache\Images(CacheMapKey)\Tile = -1 - MyDebug(" Delete " + CacheMapKey, 5) - If PBMap\MemCache\Images(CacheMapKey)\nImage;IsImage(PBMap\MemCache\Images(CacheMapKey)\nImage) - FreeImage(PBMap\MemCache\Images(CacheMapKey)\nImage) - MyDebug(" and free image nb " + Str(PBMap\MemCache\Images(CacheMapKey)\nImage), 5) - PBMap\MemCache\Images(CacheMapKey)\nImage = 0 - EndIf - DeleteMapElement(PBMap\MemCache\Images(), CacheMapKey) - DeleteElement(PBMap\MemCache\ImagesTimeStack(), 1) - ElseIf PBMap\MemCache\Images(CacheMapKey)\Tile = 0 - MyDebug(" Delete " + CacheMapKey, 5) - DeleteMapElement(PBMap\MemCache\Images(), CacheMapKey) - DeleteElement(PBMap\MemCache\ImagesTimeStack(), 1) - ElseIf PBMap\MemCache\Images(CacheMapKey)\Tile > 0 - ; If the thread is running, try to abort the download - If PBMap\MemCache\Images(CacheMapKey)\Tile\Download - AbortHTTP(PBMap\MemCache\Images(CacheMapKey)\Tile\Download) - EndIf + LockMutex(PBMap\MemoryCacheAccessNBMutex) ; Prevents thread to start or finish + Protected CacheSize = MapSize(PBMap\MemCache\Images()) * Pow(PBMap\TileSize, 2) * 4 ; Size of a tile = TileSize * TileSize * 4 bytes (RGBA) + Protected CacheLimit = PBMap\Options\MaxMemCache * 1024 + MyDebug("Cache size : " + Str(CacheSize/1024) + " / CacheLimit : " + Str(CacheLimit/1024), 5) + If CacheSize > CacheLimit + MyDebug(" Cache full. Trying cache cleaning", 5) + ResetList(PBMap\MemCache\ImagesTimeStack()) + ; Try to free half the cache memory (one pass) + While NextElement(PBMap\MemCache\ImagesTimeStack()) And CacheSize > (CacheLimit / 2) ; /2 = half + Protected CacheMapKey.s = PBMap\MemCache\ImagesTimeStack()\MapKey + ; Is the loading over + If PBMap\MemCache\Images(CacheMapKey)\Tile <= 0 ;TODO Should not verify this var directly + MyDebug(" Delete " + CacheMapKey, 5) + If PBMap\MemCache\Images(CacheMapKey)\nImage;IsImage(PBMap\MemCache\Images(CacheMapKey)\nImage) + FreeImage(PBMap\MemCache\Images(CacheMapKey)\nImage) + MyDebug(" and free image nb " + Str(PBMap\MemCache\Images(CacheMapKey)\nImage), 5) + PBMap\MemCache\Images(CacheMapKey)\nImage = 0 EndIf - CacheSize = MapSize(PBMap\MemCache\Images()) * Pow(PBMap\TileSize, 2) * 4 ; Size of a tile = TileSize * TileSize * 4 bytes (RGBA) - Wend - MyDebug(" New cache size : " + Str(CacheSize/1024) + " / CacheLimit : " + Str(CacheLimit/1024), 5) - If CacheSize > CacheLimit - MyDebug(" Cache cleaning unsuccessfull, can't add new tiles.", 5) + DeleteMapElement(PBMap\MemCache\Images(), CacheMapKey) + DeleteElement(PBMap\MemCache\ImagesTimeStack(), 1) + ; ElseIf PBMap\MemCache\Images(CacheMapKey)\Tile = 0 + ; MyDebug(" Delete " + CacheMapKey, 5) + ; DeleteMapElement(PBMap\MemCache\Images(), CacheMapKey) + ; DeleteElement(PBMap\MemCache\ImagesTimeStack(), 1) + ; ElseIf PBMap\MemCache\Images(CacheMapKey)\Tile > 0 + ; ; If the thread is running, try to abort the download + ; If PBMap\MemCache\Images(CacheMapKey)\Tile\Download + ; AbortHTTP(PBMap\MemCache\Images(CacheMapKey)\Tile\Download) ; Could lead to error + ; EndIf EndIf + CacheSize = MapSize(PBMap\MemCache\Images()) * Pow(PBMap\TileSize, 2) * 4 ; Size of a tile = TileSize * TileSize * 4 bytes (RGBA) + Wend + MyDebug(" New cache size : " + Str(CacheSize/1024) + " / CacheLimit : " + Str(CacheLimit/1024), 5) + If CacheSize > CacheLimit + MyDebug(" Cache cleaning unsuccessfull, can't add new tiles.", 5) EndIf - ; We're no more accessing MemoryCache - ;LockMutex(PBMap\MemoryCacheAccessNBMutex) - PBMap\MemoryCacheAccessNB = 0 ; Not really useful as the download thread are now blocked EndIf UnlockMutex(PBMap\MemoryCacheAccessNBMutex) EndProcedure Procedure.i GetTileFromHDD(CacheFile.s) Protected nImage.i, LifeTime.i, MaxLifeTime.i - MaxLifeTime.i = PBMap\Options\TileLifetime - If FileSize(CacheFile) > 0 ; <> -1 - ; Manage tile file lifetime - If MaxLifeTime <> -1 - LifeTime = Date() - GetFileDate(CacheFile, #PB_Date_Modified) ; There's a bug with #PB_Date_Created - If LifeTime > MaxLifeTime - MyDebug(" Deleting too old (" + StrU(LifeTime) + " secs) " + CacheFile, 3) - DeleteFile(CacheFile) - ProcedureReturn #False - EndIf - EndIf ; Everything is OK, loads the file nImage = LoadImage(#PB_Any, CacheFile) If nImage @@ -1132,9 +1109,6 @@ Module PBMap MyDebug(" Can't delete faulty image file " + CacheFile, 3) EndIf EndIf - Else - MyDebug(" Failed loading " + CacheFile + " -> Filesize = " + FileSize(CacheFile), 3) - EndIf ProcedureReturn #False EndProcedure @@ -1167,49 +1141,21 @@ Module PBMap Threaded Progress = 0, Quit = #False - Procedure GetImageThread(*Tile.Tile) - MyDebug("Thread nb " + Str(*Tile\GetImageThread) + " " + *Tile\key + " starting for image " + *Tile\CacheFile, 5) - LockMutex(PBMap\DownloadSlotsMutex) - ; Is there's no free download slot, abort - If PBMap\DownloadSlots >= PBMap\Options\MaxDownloadSlots - MyDebug(" Thread nb " + Str(*Tile\GetImageThread) + " " + *Tile\key + " for image " + *Tile\CacheFile + " canceled because no free download slot.", 5) - *Tile\Size = 0 ; \Size = 0 signals that the download has failed - UnlockMutex(PBMap\DownloadSlotsMutex) - PostEvent(#PB_Event_Gadget, PBMap\Window, PBmap\Gadget, #PB_MAP_TILE_CLEANUP, *Tile) ; To free memory outside the thread - ProcedureReturn - EndIf - PBMap\DownloadSlots + 1 - UnlockMutex(PBMap\DownloadSlotsMutex) - ; *** Waits for a free download slot - ; LockMutex(PBMap\DownloadSlotsMutex) - ; While PBMap\DownloadSlots >= PBMap\Options\MaxDownloadSlots - ; UnlockMutex(PBMap\DownloadSlotsMutex) - ; If ElapsedMilliseconds() - *Tile\Time > 10000 - ; *Tile\Size = 0 ; \Size = 0 signals that the download has failed - ; MyDebug(" Thread for image " + *Tile\CacheFile + " canceled after 10 seconds waiting for a slot.", 5) - ; PostEvent(#PB_Event_Gadget, PBMap\Window, PBmap\Gadget, #PB_MAP_TILE_CLEANUP, *Tile) ; To free memory outside the thread - ; ProcedureReturn #False - ; EndIf - ; MyDebug(" Thread for image " + *Tile\CacheFile + " waiting a download slot", 5) - ; Delay(20) - ; LockMutex(PBMap\DownloadSlotsMutex) - ; Wend - ; PBMap\DownloadSlots + 1 - ; UnlockMutex(PBMap\DownloadSlotsMutex) - ; *** - ; MemoryCache access management + Procedure GetImageThread(*Tile.Tile) LockMutex(PBMap\MemoryCacheAccessNBMutex) + MyDebug("Thread nb " + Str(*Tile\GetImageThread) + " " + *Tile\key + " starting for image " + *Tile\CacheFile, 5) ; If MemoryCache is currently being cleaned, abort - If PBMap\MemoryCacheAccessNB = -1 - MyDebug(" Thread nb " + Str(*Tile\GetImageThread) + " " + *Tile\key + " for image " + *Tile\CacheFile + " canceled because of cleaning.", 5) - *Tile\Size = 0 ; \Size = 0 signals that the download has failed - UnlockMutex(PBMap\MemoryCacheAccessNBMutex) - PostEvent(#PB_Event_Gadget, PBMap\Window, PBmap\Gadget, #PB_MAP_TILE_CLEANUP, *Tile) ; To free memory outside the thread - ProcedureReturn - EndIf +; If PBMap\MemoryCacheAccessNB = -1 +; MyDebug(" Thread nb " + Str(*Tile\GetImageThread) + " " + *Tile\key + " for image " + *Tile\CacheFile + " canceled because of cleaning.", 5) +; *Tile\Size = 0 ; \Size = 0 signals that the download has failed +; PostEvent(#PB_Event_Gadget, PBMap\Window, PBmap\Gadget, #PB_MAP_TILE_CLEANUP, *Tile) ; To free memory outside the thread +; UnlockMutex(PBMap\MemoryCacheAccessNBMutex) +; ProcedureReturn +; EndIf ; We're accessing MemoryCache PBMap\MemoryCacheAccessNB + 1 UnlockMutex(PBMap\MemoryCacheAccessNBMutex) + *Tile\Size = 0 *Tile\Download = ReceiveHTTPFile(*Tile\URL, *Tile\CacheFile, #PB_HTTP_Asynchronous) If *Tile\Download Repeat @@ -1242,12 +1188,8 @@ Module PBMap ; End of the memory cache access LockMutex(PBMap\MemoryCacheAccessNBMutex) PBMap\MemoryCacheAccessNB - 1 - UnlockMutex(PBMap\MemoryCacheAccessNBMutex) - ; Frees a download slot - LockMutex(PBMap\DownloadSlotsMutex) - PBMap\DownloadSlots - 1 - UnlockMutex(PBMap\DownloadSlotsMutex) PostEvent(#PB_Event_Gadget, PBMap\Window, PBmap\Gadget, #PB_MAP_TILE_CLEANUP, *Tile) ; To free memory outside the thread + UnlockMutex(PBMap\MemoryCacheAccessNBMutex) EndProcedure ;-*** @@ -1298,41 +1240,58 @@ Module PBMap MyDebug("Key : " + key + " added in memory cache", 4) EndIf ; If there's no active download thread for this tile - If *timg\Tile <= 0 - ; Try To load it from HD - *timg\nImage = GetTileFromHDD(CacheFile.s) + If *timg\Tile <= 0 + ; Manage tile file lifetime, delete if too old + If PBMap\Options\TileLifetime <> -1 + If Date() - GetFileDate(CacheFile, #PB_Date_Modified) > PBMap\Options\TileLifetime ; If Lifetime > MaxLifeTime ; There's a bug with #PB_Date_Created + MyDebug(" Deleting too old " + CacheFile, 3) + DeleteFile(CacheFile) + EndIf + EndIf + ; Try To load it from HD + *timg\nImage = 0 + *timg\Size = FileSize(CacheFile) + If *timg\Size > 0 + *timg\nImage = GetTileFromHDD(CacheFile.s) + Else + MyDebug(" Failed loading from HDD " + CacheFile + " -> Filesize = " + FileSize(CacheFile), 3) + EndIf If *timg\nImage ; Image found and loaded from HDD *timg\Alpha = 0 UnlockMutex(PBMap\MemoryCacheAccessNBMutex) ProcedureReturn *timg - EndIf - ; If GetTileFromHDD failed, will load it (again?) from the web (see below) - If *timg\nImage = 0 - ; Launch a new web loading thread - If PBMap\ThreadsNB < PBMap\Options\MaxThreads - Protected *NewTile.Tile = AllocateMemory(SizeOf(Tile)) - If *NewTile - With *NewTile - ; New tile parameters - \key = key - \URL = URL - \CacheFile = CacheFile - \nImage = 0 - \Time = ElapsedMilliseconds() - \GetImageThread = CreateThread(@GetImageThread(), *NewTile) - If \GetImageThread - *timg\Tile = *NewTile ; There's now a loading thread - *timg\Alpha = 0 - MyDebug(" Creating get image thread nb " + Str(\GetImageThread) + " to get " + CacheFile + " (key = " + key, 3) - PBMap\ThreadsNB + 1 - Else - MyDebug(" Can't create get image thread to get " + CacheFile, 3) - FreeMemory(*NewTile) - EndIf - EndWith - Else - MyDebug(" Error, can't allocate memory for a new tile loading thread", 3) + Else + ; If GetTileFromHDD failed, will load it (again?) from the web + If PBMap\ThreadsNB < PBMap\Options\MaxThreads + If PBMap\DownloadSlots < PBMap\Options\MaxDownloadSlots + ; Launch a new web loading thread + PBMap\DownloadSlots + 1 + Protected *NewTile.Tile = AllocateMemory(SizeOf(Tile)) + If *NewTile + With *NewTile + ; New tile parameters + \key = key + \URL = URL + \CacheFile = CacheFile + \nImage = 0 + \Time = ElapsedMilliseconds() + \GetImageThread = CreateThread(@GetImageThread(), *NewTile) + If \GetImageThread + *timg\Tile = *NewTile ; There's now a loading thread + *timg\Alpha = 0 + MyDebug(" Creating get image thread nb " + Str(\GetImageThread) + " to get " + CacheFile + " (key = " + key, 3) + PBMap\ThreadsNB + 1 + Else + MyDebug(" Can't create get image thread to get " + CacheFile, 3) + FreeMemory(*NewTile) + EndIf + EndWith + Else + MyDebug(" Error, can't allocate memory for a new tile loading thread", 3) + EndIf + Else + MyDebug(" Thread needed " + key + " for image " + CacheFile + " canceled because no free download slot.", 5) EndIf Else MyDebug(" Error, maximum threads nb reached", 3) @@ -2505,16 +2464,18 @@ Module PBMap *Tile = EventData() key = *Tile\key *Tile\Download = 0 - PBMap\MemCache\Images(key)\Tile = *Tile\Size - If *Tile\Size ; <> 0 - ; Web loading thread has finished successfully - FreeMemory(*Tile) ; Frees the data needed for the thread (*tile=PBMap\MemCache\Images(key)\Tile) - PBMap\MemCache\Images(key)\Tile = -1 - Else - FreeMemory(*Tile) ; Frees the data needed for the thread (*tile=PBMap\MemCache\Images(key)\Tile) - PBMap\MemCache\Images(key)\Tile = 0 + If FindMapElement(PBMap\MemCache\Images(), key) <> 0 + ; If the map element has not been deleted during the thread lifetime (should not occur) + PBMap\MemCache\Images(key)\Tile = *Tile\Size + If *Tile\Size + PBMap\MemCache\Images(key)\Tile = -1 ; Web loading thread has finished successfully + Else + PBMap\MemCache\Images(key)\Tile = 0 + EndIf EndIf + FreeMemory(*Tile) ; Frees the data needed for the thread (*tile=PBMap\MemCache\Images(key)\Tile) PBMap\ThreadsNB - 1 + PBMap\DownloadSlots - 1 PBMap\Redraw = #True EndSelect EndProcedure @@ -2585,11 +2546,6 @@ Module PBMap \Window = Window \Timer = 1 \Mode = #MODE_DEFAULT - \DownloadSlotsMutex = CreateMutex() - If \DownloadSlotsMutex = #False - MyDebug("Cannot create a mutex", 0) - End - EndIf \MemoryCacheAccessNB = 0 \MemoryCacheAccessNBMutex = CreateMutex() If \MemoryCacheAccessNBMutex = #False @@ -2913,10 +2869,10 @@ CompilerIf #PB_Compiler_IsMainFile CompilerEndIf ; IDE Options = PureBasic 5.60 (Windows - x64) -; CursorPosition = 1181 -; FirstLine = 1156 +; CursorPosition = 1066 +; FirstLine = 1384 ; Folding = ------------------- ; EnableThread ; EnableXP ; CompileSourceDirectory -; Watchlist = PBMap::PBMap\DownloadSlots \ No newline at end of file +; DisablePurifier = 1,1,1,1 \ No newline at end of file From d3e277937ebdd1f8c3b4fb3d1cbeb614dc3494de Mon Sep 17 00:00:00 2001 From: djes Date: Thu, 15 Jun 2017 15:30:19 +0200 Subject: [PATCH 15/16] Old files cleaning bug fixed --- PBMap.pb | 55 +++++++++++++++++++++++++++++-------------------------- 1 file changed, 29 insertions(+), 26 deletions(-) diff --git a/PBMap.pb b/PBMap.pb index b90bf51..89a8d16 100644 --- a/PBMap.pb +++ b/PBMap.pb @@ -295,8 +295,7 @@ Module PBMap Dragging.i Dirty.i ; To signal that drawing need a refresh - MemoryCacheAccessNB.i ; Count the access to the memory cache. =0 no access ; >0 download threads ; -1 cleaning - MemoryCacheAccessNBMutex.i ; Memorycache access variable mutual exclusion + MemoryCacheAccessMutex.i ; Memorycache access variable mutual exclusion DownloadSlots.i ; Actual nb of used download slots List TracksList.Tracks() ; To display a GPX track @@ -1054,7 +1053,7 @@ Module PBMap ;-*** ; If cache size exceeds limit, try to delete the oldest tiles used (first in the time stack) Procedure MemoryCacheManagement() - LockMutex(PBMap\MemoryCacheAccessNBMutex) ; Prevents thread to start or finish + LockMutex(PBMap\MemoryCacheAccessMutex) ; Prevents thread to start or finish Protected CacheSize = MapSize(PBMap\MemCache\Images()) * Pow(PBMap\TileSize, 2) * 4 ; Size of a tile = TileSize * TileSize * 4 bytes (RGBA) Protected CacheLimit = PBMap\Options\MaxMemCache * 1024 MyDebug("Cache size : " + Str(CacheSize/1024) + " / CacheLimit : " + Str(CacheLimit/1024), 5) @@ -1091,7 +1090,7 @@ Module PBMap MyDebug(" Cache cleaning unsuccessfull, can't add new tiles.", 5) EndIf EndIf - UnlockMutex(PBMap\MemoryCacheAccessNBMutex) + UnlockMutex(PBMap\MemoryCacheAccessMutex) EndProcedure Procedure.i GetTileFromHDD(CacheFile.s) @@ -1142,19 +1141,18 @@ Module PBMap Threaded Progress = 0, Quit = #False Procedure GetImageThread(*Tile.Tile) - LockMutex(PBMap\MemoryCacheAccessNBMutex) + LockMutex(PBMap\MemoryCacheAccessMutex) MyDebug("Thread nb " + Str(*Tile\GetImageThread) + " " + *Tile\key + " starting for image " + *Tile\CacheFile, 5) ; If MemoryCache is currently being cleaned, abort ; If PBMap\MemoryCacheAccessNB = -1 ; MyDebug(" Thread nb " + Str(*Tile\GetImageThread) + " " + *Tile\key + " for image " + *Tile\CacheFile + " canceled because of cleaning.", 5) ; *Tile\Size = 0 ; \Size = 0 signals that the download has failed ; PostEvent(#PB_Event_Gadget, PBMap\Window, PBmap\Gadget, #PB_MAP_TILE_CLEANUP, *Tile) ; To free memory outside the thread -; UnlockMutex(PBMap\MemoryCacheAccessNBMutex) +; UnlockMutex(PBMap\MemoryCacheAccessMutex) ; ProcedureReturn ; EndIf ; We're accessing MemoryCache - PBMap\MemoryCacheAccessNB + 1 - UnlockMutex(PBMap\MemoryCacheAccessNBMutex) + UnlockMutex(PBMap\MemoryCacheAccessMutex) *Tile\Size = 0 *Tile\Download = ReceiveHTTPFile(*Tile\URL, *Tile\CacheFile, #PB_HTTP_Asynchronous) If *Tile\Download @@ -1186,17 +1184,16 @@ Module PBMap Until Quit EndIf ; End of the memory cache access - LockMutex(PBMap\MemoryCacheAccessNBMutex) - PBMap\MemoryCacheAccessNB - 1 + LockMutex(PBMap\MemoryCacheAccessMutex) PostEvent(#PB_Event_Gadget, PBMap\Window, PBmap\Gadget, #PB_MAP_TILE_CLEANUP, *Tile) ; To free memory outside the thread - UnlockMutex(PBMap\MemoryCacheAccessNBMutex) + UnlockMutex(PBMap\MemoryCacheAccessMutex) EndProcedure ;-*** Procedure.i GetTile(key.s, URL.s, CacheFile.s) ; MemoryCache access management - LockMutex(PBMap\MemoryCacheAccessNBMutex) + LockMutex(PBMap\MemoryCacheAccessMutex) ; Try to find the tile in memory cache Protected *timg.ImgMemCach = FindMapElement(PBMap\MemCache\Images(), key) If *timg @@ -1211,7 +1208,7 @@ Module PBMap MoveElement(PBMap\MemCache\ImagesTimeStack(), #PB_List_Last) ; *timg\TimeStackPtr = LastElement(PBMap\MemCache\ImagesTimeStack()) ; *** - UnlockMutex(PBMap\MemoryCacheAccessNBMutex) + UnlockMutex(PBMap\MemoryCacheAccessMutex) ProcedureReturn *timg Else ; No, try to load it from HD (see below) @@ -1222,7 +1219,7 @@ Module PBMap *timg = AddMapElement(PBMap\MemCache\Images(), key) If *timg = 0 MyDebug(" Can't add a new cache element.", 4) - UnlockMutex(PBMap\MemoryCacheAccessNBMutex) + UnlockMutex(PBMap\MemoryCacheAccessMutex) ProcedureReturn #False EndIf ; add a new time stack element at the End @@ -1232,7 +1229,7 @@ Module PBMap If *timg\TimeStackPtr = 0 MyDebug(" Can't add a new time stack element.", 4) DeleteMapElement(PBMap\MemCache\Images()) - UnlockMutex(PBMap\MemoryCacheAccessNBMutex) + UnlockMutex(PBMap\MemoryCacheAccessMutex) ProcedureReturn #False EndIf ; Associates the time stack element to the cache element @@ -1242,10 +1239,17 @@ Module PBMap ; If there's no active download thread for this tile If *timg\Tile <= 0 ; Manage tile file lifetime, delete if too old - If PBMap\Options\TileLifetime <> -1 - If Date() - GetFileDate(CacheFile, #PB_Date_Modified) > PBMap\Options\TileLifetime ; If Lifetime > MaxLifeTime ; There's a bug with #PB_Date_Created - MyDebug(" Deleting too old " + CacheFile, 3) - DeleteFile(CacheFile) + If PBMap\Options\TileLifetime <> -1 + If FileSize(CacheFile) > 0 ; Does the file exists ? + If Date() - GetFileDate(CacheFile, #PB_Date_Modified) > PBMap\Options\TileLifetime ; If Lifetime > MaxLifeTime ; There's a bug with #PB_Date_Created + If DeleteFile(CacheFile) + MyDebug(" Deleting too old image file " + CacheFile, 3) + Else + MyDebug(" Can't delete too old image file " + CacheFile, 3) + UnlockMutex(PBMap\MemoryCacheAccessMutex) + ProcedureReturn #False + EndIf + EndIf EndIf EndIf ; Try To load it from HD @@ -1259,7 +1263,7 @@ Module PBMap If *timg\nImage ; Image found and loaded from HDD *timg\Alpha = 0 - UnlockMutex(PBMap\MemoryCacheAccessNBMutex) + UnlockMutex(PBMap\MemoryCacheAccessMutex) ProcedureReturn *timg Else ; If GetTileFromHDD failed, will load it (again?) from the web @@ -1298,7 +1302,7 @@ Module PBMap EndIf EndIf EndIf - UnlockMutex(PBMap\MemoryCacheAccessNBMutex) + UnlockMutex(PBMap\MemoryCacheAccessMutex) ProcedureReturn #False EndProcedure @@ -2546,9 +2550,8 @@ Module PBMap \Window = Window \Timer = 1 \Mode = #MODE_DEFAULT - \MemoryCacheAccessNB = 0 - \MemoryCacheAccessNBMutex = CreateMutex() - If \MemoryCacheAccessNBMutex = #False + \MemoryCacheAccessMutex = CreateMutex() + If \MemoryCacheAccessMutex = #False MyDebug("Cannot create a mutex", 0) End EndIf @@ -2869,8 +2872,8 @@ CompilerIf #PB_Compiler_IsMainFile CompilerEndIf ; IDE Options = PureBasic 5.60 (Windows - x64) -; CursorPosition = 1066 -; FirstLine = 1384 +; CursorPosition = 2552 +; FirstLine = 2548 ; Folding = ------------------- ; EnableThread ; EnableXP From 4183dcd59bdb9ada7ea66f503cc74e94a1c8b0c1 Mon Sep 17 00:00:00 2001 From: djes Date: Thu, 15 Jun 2017 15:32:33 +0200 Subject: [PATCH 16/16] Create README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index a86b00e..32d63bb 100644 --- a/README.md +++ b/README.md @@ -17,3 +17,4 @@ Thyphoon djes Idle Progi1984 +yves86