void AddLoadTask(LoadTask t) { if (tileLoadQueue4Tasks == null) { lock (tileLoadQueue4) { if (tileLoadQueue4Tasks == null) { tileLoadQueue4Tasks = new List <Task>(); while (tileLoadQueue4Tasks.Count < GThreadPoolSize) { Debug.WriteLine("creating ProcessLoadTask: " + tileLoadQueue4Tasks.Count); tileLoadQueue4Tasks.Add(Task.Factory.StartNew(delegate() { string ctid = "ProcessLoadTask[" + Thread.CurrentThread.ManagedThreadId + "]"; Thread.CurrentThread.Name = ctid; Debug.WriteLine(ctid + ": started"); do { if (tileLoadQueue4.Count == 0) { Debug.WriteLine(ctid + ": ready"); if (Interlocked.Increment(ref loadWaitCount) >= GThreadPoolSize) { Interlocked.Exchange(ref loadWaitCount, 0); OnLoadComplete(ctid); } } Interlocked.Increment(ref loadOnWaitTake); var task = tileLoadQueue4.Take(); Interlocked.Decrement(ref loadOnWaitTake); ProcessLoadTask(task, ctid); }while (!tileLoadQueue4.IsAddingCompleted); Debug.WriteLine(ctid + ": exit"); }, TaskCreationOptions.LongRunning)); } } } } tileLoadQueue4.Add(t); }
/// <summary> /// updates map bounds /// </summary> void UpdateBounds() { tileDrawingListLock.AcquireWriterLock(); try { FindTilesAround(); lock (tileLoadQueue) { foreach (Point p in tileDrawingList) { LoadTask task = new LoadTask(p, Zoom); { if (!tileLoadQueue.Contains(task)) { tileLoadQueue.Enqueue(task); } } } EnsureLoaderThreads(); } } finally { tileDrawingListLock.ReleaseWriterLock(); if (OnTileLoadStart != null) { OnTileLoadStart(); } LastTileLoadStart = DateTime.Now; Debug.WriteLine("OnTileLoadStart - at zoom " + Zoom + ", time: " + LastTileLoadStart.TimeOfDay); waitForTileLoad.Set(); } }
/// <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> /// 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> /// render map in WPF /// </summary> /// <param name="g"></param> void DrawMap(DrawingContext g) { if(MapProvider == EmptyProvider.Instance || MapProvider == null) { return; } Core.tileDrawingListLock.AcquireReaderLock(); Core.Matrix.EnterReadLock(); try { foreach(var tilePoint in Core.tileDrawingList) { Core.tileRect.Location = tilePoint.PosPixel; Core.tileRect.OffsetNegative(Core.compensationOffset); //if(region.IntersectsWith(Core.tileRect) || IsRotated) { bool found = false; Tile t = Core.Matrix.GetTileWithNoLock(Core.Zoom, tilePoint.PosXY); if(t.NotEmpty) { foreach(GMapImage img in t.Overlays) { if(img != null && img.Img != null) { if(!found) found = true; var imgRect = new Rect(Core.tileRect.X + 0.6, Core.tileRect.Y + 0.6, Core.tileRect.Width + 0.6, Core.tileRect.Height + 0.6); if(!img.IsParent) { g.DrawImage(img.Img, imgRect); } else { // TODO: move calculations to loader thread var geometry = new RectangleGeometry(imgRect); var parentImgRect = new Rect(Core.tileRect.X - Core.tileRect.Width * img.Xoff + 0.6, Core.tileRect.Y - Core.tileRect.Height * img.Yoff + 0.6, Core.tileRect.Width * img.Ix + 0.6, Core.tileRect.Height * img.Ix + 0.6); g.PushClip(geometry); g.DrawImage(img.Img, parentImgRect); g.Pop(); geometry = null; } } } } else if(FillEmptyTiles && MapProvider.Projection is MercatorProjection) { #region -- fill empty tiles -- int zoomOffset = 1; Tile parentTile = Tile.Empty; long Ix = 0; while(!parentTile.NotEmpty && zoomOffset < Core.Zoom && zoomOffset <= LevelsKeepInMemmory) { Ix = (long)Math.Pow(2, zoomOffset); parentTile = Core.Matrix.GetTileWithNoLock(Core.Zoom - zoomOffset++, new GMap.NET.GPoint((int)(tilePoint.PosXY.X / Ix), (int)(tilePoint.PosXY.Y / Ix))); } if(parentTile.NotEmpty) { long Xoff = Math.Abs(tilePoint.PosXY.X - (parentTile.Pos.X * Ix)); long Yoff = Math.Abs(tilePoint.PosXY.Y - (parentTile.Pos.Y * Ix)); 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); // render tile { foreach(GMapImage img in parentTile.Overlays) { if(img != null && img.Img != null && !img.IsParent) { if(!found) found = true; g.PushClip(geometry); g.DrawImage(img.Img, parentImgRect); g.DrawRectangle(SelectedAreaFill, null, geometry.Bounds); g.Pop(); } } } geometry = null; } #endregion } // add text if tile is missing if(!found) { lock(Core.FailedLoads) { var lt = new LoadTask(tilePoint.PosXY, Core.Zoom); if(Core.FailedLoads.ContainsKey(lt)) { g.DrawRectangle(EmptytileBrush, EmptyTileBorders, new Rect(Core.tileRect.X, Core.tileRect.Y, Core.tileRect.Width, Core.tileRect.Height)); var ex = Core.FailedLoads[lt]; FormattedText TileText = new FormattedText("Exception: " + ex.Message, System.Globalization.CultureInfo.CurrentUICulture, FlowDirection.LeftToRight, tileTypeface, 14, Brushes.Red); TileText.MaxTextWidth = Core.tileRect.Width - 11; g.DrawText(TileText, new System.Windows.Point(Core.tileRect.X + 11, Core.tileRect.Y + 11)); g.DrawText(EmptyTileText, new System.Windows.Point(Core.tileRect.X + Core.tileRect.Width / 2 - EmptyTileText.Width / 2, Core.tileRect.Y + Core.tileRect.Height / 2 - EmptyTileText.Height / 2)); } } } if(ShowTileGridLines) { g.DrawRectangle(null, EmptyTileBorders, new Rect(Core.tileRect.X, Core.tileRect.Y, Core.tileRect.Width, Core.tileRect.Height)); if(tilePoint.PosXY == Core.centerTileXYLocation) { FormattedText TileText = new FormattedText("CENTER:" + tilePoint.ToString(), System.Globalization.CultureInfo.CurrentUICulture, FlowDirection.LeftToRight, tileTypeface, 16, Brushes.Red); TileText.MaxTextWidth = Core.tileRect.Width; g.DrawText(TileText, new System.Windows.Point(Core.tileRect.X + Core.tileRect.Width / 2 - EmptyTileText.Width / 2, Core.tileRect.Y + Core.tileRect.Height / 2 - TileText.Height / 2)); } else { FormattedText TileText = new FormattedText("TILE: " + tilePoint.ToString(), System.Globalization.CultureInfo.CurrentUICulture, FlowDirection.LeftToRight, tileTypeface, 16, Brushes.Red); TileText.MaxTextWidth = Core.tileRect.Width; g.DrawText(TileText, new System.Windows.Point(Core.tileRect.X + Core.tileRect.Width / 2 - EmptyTileText.Width / 2, Core.tileRect.Y + Core.tileRect.Height / 2 - TileText.Height / 2)); } } } } } finally { Core.Matrix.LeaveReadLock(); Core.tileDrawingListLock.ReleaseReaderLock(); } }
/// <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(); } }
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(); } } }
/// <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; Monitor.PulseAll(tileLoadQueue); } 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++) { 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 NET46 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 NET46 AddLoadTask(task); #else { if (!TileLoadQueue.Contains(task)) { TileLoadQueue.Push(task); } } #endif } } finally { TileDrawingListLock.ReleaseReaderLock(); } #if !NET46 #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 !NET46 _loadWaitCount = 0; Monitor.PulseAll(TileLoadQueue); } finally { Monitor.Exit(TileLoadQueue); } #endif UpdatingBounds = false; 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(); } Interlocked.Exchange(ref loadWaitCount, 0); tileDrawingListLock.AcquireReaderLock(); try { foreach (DrawTile p in tileDrawingList) { LoadTask task = new LoadTask(p.PosXY, Zoom, this); AddLoadTask(task); } } finally { tileDrawingListLock.ReleaseReaderLock(); } { LastTileLoadStart = DateTime.Now; Debug.WriteLine("OnTileLoadStart - at zoom " + Zoom + ", time: " + LastTileLoadStart.TimeOfDay); } updatingBounds = false; OnTileLoadStart?.Invoke(); }
/// <summary> /// render map in GDI+ /// </summary> /// <param name="g"></param> void DrawMapGDIplus(Graphics g) { if (MapType == NET.MapType.None) { return; } Core.Matrix.EnterReadLock(); Core.tileDrawingListLock.AcquireReaderLock(); try { foreach (var tilePoint in Core.tileDrawingList) { { Core.tileRect.X = tilePoint.X * Core.tileRect.Width; Core.tileRect.Y = tilePoint.Y * Core.tileRect.Height; Core.tileRect.Offset(Core.renderOffset); if (Core.currentRegion.IntersectsWith(Core.tileRect) || IsRotated) { bool found = false; Tile t = Core.Matrix.GetTileWithNoLock(Core.Zoom, tilePoint); if (t != null) { // render tile lock (t.Overlays) { foreach (WindowsFormsImage img in t.Overlays) { if (img != null && img.Img != null) { if (!found) found = true; g.DrawImage(img.Img, Core.tileRect.X, Core.tileRect.Y, Core.tileRectBearing.Width, Core.tileRectBearing.Height); } } } } else // testing smooth zooming { int ZoomOffset = 0; Tile ParentTile = null; int Ix = 0; while (ParentTile == null && (Core.Zoom - ZoomOffset) >= 1 && ZoomOffset <= LevelsKeepInMemmory) { Ix = (int)Math.Pow(2, ++ZoomOffset); ParentTile = Core.Matrix.GetTileWithNoLock(Core.Zoom - ZoomOffset, new Point((int)(tilePoint.X / Ix), (int)(tilePoint.Y / Ix))); } if (ParentTile != null) { int Xoff = Math.Abs(tilePoint.X - (ParentTile.Pos.X * Ix)); int Yoff = Math.Abs(tilePoint.Y - (ParentTile.Pos.Y * Ix)); // render tile lock (ParentTile.Overlays) { foreach (WindowsFormsImage img in ParentTile.Overlays) { if (img != null && img.Img != null) { if (!found) found = true; 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)); System.Drawing.Rectangle dst = new System.Drawing.Rectangle(Core.tileRect.X, Core.tileRect.Y, Core.tileRect.Width, Core.tileRect.Height); g.DrawImage(img.Img, dst, srcRect.X, srcRect.Y, srcRect.Width, srcRect.Height, GraphicsUnit.Pixel, TileFlipXYAttributes); g.FillRectangle(SelectedAreaFill, dst); } } } } } // add text if tile is missing if (!found) { lock (Core.FailedLoads) { var lt = new LoadTask(tilePoint, Core.Zoom); if (Core.FailedLoads.ContainsKey(lt)) { var ex = Core.FailedLoads[lt]; g.FillRectangle(EmptytileBrush, new RectangleF(Core.tileRect.X, Core.tileRect.Y, Core.tileRect.Width, Core.tileRect.Height)); g.DrawString("Exception: " + ex.Message, MissingDataFont, Brushes.Red, new RectangleF(Core.tileRect.X + 11, Core.tileRect.Y + 11, Core.tileRect.Width - 11, Core.tileRect.Height - 11)); g.DrawString(EmptyTileText, MissingDataFont, Brushes.Blue, new RectangleF(Core.tileRect.X, Core.tileRect.Y, Core.tileRect.Width, Core.tileRect.Height), CenterFormat); g.DrawRectangle(EmptyTileBorders, Core.tileRect.X, Core.tileRect.Y, Core.tileRect.Width, Core.tileRect.Height); } } } if (ShowTileGridLines) { g.DrawRectangle(EmptyTileBorders, Core.tileRect.X, Core.tileRect.Y, Core.tileRect.Width, Core.tileRect.Height); { g.DrawString((tilePoint == Core.centerTileXYLocation ? "CENTER: " : "TILE: ") + tilePoint, MissingDataFont, Brushes.Red, new RectangleF(Core.tileRect.X, Core.tileRect.Y, Core.tileRect.Width, Core.tileRect.Height), CenterFormat); } } } } } } finally { Core.tileDrawingListLock.ReleaseReaderLock(); Core.Matrix.LeaveReadLock(); } }
/// <summary> /// render map in WPF /// </summary> /// <param name="g"></param> void DrawMapWPF(DrawingContext g) { if(MapType == NET.MapType.None) { return; } Core.Matrix.EnterReadLock(); Core.tileDrawingListLock.AcquireReaderLock(); try { foreach(var tilePoint in Core.tileDrawingList) { Core.tileRect.X = tilePoint.X * Core.tileRect.Width; Core.tileRect.Y = tilePoint.Y * Core.tileRect.Height; Core.tileRect.Offset(Core.renderOffset); if(region.IntersectsWith(Core.tileRect) || IsRotated) { bool found = false; Tile t = Core.Matrix.GetTileWithNoLock(Core.Zoom, tilePoint); if(t != null) { lock(t.Overlays) { foreach(WindowsPresentationImage img in t.Overlays) { if(img != null && img.Img != null) { if(!found) found = true; g.DrawImage(img.Img, new Rect(Core.tileRect.X + 0.6, Core.tileRect.Y + 0.6, Core.tileRect.Width + 0.6, Core.tileRect.Height + 0.6)); } } } } //else // testing smooth zooming //{ // int ZoomOffset = 0; // Tile ParentTile = null; // int Ix = 0; // while(ParentTile == null && (Core.Zoom - ZoomOffset) >= 1 && ZoomOffset <= LevelsKeepInMemmory) // { // Ix = (int) Math.Pow(2, ++ZoomOffset); // ParentTile = Core.Matrix.GetTileWithNoLock(Core.Zoom - ZoomOffset, new GMap.NET.Point((int) (tilePoint.X / Ix), (int) (tilePoint.Y / Ix))); // } // if(ParentTile != null) // { // int Xoff = Math.Abs(tilePoint.X - (ParentTile.Pos.X * Ix)); // int Yoff = Math.Abs(tilePoint.Y - (ParentTile.Pos.Y * Ix)); // // render tile // lock(ParentTile.Overlays) // { // foreach(WindowsPresentationImage img in ParentTile.Overlays) // { // if(img != null && img.Img != null) // { // if(!found) // found = true; // //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)); // //System.Drawing.Rectangle dst = new System.Drawing.Rectangle(Core.tileRect.X, Core.tileRect.Y, Core.tileRect.Width, Core.tileRect.Height); // //g.DrawImage(img.Img, new Rect( // //g.DrawImage(img.Img, dst, srcRect.X, srcRect.Y, srcRect.Width, srcRect.Height, GraphicsUnit.Pixel, TileFlipXYAttributes); // //g.FillRectangle(SelectedAreaFill, dst); // } // } // } // } //} // add text if tile is missing if(!found) { lock(Core.FailedLoads) { var lt = new LoadTask(tilePoint, Core.Zoom); if(Core.FailedLoads.ContainsKey(lt)) { g.DrawRectangle(EmptytileBrush, EmptyTileBorders, new Rect(Core.tileRect.X, Core.tileRect.Y, Core.tileRect.Width, Core.tileRect.Height)); var ex = Core.FailedLoads[lt]; FormattedText TileText = new FormattedText("Exception: " + ex.Message, System.Globalization.CultureInfo.CurrentUICulture, FlowDirection.LeftToRight, tileTypeface, 14, Brushes.Red); TileText.MaxTextWidth = Core.tileRect.Width - 11; g.DrawText(TileText, new System.Windows.Point(Core.tileRect.X + 11, Core.tileRect.Y + 11)); g.DrawText(EmptyTileText, new System.Windows.Point(Core.tileRect.X + Core.tileRect.Width / 2 - EmptyTileText.Width / 2, Core.tileRect.Y + Core.tileRect.Height / 2 - EmptyTileText.Height / 2)); } } } if(ShowTileGridLines) { g.DrawRectangle(null, EmptyTileBorders, new Rect(Core.tileRect.X, Core.tileRect.Y, Core.tileRect.Width, Core.tileRect.Height)); if(tilePoint == Core.centerTileXYLocation) { FormattedText TileText = new FormattedText("CENTER:" + tilePoint.ToString(), System.Globalization.CultureInfo.CurrentUICulture, FlowDirection.LeftToRight, tileTypeface, 16, Brushes.Red); g.DrawText(TileText, new System.Windows.Point(Core.tileRect.X + Core.tileRect.Width / 2 - EmptyTileText.Width / 2, Core.tileRect.Y + Core.tileRect.Height / 2 - TileText.Height / 2)); } else { FormattedText TileText = new FormattedText("TILE: " + tilePoint.ToString(), System.Globalization.CultureInfo.CurrentUICulture, FlowDirection.LeftToRight, tileTypeface, 16, Brushes.Red); g.DrawText(TileText, new System.Windows.Point(Core.tileRect.X + Core.tileRect.Width / 2 - EmptyTileText.Width / 2, Core.tileRect.Y + Core.tileRect.Height / 2 - TileText.Height / 2)); } } } } } finally { Core.tileDrawingListLock.ReleaseReaderLock(); Core.Matrix.LeaveReadLock(); } }
/// <summary> /// render map in WPF /// </summary> /// <param name="g"></param> void DrawMapWPF(DrawingContext g) { Core.Matrix.EnterReadLock(); Core.tileDrawingListLock.AcquireReaderLock(); try { foreach(var tilePoint in Core.tileDrawingList) { Core.tileRect.X = tilePoint.X * Core.tileRect.Width; Core.tileRect.Y = tilePoint.Y * Core.tileRect.Height; Core.tileRect.Offset(Core.renderOffset); if(region.IntersectsWith(Core.tileRect)) { bool found = false; Tile t = Core.Matrix.GetTileWithNoLock(Core.Zoom, tilePoint); if(t != null) { lock(t.Overlays) { foreach(WindowsPresentationImage img in t.Overlays) { if(img != null && img.Img != null) { if(!found) found = true; g.DrawImage(img.Img, new Rect(Core.tileRect.X+0.6, Core.tileRect.Y+0.6, Core.tileRect.Width+0.6, Core.tileRect.Height+0.6)); } } } } // add text if tile is missing if(!found) { lock(Core.FailedLoads) { var lt = new LoadTask(tilePoint, Core.Zoom); if(Core.FailedLoads.ContainsKey(lt)) { g.DrawRectangle(EmptytileBrush, EmptyTileBorders, new Rect(Core.tileRect.X, Core.tileRect.Y, Core.tileRect.Width, Core.tileRect.Height)); var ex = Core.FailedLoads[lt]; FormattedText TileText = new FormattedText("Exception: " + ex.Message, System.Globalization.CultureInfo.CurrentUICulture, FlowDirection.LeftToRight, tileTypeface, 14, Brushes.Red); TileText.MaxTextWidth = Core.tileRect.Width - 11; g.DrawText(TileText, new System.Windows.Point(Core.tileRect.X + 11, Core.tileRect.Y + 11)); g.DrawText(EmptyTileText, new System.Windows.Point(Core.tileRect.X + Core.tileRect.Width / 2 - EmptyTileText.Width / 2, Core.tileRect.Y + Core.tileRect.Height / 2 - EmptyTileText.Height / 2)); } } } if(ShowTileGridLines) { g.DrawRectangle(null, EmptyTileBorders, new Rect(Core.tileRect.X, Core.tileRect.Y, Core.tileRect.Width, Core.tileRect.Height)); if(tilePoint == Core.centerTileXYLocation) { FormattedText TileText = new FormattedText("CENTER:" + tilePoint.ToString(), System.Globalization.CultureInfo.CurrentUICulture, FlowDirection.LeftToRight, tileTypeface, 16, Brushes.Red); g.DrawText(TileText, new System.Windows.Point(Core.tileRect.X + Core.tileRect.Width / 2 - EmptyTileText.Width / 2, Core.tileRect.Y + Core.tileRect.Height / 2 - TileText.Height / 2)); } else { FormattedText TileText = new FormattedText("TILE: " + tilePoint.ToString(), System.Globalization.CultureInfo.CurrentUICulture, FlowDirection.LeftToRight, tileTypeface, 16, Brushes.Red); g.DrawText(TileText, new System.Windows.Point(Core.tileRect.X + Core.tileRect.Width / 2 - EmptyTileText.Width / 2, Core.tileRect.Y + Core.tileRect.Height / 2 - TileText.Height / 2)); } } } } } finally { Core.tileDrawingListLock.ReleaseReaderLock(); Core.Matrix.LeaveReadLock(); } }
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 AddLoadTask(LoadTask t) { if (tileLoadQueue4Tasks == null) { lock (tileLoadQueue4) { if (tileLoadQueue4Tasks == null) { tileLoadQueue4Tasks = new List<Task>(); while (tileLoadQueue4Tasks.Count < GThreadPoolSize) { Debug.WriteLine("creating ProcessLoadTask: " + tileLoadQueue4Tasks.Count); tileLoadQueue4Tasks.Add(Task.Factory.StartNew(delegate () { string ctid = "ProcessLoadTask[" + Thread.CurrentThread.ManagedThreadId + "]"; Thread.CurrentThread.Name = ctid; Debug.WriteLine(ctid + ": started"); do { if (tileLoadQueue4.Count == 0) { Debug.WriteLine(ctid + ": ready"); if (Interlocked.Increment(ref loadWaitCount) >= GThreadPoolSize) { Interlocked.Exchange(ref loadWaitCount, 0); OnLoadComplete(ctid); } } ProcessLoadTask(tileLoadQueue4.Take(), ctid); } while (!tileLoadQueue4.IsAddingCompleted); Debug.WriteLine(ctid + ": exit"); }, TaskCreationOptions.LongRunning)); } } } } tileLoadQueue4.Add(t); }