/// <summary> /// enqueueens tile to cache /// </summary> /// <param name="task"></param> void EnqueueCacheTask(CacheQueueItem task) { lock (tileCacheQueue) { if (!tileCacheQueue.Contains(task)) { Debug.WriteLine("EnqueueCacheTask: " + task); tileCacheQueue.Enqueue(task); if (CacheEngine != null && CacheEngine.IsAlive) { WaitForCache.Set(); } #if PocketPC else if (CacheEngine == null || CacheEngine.State == ThreadState.Stopped || CacheEngine.State == ThreadState.Unstarted) #else else if (CacheEngine == null || CacheEngine.ThreadState == System.Threading.ThreadState.Stopped || CacheEngine.ThreadState == System.Threading.ThreadState.Unstarted) #endif { CacheEngine = null; CacheEngine = new Thread(new ThreadStart(CacheEngineLoop)) { Name = "CacheEngine", IsBackground = false, Priority = ThreadPriority.Lowest }; abortCacheLoop = false; CacheEngine.Start(); } } } }
/// <summary> /// Creates our event thread that will receive native events /// </summary> private void CreateGpsEventThread() { // we only want to create the thread if we don't have one created already // and we have opened the gps device if (gpsEventThread == null && gpsHandle != IntPtr.Zero) { // Create and start thread to listen for GPS events gpsEventThread = new Thread(new System.Threading.ThreadStart(WaitForGpsEvents)); gpsEventThread.IsBackground = false; gpsEventThread.Name = "GMap.NET GpsEvents"; gpsEventThread.Start(); } }
/// <summary> /// starts loader threads if needed /// </summary> void EnsureLoaderThreads() { #if !PocketPC while (GThreadPool.Count < 5) #else while (GThreadPool.Count < 2) #endif { Thread t = new Thread(new ThreadStart(ProcessLoadTask)); { t.Name = "GMap.NET TileLoader: " + GThreadPool.Count; t.IsBackground = true; t.Priority = ThreadPriority.BelowNormal; } GThreadPool.Add(t); Debug.WriteLine("add " + t.Name + " to GThreadPool"); t.Start(); } }
public Task ReloadMapAsync() { ReloadMap(); return(Task.Factory.StartNew(() => { bool wait; do { Thread.Sleep(100); Monitor.Enter(TileLoadQueue); try { wait = TileLoadQueue.Any(); } finally { Monitor.Exit(TileLoadQueue); } } while (wait); })); }
/// <summary> /// Closes the gps device. /// </summary> public void Close() { if (gpsHandle != IntPtr.Zero) { GPSCloseDevice(gpsHandle); gpsHandle = IntPtr.Zero; } // Set our native stop event so we can exit our event thread. if (stopHandle != IntPtr.Zero) { Win32.EventModify(stopHandle, (int)Win32.EventFlags.SET); } // wait exit if (gpsEventThread != null) { quit.WaitOne(); gpsEventThread = null; } }
/// <summary> /// updates map bounds /// </summary> void UpdateBounds() { if (MapType == NET.MapType.None) { return; } lock (tileLoadQueue) { tileDrawingListLock.AcquireWriterLock(); try { #region -- find tiles around -- tileDrawingList.Clear(); for (int i = -sizeOfMapArea.Width; i <= sizeOfMapArea.Width; i++) { for (int j = -sizeOfMapArea.Height; j <= sizeOfMapArea.Height; j++) { Point p = centerTileXYLocation; p.X += i; p.Y += j; #if ContinuesMap // ---------------------------- if (p.X < minOfTiles.Width) { p.X += (maxOfTiles.Width + 1); } if (p.X > maxOfTiles.Width) { p.X -= (maxOfTiles.Width + 1); } // ---------------------------- #endif if (p.X >= minOfTiles.Width && p.Y >= minOfTiles.Height && p.X <= maxOfTiles.Width && p.Y <= maxOfTiles.Height) { if (!tileDrawingList.Contains(p)) { tileDrawingList.Add(p); } } } } if (GMaps.Instance.ShuffleTilesOnLoad) { Stuff.Shuffle <Point>(tileDrawingList); } #endregion foreach (Point p in tileDrawingList) { LoadTask task = new LoadTask(p, Zoom); { if (!tileLoadQueue.Contains(task)) { tileLoadQueue.Enqueue(task); } } } } finally { tileDrawingListLock.ReleaseWriterLock(); } #region -- starts loader threads if needed -- #if !PocketPC while (GThreadPool.Count < GThreadPoolSize) #else while (GThreadPool.Count < GThreadPoolSize) #endif { Thread t = new Thread(new ThreadStart(ProcessLoadTask)); { t.Name = "GMap.NET TileLoader: " + GThreadPool.Count; t.IsBackground = true; t.Priority = ThreadPriority.BelowNormal; } GThreadPool.Add(t); Debug.WriteLine("add " + t.Name + " to GThreadPool"); t.Start(); } #endregion lock (LastTileLoadStartEndLock) { LastTileLoadStart = DateTime.Now; Debug.WriteLine("OnTileLoadStart - at zoom " + Zoom + ", time: " + LastTileLoadStart.TimeOfDay); } loadWaitCount = 0; #if !PocketPC Monitor.PulseAll(tileLoadQueue); #else wait.PulseAll(); #endif } if (OnTileLoadStart != null) { OnTileLoadStart(); } }
void Dispose(bool disposing) { if (IsStarted) { if (invalidator != null) { invalidator.CancelAsync(); invalidator.DoWork -= new DoWorkEventHandler(invalidatorWatch); invalidator.Dispose(); invalidator = null; } if (Refresh != null) { Refresh.Set(); Refresh.Close(); Refresh = null; } int x = Interlocked.Decrement(ref instances); Debug.WriteLine("OnMapClose: " + x); CancelAsyncTasks(); IsStarted = false; if (Matrix != null) { Matrix.Dispose(); Matrix = null; } if (FailedLoads != null) { lock (FailedLoads) { FailedLoads.Clear(); RaiseEmptyTileError = false; } FailedLoads = null; } // cancel waiting loaders Monitor.Enter(tileLoadQueue); try { Monitor.PulseAll(tileLoadQueue); tileDrawingList.Clear(); } finally { Monitor.Exit(tileLoadQueue); } lock (GThreadPool) { #if PocketPC Debug.WriteLine("waiting until loaders are stopped..."); while (GThreadPool.Count > 0) { var t = GThreadPool[0]; if (t.State != ThreadState.Stopped) { var tr = t.Join(1111); Debug.WriteLine(t.Name + ", " + t.State); if (!tr) { continue; } else { GThreadPool.Remove(t); } } else { GThreadPool.Remove(t); } } Thread.Sleep(1111); #endif } if (tileDrawingListLock != null) { tileDrawingListLock.Dispose(); tileDrawingListLock = null; tileDrawingList = null; } if (x == 0) { #if DEBUG GMaps.Instance.CancelTileCaching(); #endif GMaps.Instance.noMapInstances = true; GMaps.Instance.WaitForCache.Set(); if (disposing) { GMaps.Instance.MemoryCache.Clear(); } } } }
// tile consumer thread void ProcessLoadTask() { LoadTask?task = null; long lastTileLoadTimeMs; bool stop = false; #if !PocketPC Thread ct = Thread.CurrentThread; string ctid = "Thread[" + ct.ManagedThreadId + "]"; #else int ctid = 0; #endif while (!stop && IsStarted) { task = null; Monitor.Enter(tileLoadQueue); try { while (tileLoadQueue.Count == 0) { Debug.WriteLine(ctid + " - Wait " + loadWaitCount + " - " + DateTime.Now.TimeOfDay); if (++loadWaitCount >= GThreadPoolSize) { loadWaitCount = 0; #region -- last thread takes action -- { LastTileLoadEnd = DateTime.Now; lastTileLoadTimeMs = (long)(LastTileLoadEnd - LastTileLoadStart).TotalMilliseconds; } #region -- clear stuff-- if (IsStarted) { GMaps.Instance.MemoryCache.RemoveOverload(); tileDrawingListLock.AcquireReaderLock(); try { Matrix.ClearLevelAndPointsNotIn(Zoom, tileDrawingList); } finally { tileDrawingListLock.ReleaseReaderLock(); } } #endregion UpdateGroundResolution(); #if UseGC GC.Collect(); GC.WaitForPendingFinalizers(); GC.Collect(); #endif Debug.WriteLine(ctid + " - OnTileLoadComplete: " + lastTileLoadTimeMs + "ms, MemoryCacheSize: " + GMaps.Instance.MemoryCache.Size + "MB"); if (OnTileLoadComplete != null) { OnTileLoadComplete(lastTileLoadTimeMs); } #endregion } if (!IsStarted || false == Monitor.Wait(tileLoadQueue, WaitForTileLoadThreadTimeout, false) || !IsStarted) { stop = true; break; } } if (IsStarted && !stop || tileLoadQueue.Count > 0) { task = tileLoadQueue.Pop(); } } finally { Monitor.Exit(tileLoadQueue); } if (task.HasValue && IsStarted) { try { #region -- execute -- var m = Matrix.GetTileWithReadLock(task.Value.Zoom, task.Value.Pos); if (!m.NotEmpty) { Debug.WriteLine(ctid + " - try load: " + task); Tile t = new Tile(task.Value.Zoom, task.Value.Pos); foreach (var tl in provider.Overlays) { int retry = 0; do { PureImage img = null; Exception ex = null; if (!provider.MaxZoom.HasValue || task.Value.Zoom <= provider.MaxZoom) { if (skipOverZoom == 0 || task.Value.Zoom <= skipOverZoom) { // tile number inversion(BottomLeft -> TopLeft) if (tl.InvertedAxisY) { img = GMaps.Instance.GetImageFrom(tl, new GPoint(task.Value.Pos.X, maxOfTiles.Height - task.Value.Pos.Y), task.Value.Zoom, out ex); } else // ok { img = GMaps.Instance.GetImageFrom(tl, task.Value.Pos, task.Value.Zoom, out ex); } } } if (img != null && ex == null) { if (okZoom < task.Value.Zoom) { okZoom = task.Value.Zoom; skipOverZoom = 0; Debug.WriteLine("skipOverZoom disabled, okZoom: " + okZoom); } } else if (ex != null) { if (skipOverZoom != okZoom) { if (ex.Message.Contains("(404) Not Found")) { skipOverZoom = okZoom; Debug.WriteLine("skipOverZoom enabled: " + skipOverZoom); } } } // check for parent tiles if not found if (img == null && okZoom > 0 && fillEmptyTiles && Provider.Projection is MercatorProjection) { int zoomOffset = task.Value.Zoom > okZoom ? task.Value.Zoom - okZoom : 1; long Ix = 0; GPoint parentTile = GPoint.Empty; while (img == null && zoomOffset < task.Value.Zoom) { Ix = (long)Math.Pow(2, zoomOffset); parentTile = new GMap.NET.GPoint((task.Value.Pos.X / Ix), (task.Value.Pos.Y / Ix)); img = GMaps.Instance.GetImageFrom(tl, parentTile, task.Value.Zoom - zoomOffset++, out ex); } if (img != null) { // offsets in quadrant long Xoff = Math.Abs(task.Value.Pos.X - (parentTile.X * Ix)); long Yoff = Math.Abs(task.Value.Pos.Y - (parentTile.Y * Ix)); img.IsParent = true; img.Ix = Ix; img.Xoff = Xoff; img.Yoff = Yoff; // wpf //var geometry = new RectangleGeometry(new Rect(Core.tileRect.X + 0.6, Core.tileRect.Y + 0.6, Core.tileRect.Width + 0.6, Core.tileRect.Height + 0.6)); //var parentImgRect = new Rect(Core.tileRect.X - Core.tileRect.Width * Xoff + 0.6, Core.tileRect.Y - Core.tileRect.Height * Yoff + 0.6, Core.tileRect.Width * Ix + 0.6, Core.tileRect.Height * Ix + 0.6); // gdi+ //System.Drawing.Rectangle dst = new System.Drawing.Rectangle((int)Core.tileRect.X, (int)Core.tileRect.Y, (int)Core.tileRect.Width, (int)Core.tileRect.Height); //System.Drawing.RectangleF srcRect = new System.Drawing.RectangleF((float)(Xoff * (img.Img.Width / Ix)), (float)(Yoff * (img.Img.Height / Ix)), (img.Img.Width / Ix), (img.Img.Height / Ix)); } } if (img != null) { Debug.WriteLine(ctid + " - tile loaded: " + img.Data.Length / 1024 + "KB, " + task); { t.AddOverlay(img); } break; } else { if (ex != null) { lock (FailedLoads) { if (!FailedLoads.ContainsKey(task.Value)) { FailedLoads.Add(task.Value, ex); if (OnEmptyTileError != null) { if (!RaiseEmptyTileError) { RaiseEmptyTileError = true; OnEmptyTileError(task.Value.Zoom, task.Value.Pos); } } } } } if (RetryLoadTile > 0) { Debug.WriteLine(ctid + " - ProcessLoadTask: " + task + " -> empty tile, retry " + retry); { Thread.Sleep(1111); } } } }while(++retry < RetryLoadTile); } if (t.HasAnyOverlays && IsStarted) { Matrix.SetTile(t); } else { t.Dispose(); } } #endregion } catch (Exception ex) { Debug.WriteLine(ctid + " - ProcessLoadTask: " + ex.ToString()); } finally { if (Refresh != null) { Refresh.Set(); } } } } #if !PocketPC Monitor.Enter(tileLoadQueue); try { Debug.WriteLine("Quit - " + ct.Name); lock (GThreadPool) { GThreadPool.Remove(ct); } } finally { Monitor.Exit(tileLoadQueue); } #endif }
/// <summary> /// Method used to listen for native events from the GPS. /// </summary> private void WaitForGpsEvents() { //lock (this) { bool listening = true; // allocate 3 handles worth of memory to pass to WaitForMultipleObjects IntPtr handles = Utils.LocalAlloc(12); // write the three handles we are listening for. Marshal.WriteInt32(handles, 0, stopHandle.ToInt32()); Marshal.WriteInt32(handles, 4, deviceStateChangedHandle.ToInt32()); Marshal.WriteInt32(handles, 8, newLocationHandle.ToInt32()); while (listening) { int obj = WaitForMultipleObjects(3, handles, 0, -1); if (obj != waitFailed) { switch (obj) { case 0: // we've been signalled to stop listening = false; break; case 1: // device state has changed if (deviceStateChanged != null) { deviceStateChanged(this, GetDeviceState()); } break; case 2: // location has changed if (locationChanged != null) { locationChanged(this, GetPosition()); } break; } } } // free the memory we allocated for the native handles Utils.LocalFree(handles); if (newLocationHandle != IntPtr.Zero) { CloseHandle(newLocationHandle); newLocationHandle = IntPtr.Zero; } if (deviceStateChangedHandle != IntPtr.Zero) { CloseHandle(deviceStateChangedHandle); deviceStateChangedHandle = IntPtr.Zero; } if (stopHandle != IntPtr.Zero) { CloseHandle(stopHandle); stopHandle = IntPtr.Zero; } // clear our gpsEventThread so that we can recreate this thread again // if the events are hooked up again. gpsEventThread = null; Debug.WriteLine("gps device stopped..."); } }
/// <summary> /// updates map bounds /// </summary> void UpdateBounds() { if (!IsStarted || Provider.Equals(EmptyProvider.Instance)) { return; } updatingBounds = true; tileDrawingListLock.AcquireWriterLock(); try { #region -- find tiles around -- tileDrawingList.Clear(); for (long i = (int)Math.Floor(-sizeOfMapArea.Width * scaleX), countI = (int)Math.Ceiling(sizeOfMapArea.Width * scaleX); i <= countI; i++) { for (long j = (int)Math.Floor(-sizeOfMapArea.Height * scaleY), countJ = (int)Math.Ceiling(sizeOfMapArea.Height * scaleY); j <= countJ; j++) { GPoint p = centerTileXYLocation; p.X += i; p.Y += j; #if ContinuesMap // ---------------------------- if (p.X < minOfTiles.Width) { p.X += (maxOfTiles.Width + 1); } if (p.X > maxOfTiles.Width) { p.X -= (maxOfTiles.Width + 1); } // ---------------------------- #endif if (p.X >= minOfTiles.Width && p.Y >= minOfTiles.Height && p.X <= maxOfTiles.Width && p.Y <= maxOfTiles.Height) { DrawTile dt = new DrawTile() { PosXY = p, PosPixel = new GPoint(p.X * tileRect.Width, p.Y * tileRect.Height), DistanceSqr = (centerTileXYLocation.X - p.X) * (centerTileXYLocation.X - p.X) + (centerTileXYLocation.Y - p.Y) * (centerTileXYLocation.Y - p.Y) }; if (!tileDrawingList.Contains(dt)) { tileDrawingList.Add(dt); } } } } if (GMaps.Instance.ShuffleTilesOnLoad) { Stuff.Shuffle <DrawTile>(tileDrawingList); } else { tileDrawingList.Sort(); } #endregion } finally { tileDrawingListLock.ReleaseWriterLock(); } Monitor.Enter(tileLoadQueue); try { tileDrawingListLock.AcquireReaderLock(); try { foreach (DrawTile p in tileDrawingList) { LoadTask task = new LoadTask(p.PosXY, Zoom); { if (!tileLoadQueue.Contains(task)) { tileLoadQueue.Push(task); } } } } finally { tileDrawingListLock.ReleaseReaderLock(); } #region -- starts loader threads if needed -- lock (GThreadPool) { while (GThreadPool.Count < GThreadPoolSize) { Thread t = new Thread(new ThreadStart(ProcessLoadTask)); { t.Name = "TileLoader: " + GThreadPool.Count; t.IsBackground = true; t.Priority = ThreadPriority.BelowNormal; } GThreadPool.Add(t); Debug.WriteLine("add " + t.Name + " to GThreadPool"); t.Start(); } } #endregion { LastTileLoadStart = DateTime.Now; Debug.WriteLine("OnTileLoadStart - at zoom " + Zoom + ", time: " + LastTileLoadStart.TimeOfDay); } loadWaitCount = 0; Monitor.PulseAll(tileLoadQueue); } finally { Monitor.Exit(tileLoadQueue); } updatingBounds = false; if (OnTileLoadStart != null) { OnTileLoadStart(); } }
/// <summary> /// Method used to listen for native events from the GPS. /// </summary> private void WaitForGpsEvents() { //lock (this) { bool listening = true; // allocate 3 handles worth of memory to pass to WaitForMultipleObjects IntPtr handles = Utils.LocalAlloc(12); // write the three handles we are listening for. Marshal.WriteInt32(handles, 0, stopHandle.ToInt32()); Marshal.WriteInt32(handles, 4, deviceStateChangedHandle.ToInt32()); Marshal.WriteInt32(handles, 8, newLocationHandle.ToInt32()); while(listening) { int obj = WaitForMultipleObjects(3, handles, 0, -1); if(obj != waitFailed) { switch(obj) { case 0: // we've been signalled to stop listening = false; break; case 1: // device state has changed if(deviceStateChanged != null) { deviceStateChanged(this, GetDeviceState()); } break; case 2: // location has changed if(locationChanged != null) { locationChanged(this, GetPosition()); } break; } } } // free the memory we allocated for the native handles Utils.LocalFree(handles); if(newLocationHandle != IntPtr.Zero) { CloseHandle(newLocationHandle); newLocationHandle = IntPtr.Zero; } if(deviceStateChangedHandle != IntPtr.Zero) { CloseHandle(deviceStateChangedHandle); deviceStateChangedHandle = IntPtr.Zero; } if(stopHandle != IntPtr.Zero) { CloseHandle(stopHandle); stopHandle = IntPtr.Zero; } // clear our gpsEventThread so that we can recreate this thread again // if the events are hooked up again. gpsEventThread = null; Debug.WriteLine("gps device stopped..."); } }
/// <summary> /// updates map bounds /// </summary> void UpdateBounds() { if (!IsStarted || Provider.Equals(EmptyProvider.Instance)) { return; } UpdatingBounds = true; TileDrawingListLock.AcquireWriterLock(); try { #region -- find tiles around -- TileDrawingList.Clear(); for (long i = (int)Math.Floor(-_sizeOfMapArea.Width * ScaleX), countI = (int)Math.Ceiling(_sizeOfMapArea.Width * ScaleX); i <= countI; i++) { for (long j = (int)Math.Floor(-_sizeOfMapArea.Height * ScaleY), countJ = (int)Math.Ceiling(_sizeOfMapArea.Height * ScaleY); j <= countJ; j++) { var p = CenterTileXYLocation; p.X += i; p.Y += j; #if ContinuesMap // ---------------------------- if (p.X < minOfTiles.Width) { p.X += (maxOfTiles.Width + 1); } if (p.X > maxOfTiles.Width) { p.X -= (maxOfTiles.Width + 1); } // ---------------------------- #endif if (p.X >= _minOfTiles.Width && p.Y >= _minOfTiles.Height && p.X <= _maxOfTiles.Width && p.Y <= _maxOfTiles.Height) { var dt = new DrawTile() { PosXY = p, PosPixel = new GPoint(p.X * TileRect.Width, p.Y * TileRect.Height), DistanceSqr = (CenterTileXYLocation.X - p.X) * (CenterTileXYLocation.X - p.X) + (CenterTileXYLocation.Y - p.Y) * (CenterTileXYLocation.Y - p.Y) }; if (!TileDrawingList.Contains(dt)) { TileDrawingList.Add(dt); } } } } if (GMaps.Instance.ShuffleTilesOnLoad) { Stuff.Shuffle(TileDrawingList); } else { TileDrawingList.Sort(); } #endregion } finally { TileDrawingListLock.ReleaseWriterLock(); } #if NET40 Interlocked.Exchange(ref _loadWaitCount, 0); #else Monitor.Enter(TileLoadQueue); try { #endif TileDrawingListLock.AcquireReaderLock(); try { foreach (var p in TileDrawingList) { var task = new LoadTask(p.PosXY, Zoom, this); #if NET40 AddLoadTask(task); #else { if (!TileLoadQueue.Contains(task)) { TileLoadQueue.Push(task); } } #endif } } finally { TileDrawingListLock.ReleaseReaderLock(); } #if !NET40 #region -- starts loader threads if needed -- lock (_gThreadPool) { while (_gThreadPool.Count < GThreadPoolSize) { var t = new Thread(TileLoadThread); { t.Name = "TileLoader: " + _gThreadPool.Count; t.IsBackground = true; t.Priority = ThreadPriority.BelowNormal; } _gThreadPool.Add(t); Debug.WriteLine("add " + t.Name + " to GThreadPool"); t.Start(); } } #endregion #endif { _lastTileLoadStart = DateTime.Now; Debug.WriteLine("OnTileLoadStart - at zoom " + Zoom + ", time: " + _lastTileLoadStart.TimeOfDay); } #if !NET40 _loadWaitCount = 0; Monitor.PulseAll(TileLoadQueue); } finally { Monitor.Exit(TileLoadQueue); } #endif UpdatingBounds = false; if (OnTileLoadStart != null) { OnTileLoadStart(); } }
/// <summary> /// Closes the gps device. /// </summary> public void Close() { if(gpsHandle != IntPtr.Zero) { GPSCloseDevice(gpsHandle); gpsHandle = IntPtr.Zero; } // Set our native stop event so we can exit our event thread. if(stopHandle != IntPtr.Zero) { Win32.EventModify(stopHandle, (int)Win32.EventFlags.SET); } // wait exit if (gpsEventThread != null) { quit.WaitOne(); gpsEventThread = null; } }
/// <summary> /// Creates our event thread that will receive native events /// </summary> private void CreateGpsEventThread() { // we only want to create the thread if we don't have one created already // and we have opened the gps device if(gpsEventThread == null && gpsHandle != IntPtr.Zero) { // Create and start thread to listen for GPS events gpsEventThread = new Thread(new System.Threading.ThreadStart(WaitForGpsEvents)); gpsEventThread.IsBackground = false; gpsEventThread.Name = "GMap.NET GpsEvents"; gpsEventThread.Start(); } }
/// <summary> /// live for cache ;} /// </summary> /// <param name="sender"></param> /// <param name="e"></param> void CacheEngineLoop() { Debug.WriteLine("CacheEngine: start"); int left = 0; OnTileCacheStart?.Invoke(); bool startEvent = false; while (!abortCacheLoop) { try { CacheQueueItem?task = null; lock (tileCacheQueue) { left = tileCacheQueue.Count; if (left > 0) { task = tileCacheQueue.Dequeue(); } } if (task.HasValue) { if (startEvent) { startEvent = false; OnTileCacheStart?.Invoke(); } OnTileCacheProgress?.Invoke(left); #region -- save -- // check if stream wasn't disposed somehow if (task.Value.Img != null) { Debug.WriteLine("CacheEngine[" + left + "]: storing tile " + task.Value + ", " + task.Value.Img.Length / 1024 + "kB..."); if ((task.Value.CacheType & CacheUsage.First) == CacheUsage.First && PrimaryCache != null) { if (cacheOnIdleRead) { while (Interlocked.Decrement(ref readingCache) > 0) { Thread.Sleep(1000); } } PrimaryCache.PutImageToCache(task.Value.Img, task.Value.Tile.Type, task.Value.Tile.Pos, task.Value.Tile.Zoom); } if ((task.Value.CacheType & CacheUsage.Second) == CacheUsage.Second && SecondaryCache != null) { if (cacheOnIdleRead) { while (Interlocked.Decrement(ref readingCache) > 0) { Thread.Sleep(1000); } } SecondaryCache.PutImageToCache(task.Value.Img, task.Value.Tile.Type, task.Value.Tile.Pos, task.Value.Tile.Zoom); } task.Value.Clear(); if (!boostCacheEngine) { #if PocketPC Thread.Sleep(3333); #else Thread.Sleep(333); #endif } } else { Debug.WriteLine("CacheEngineLoop: skip, tile disposed to early -> " + task.Value); } task = null; #endregion } else { if (!startEvent) { startEvent = true; OnTileCacheComplete?.Invoke(); } if (abortCacheLoop || noMapInstances || !WaitForCache.WaitOne(33333, false) || noMapInstances) { break; } } } #if !PocketPC catch (AbandonedMutexException) { break; } #endif catch (Exception ex) { Debug.WriteLine("CacheEngineLoop: " + ex.ToString()); } } Debug.WriteLine("CacheEngine: stop"); if (!startEvent) { OnTileCacheComplete?.Invoke(); } }
static void ProcessLoadTask(LoadTask task, string ctid) { try { #region -- execute -- var m = task.Core.Matrix.GetTileWithReadLock(task.Zoom, task.Pos); if (!m.NotEmpty) { Debug.WriteLine(ctid + " - try load: " + task); Tile t = new Tile(task.Zoom, task.Pos); foreach (var tl in task.Core.provider.Overlays) { int retry = 0; do { PureImage img = null; Exception ex = null; if (task.Zoom >= task.Core.provider.MinZoom && (!task.Core.provider.MaxZoom.HasValue || task.Zoom <= task.Core.provider.MaxZoom)) { if (task.Core.skipOverZoom == 0 || task.Zoom <= task.Core.skipOverZoom) { // tile number inversion(BottomLeft -> TopLeft) if (tl.InvertedAxisY) { img = GMaps.Instance.GetImageFrom(tl, new GPoint(task.Pos.X, task.Core.maxOfTiles.Height - task.Pos.Y), task.Zoom, out ex); } else // ok { img = GMaps.Instance.GetImageFrom(tl, task.Pos, task.Zoom, out ex); } } } if (img != null && ex == null) { if (task.Core.okZoom < task.Zoom) { task.Core.okZoom = task.Zoom; task.Core.skipOverZoom = 0; Debug.WriteLine("skipOverZoom disabled, okZoom: " + task.Core.okZoom); } } else if (ex != null) { if ((task.Core.skipOverZoom != task.Core.okZoom) && (task.Zoom > task.Core.okZoom)) { if (ex.Message.Contains("(404) Not Found")) { task.Core.skipOverZoom = task.Core.okZoom; Debug.WriteLine("skipOverZoom enabled: " + task.Core.skipOverZoom); } } } // check for parent tiles if not found if (img == null && task.Core.okZoom > 0 && task.Core.fillEmptyTiles && task.Core.Provider.Projection is MercatorProjection) { int zoomOffset = task.Zoom > task.Core.okZoom ? task.Zoom - task.Core.okZoom : 1; long Ix = 0; GPoint parentTile = GPoint.Empty; while (img == null && zoomOffset < task.Zoom) { Ix = (long)Math.Pow(2, zoomOffset); parentTile = new GMap.NET.GPoint((task.Pos.X / Ix), (task.Pos.Y / Ix)); img = GMaps.Instance.GetImageFrom(tl, parentTile, task.Zoom - zoomOffset++, out ex); } if (img != null) { // offsets in quadrant long Xoff = Math.Abs(task.Pos.X - (parentTile.X * Ix)); long Yoff = Math.Abs(task.Pos.Y - (parentTile.Y * Ix)); img.IsParent = true; img.Ix = Ix; img.Xoff = Xoff; img.Yoff = Yoff; // wpf //var geometry = new RectangleGeometry(new Rect(Core.tileRect.X + 0.6, Core.tileRect.Y + 0.6, Core.tileRect.Width + 0.6, Core.tileRect.Height + 0.6)); //var parentImgRect = new Rect(Core.tileRect.X - Core.tileRect.Width * Xoff + 0.6, Core.tileRect.Y - Core.tileRect.Height * Yoff + 0.6, Core.tileRect.Width * Ix + 0.6, Core.tileRect.Height * Ix + 0.6); // gdi+ //System.Drawing.Rectangle dst = new System.Drawing.Rectangle((int)Core.tileRect.X, (int)Core.tileRect.Y, (int)Core.tileRect.Width, (int)Core.tileRect.Height); //System.Drawing.RectangleF srcRect = new System.Drawing.RectangleF((float)(Xoff * (img.Img.Width / Ix)), (float)(Yoff * (img.Img.Height / Ix)), (img.Img.Width / Ix), (img.Img.Height / Ix)); } } if (img != null) { Debug.WriteLine(ctid + " - tile loaded: " + img.Data.Length / 1024 + "KB, " + task); { t.AddOverlay(img); } break; } else { if (ex != null) { lock (task.Core.FailedLoads) { if (!task.Core.FailedLoads.ContainsKey(task)) { task.Core.FailedLoads.Add(task, ex); if (task.Core.OnEmptyTileError != null) { if (!task.Core.RaiseEmptyTileError) { task.Core.RaiseEmptyTileError = true; task.Core.OnEmptyTileError(task.Zoom, task.Pos); } } } } } if (task.Core.RetryLoadTile > 0) { Debug.WriteLine(ctid + " - ProcessLoadTask: " + task + " -> empty tile, retry " + retry); { Thread.Sleep(1111); } } } }while (++retry < task.Core.RetryLoadTile); } if (t.HasAnyOverlays && task.Core.IsStarted) { task.Core.Matrix.SetTile(t); } else { t.Dispose(); } } #endregion } catch (Exception ex) { Debug.WriteLine(ctid + " - ProcessLoadTask: " + ex.ToString()); } finally { if (task.Core.Refresh != null) { task.Core.Refresh.Set(); } } }
void tileLoadThread() { LoadTask?task = null; bool stop = false; #if !PocketPC Thread ct = Thread.CurrentThread; string ctid = "Thread[" + ct.ManagedThreadId + "]"; #else int ctid = 0; #endif while (!stop && IsStarted) { task = null; Monitor.Enter(tileLoadQueue); try { while (tileLoadQueue.Count == 0) { Debug.WriteLine(ctid + " - Wait " + loadWaitCount + " - " + DateTime.Now.TimeOfDay); if (++loadWaitCount >= GThreadPoolSize) { loadWaitCount = 0; OnLoadComplete(ctid); } if (!IsStarted || false == Monitor.Wait(tileLoadQueue, WaitForTileLoadThreadTimeout, false) || !IsStarted) { stop = true; break; } } if (IsStarted && !stop || tileLoadQueue.Count > 0) { task = tileLoadQueue.Pop(); } } finally { Monitor.Exit(tileLoadQueue); } if (task.HasValue && IsStarted) { ProcessLoadTask(task.Value, ctid); } } #if !PocketPC Monitor.Enter(tileLoadQueue); try { Debug.WriteLine("Quit - " + ct.Name); lock (GThreadPool) { GThreadPool.Remove(ct); } } finally { Monitor.Exit(tileLoadQueue); } #endif }
/// <summary> /// live for cache ;} /// </summary> /// <param name="sender"></param> /// <param name="e"></param> void CacheEngineLoop() { int left = 0; if (OnTileCacheStart != null) { OnTileCacheStart(); } bool startEvent = false; while (!abortCacheLoop) { try { CacheQueueItem?task = null; lock (tileCacheQueue) { left = tileCacheQueue.Count; if (left > 0) { task = tileCacheQueue.Dequeue(); } } if (task.HasValue) { if (startEvent) { startEvent = false; if (OnTileCacheStart != null) { OnTileCacheStart(); } } if (OnTileCacheProgress != null) { OnTileCacheProgress(left); } #region -- save -- // check if stream wasn't disposed somehow if (task.Value.Img != null) { if ((task.Value.CacheType & CacheUsage.First) == CacheUsage.First && PrimaryCache != null) { if (cacheOnIdleRead) { while (Interlocked.Decrement(ref readingCache) > 0) { Thread.Sleep(1000); } } PrimaryCache.PutImageToCache(task.Value.Img, task.Value.Tile.Type, task.Value.Tile.Pos, task.Value.Tile.Zoom); } if ((task.Value.CacheType & CacheUsage.Second) == CacheUsage.Second && SecondaryCache != null) { if (cacheOnIdleRead) { while (Interlocked.Decrement(ref readingCache) > 0) { Thread.Sleep(1000); } } SecondaryCache.PutImageToCache(task.Value.Img, task.Value.Tile.Type, task.Value.Tile.Pos, task.Value.Tile.Zoom); } task.Value.Clear(); if (!boostCacheEngine) { #if PocketPC Thread.Sleep(3333); #else Thread.Sleep(333); #endif } } else { } task = null; #endregion } else { if (!startEvent) { startEvent = true; if (OnTileCacheComplete != null) { OnTileCacheComplete(); } } if (abortCacheLoop || noMapInstances || !WaitForCache.WaitOne(33333, false) || noMapInstances) { break; } } } #if !PocketPC catch (AbandonedMutexException) { break; } #endif catch { } } if (!startEvent) { if (OnTileCacheComplete != null) { OnTileCacheComplete(); } } }
/// <summary> /// updates map bounds /// </summary> void UpdateBounds() { if(MapType == NET.MapType.None) { return; } lock(tileLoadQueue) { tileDrawingListLock.AcquireWriterLock(); try { #region -- find tiles around -- tileDrawingList.Clear(); for(int i = -sizeOfMapArea.Width; i <= sizeOfMapArea.Width; i++) { for(int j = -sizeOfMapArea.Height; j <= sizeOfMapArea.Height; j++) { Point p = centerTileXYLocation; p.X += i; p.Y += j; #if ContinuesMap // ---------------------------- if(p.X < minOfTiles.Width) { p.X += (maxOfTiles.Width + 1); } if(p.X > maxOfTiles.Width) { p.X -= (maxOfTiles.Width + 1); } // ---------------------------- #endif if(p.X >= minOfTiles.Width && p.Y >= minOfTiles.Height && p.X <= maxOfTiles.Width && p.Y <= maxOfTiles.Height) { if(!tileDrawingList.Contains(p)) { tileDrawingList.Add(p); } } } } if(GMaps.Instance.ShuffleTilesOnLoad) { Stuff.Shuffle<Point>(tileDrawingList); } #endregion foreach(Point p in tileDrawingList) { LoadTask task = new LoadTask(p, Zoom); { if(!tileLoadQueue.Contains(task)) { tileLoadQueue.Enqueue(task); } } } } finally { tileDrawingListLock.ReleaseWriterLock(); } #region -- starts loader threads if needed -- #if !PocketPC while(GThreadPool.Count < GThreadPoolSize) #else while(GThreadPool.Count < GThreadPoolSize) #endif { Thread t = new Thread(new ThreadStart(ProcessLoadTask)); { t.Name = "GMap.NET TileLoader: " + GThreadPool.Count; t.IsBackground = true; t.Priority = ThreadPriority.BelowNormal; } GThreadPool.Add(t); Debug.WriteLine("add " + t.Name + " to GThreadPool"); t.Start(); } #endregion lock(LastTileLoadStartEndLock) { LastTileLoadStart = DateTime.Now; Debug.WriteLine("OnTileLoadStart - at zoom " + Zoom + ", time: " + LastTileLoadStart.TimeOfDay); } loadWaitCount = 0; #if !PocketPC Monitor.PulseAll(tileLoadQueue); #else wait.PulseAll(); #endif } if(OnTileLoadStart != null) { OnTileLoadStart(); } }
/// <summary> /// updates map bounds /// </summary> void UpdateBounds() { if(!IsStarted || Provider.Equals(EmptyProvider.Instance)) { return; } updatingBounds = true; tileDrawingListLock.AcquireWriterLock(); try { #region -- find tiles around -- tileDrawingList.Clear(); for(long i = (int)Math.Floor(-sizeOfMapArea.Width * scaleX), countI = (int)Math.Ceiling(sizeOfMapArea.Width * scaleX); i <= countI; i++) { for (long j = (int)Math.Floor(-sizeOfMapArea.Height * scaleY), countJ = (int)Math.Ceiling(sizeOfMapArea.Height * scaleY); j <= countJ; j++) { GPoint p = centerTileXYLocation; p.X += i; p.Y += j; #if ContinuesMap // ---------------------------- if(p.X < minOfTiles.Width) { p.X += (maxOfTiles.Width + 1); } if(p.X > maxOfTiles.Width) { p.X -= (maxOfTiles.Width + 1); } // ---------------------------- #endif if(p.X >= minOfTiles.Width && p.Y >= minOfTiles.Height && p.X <= maxOfTiles.Width && p.Y <= maxOfTiles.Height) { DrawTile dt = new DrawTile() { PosXY = p, PosPixel = new GPoint(p.X * tileRect.Width, p.Y * tileRect.Height), DistanceSqr = (centerTileXYLocation.X - p.X) * (centerTileXYLocation.X - p.X) + (centerTileXYLocation.Y - p.Y) * (centerTileXYLocation.Y - p.Y) }; if(!tileDrawingList.Contains(dt)) { tileDrawingList.Add(dt); } } } } if(GMaps.Instance.ShuffleTilesOnLoad) { Stuff.Shuffle<DrawTile>(tileDrawingList); } else { tileDrawingList.Sort(); } #endregion } finally { tileDrawingListLock.ReleaseWriterLock(); } Monitor.Enter(tileLoadQueue); try { tileDrawingListLock.AcquireReaderLock(); try { foreach(DrawTile p in tileDrawingList) { LoadTask task = new LoadTask(p.PosXY, Zoom); { if(!tileLoadQueue.Contains(task)) { tileLoadQueue.Push(task); } } } } finally { tileDrawingListLock.ReleaseReaderLock(); } #region -- starts loader threads if needed -- lock(GThreadPool) { while(GThreadPool.Count < GThreadPoolSize) { Thread t = new Thread(new ThreadStart(ProcessLoadTask)); { t.Name = "TileLoader: " + GThreadPool.Count; t.IsBackground = true; t.Priority = ThreadPriority.BelowNormal; } GThreadPool.Add(t); Debug.WriteLine("add " + t.Name + " to GThreadPool"); t.Start(); } } #endregion { LastTileLoadStart = DateTime.Now; Debug.WriteLine("OnTileLoadStart - at zoom " + Zoom + ", time: " + LastTileLoadStart.TimeOfDay); } loadWaitCount = 0; Monitor.PulseAll(tileLoadQueue); } finally { Monitor.Exit(tileLoadQueue); } updatingBounds = false; if(OnTileLoadStart != null) { OnTileLoadStart(); } }
void ProcessLoadTask() { bool invalidate = false; LoadTask?task = null; long lastTileLoadTimeMs; bool stop = false; #if !PocketPC Thread ct = Thread.CurrentThread; string ctid = "Thread[" + ct.ManagedThreadId + "]"; #else int ctid = 0; #endif while (!stop) { invalidate = false; task = null; lock (tileLoadQueue) { while (tileLoadQueue.Count == 0) { Debug.WriteLine(ctid + " - Wait " + loadWaitCount + " - " + DateTime.Now.TimeOfDay); if (++loadWaitCount >= GThreadPoolSize) { loadWaitCount = 0; lock (LastInvalidationLock) { LastInvalidation = DateTime.Now; } if (OnNeedInvalidation != null) { OnNeedInvalidation(); } lock (LastTileLoadStartEndLock) { LastTileLoadEnd = DateTime.Now; lastTileLoadTimeMs = (long)(LastTileLoadEnd - LastTileLoadStart).TotalMilliseconds; } #region -- clear stuff-- { GMaps.Instance.kiberCacheLock.AcquireWriterLock(); try { GMaps.Instance.TilesInMemory.RemoveMemoryOverload(); } finally { GMaps.Instance.kiberCacheLock.ReleaseWriterLock(); } tileDrawingListLock.AcquireReaderLock(); try { Matrix.ClearLevelAndPointsNotIn(Zoom, tileDrawingList); } finally { tileDrawingListLock.ReleaseReaderLock(); } } #endregion UpdateGroundResolution(); #if UseGC GC.Collect(); GC.WaitForPendingFinalizers(); GC.Collect(); #endif Debug.WriteLine(ctid + " - OnTileLoadComplete: " + lastTileLoadTimeMs + "ms, MemoryCacheSize: " + GMaps.Instance.MemoryCacheSize + "MB"); if (OnTileLoadComplete != null) { OnTileLoadComplete(lastTileLoadTimeMs); } } #if !PocketPC if (false == Monitor.Wait(tileLoadQueue, WaitForTileLoadThreadTimeout, false)) { stop = true; break; } #else wait.Wait(); #endif } if (!stop || tileLoadQueue.Count > 0) { task = tileLoadQueue.Dequeue(); } } if (task.HasValue) { try { #region -- execute -- var m = Matrix.GetTileWithReadLock(task.Value.Zoom, task.Value.Pos); if (m == null || m.Overlays.Count == 0) { Debug.WriteLine(ctid + " - Fill empty TileMatrix: " + task); Tile t = new Tile(task.Value.Zoom, task.Value.Pos); var layers = GMaps.Instance.GetAllLayersOfType(MapType); foreach (MapType tl in layers) { int retry = 0; do { PureImage img; Exception ex; // tile number inversion(BottomLeft -> TopLeft) for pergo maps if (tl == MapType.PergoTurkeyMap) { img = GMaps.Instance.GetImageFrom(tl, new Point(task.Value.Pos.X, maxOfTiles.Height - task.Value.Pos.Y), task.Value.Zoom, out ex); } else // ok { img = GMaps.Instance.GetImageFrom(tl, task.Value.Pos, task.Value.Zoom, out ex); } if (img != null) { lock (t.Overlays) { t.Overlays.Add(img); } break; } else { if (ex != null) { lock (FailedLoads) { if (!FailedLoads.ContainsKey(task.Value)) { FailedLoads.Add(task.Value, ex); if (OnEmptyTileError != null) { if (!RaiseEmptyTileError) { RaiseEmptyTileError = true; OnEmptyTileError(task.Value.Zoom, task.Value.Pos); } } } } } if (RetryLoadTile > 0) { Debug.WriteLine(ctid + " - ProcessLoadTask: " + task + " -> empty tile, retry " + retry); { Thread.Sleep(1111); } } } }while(++retry < RetryLoadTile); } if (t.Overlays.Count > 0) { Matrix.SetTile(t); } else { t.Clear(); t = null; } layers = null; } #endregion } catch (Exception ex) { Debug.WriteLine(ctid + " - ProcessLoadTask: " + ex.ToString()); } finally { lock (LastInvalidationLock) { invalidate = ((DateTime.Now - LastInvalidation).TotalMilliseconds > 111); if (invalidate) { LastInvalidation = DateTime.Now; } } if (invalidate) { if (OnNeedInvalidation != null) { OnNeedInvalidation(); } } #if DEBUG //else //{ // lock(LastInvalidationLock) // { // Debug.WriteLine(ctid + " - SkipInvalidation, Delta: " + (DateTime.Now - LastInvalidation).TotalMilliseconds + "ms"); // } //} #endif } } } #if !PocketPC lock (tileLoadQueue) { Debug.WriteLine("Quit - " + ct.Name); GThreadPool.Remove(ct); } #endif }