namespace GMap.NET.Internals{
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;
using GMap.NET.Projections;
using System.IO;
#if PocketPC
using Semaphore=OpenNETCF.Threading.Semaphore;
#endif
/// <summary>
/// internal map control core
/// </summary>
internal class Core
{
public PointLatLng currentPosition;
public Point currentPositionPixel;
public Point renderOffset;
public Point centerTileXYLocation;
public Point centerTileXYLocationLast;
public Point dragPoint;
public Point mouseDown;
public Point mouseCurrent;
public Point mouseLastZoom;
public MouseWheelZoomType MouseWheelZoomType = MouseWheelZoomType.MousePositionAndCenter;
public PointLatLng? LastLocationInBounds = null;
public Size sizeOfMapArea;
public Size minOfTiles;
public Size maxOfTiles;
public Rectangle tileRect;
public Point tilePoint;
public Rectangle CurrentRegion;
public readonly TileMatrix Matrix = new TileMatrix();
readonly System.Threading.EventWaitHandle waitOnEmptyTasks = new System.Threading.EventWaitHandle(false, System.Threading.EventResetMode.AutoReset);
public List<Point> tileDrawingList = new List<Point>();
public readonly Queue<LoadTask> tileLoadQueue = new Queue<LoadTask>();
readonly WaitCallback ProcessLoadTaskCallback;
public static readonly string googleCopyright = string.Format("{0} Google - Map data {0} Tele Atlas, Imagery {0} TerraMetrics", DateTime.Today.Year);
public static readonly string openStreetMapCopyright = string.Format(" OpenStreetMap - Map data {0} OpenStreetMap", DateTime.Today.Year);
public static readonly string yahooMapCopyright = string.Format(" Yahoo! Inc. - Map data & Imagery {0} NAVTEQ", DateTime.Today.Year);
public static readonly string virtualEarthCopyright = string.Format("{0} Microsoft Corporation, {0} NAVTEQ, {0} Image courtesy of NASA", DateTime.Today.Year);
public static readonly string arcGisCopyright = string.Format("{0} ESRI - Map data {0} ArcGIS", DateTime.Today.Year);
public static readonly string hnitCopyright = string.Format("{0} Hnit-Baltic - Map data {0} ESRI", DateTime.Today.Year);
internal bool started = false;
int zoom;
internal int maxZoom = 2;
internal int minZoom = 2;
internal int Width;
internal int Height;
internal int pxRes100m; // 100 meters
internal int pxRes1000m; // 1km
internal int pxRes10km; // 10km
internal int pxRes100km; // 100km
internal int pxRes1000km; // 1000km
internal int pxRes5000km; // 5000km
/// <summary>
/// current peojection
/// </summary>
public PureProjection Projection;
/// <summary>
/// is user dragging map
/// </summary>
public bool IsDragging = false;
/// <summary>
/// map zoom
/// </summary>
public int Zoom
{
get
{
return zoom;
}
set
{
if(zoom != value && !IsDragging)
{
zoom = value;
minOfTiles = Projection.GetTileMatrixMinXY(value);
maxOfTiles = Projection.GetTileMatrixMaxXY(value);
CurrentPositionGPixel = Projection.FromLatLngToPixel(CurrentPosition, value);
if(started)
{
lock(tileLoadQueue)
{
tileLoadQueue.Clear();
}
Matrix.ClearLevelsBelove(zoom - LevelsKeepInMemmory);
Matrix.ClearLevelsAbove(zoom + LevelsKeepInMemmory);
lock(FailedLoads)
{
FailedLoads.Clear();
RaiseEmptyTileError = true;
}
GoToCurrentPositionOnZoom();
UpdateBounds();
if(OnMapDrag != null)
{
OnMapDrag();
}
if(OnMapZoomChanged != null)
{
OnMapZoomChanged();
}
if(OnNeedInvalidation != null)
{
OnNeedInvalidation();
}
}
}
}
}
/// <summary>
/// current marker position in pixel coordinates
/// </summary>
public Point CurrentPositionGPixel
{
get
{
return currentPositionPixel;
}
internal set
{
currentPositionPixel = value;
}
}
/// <summary>
/// current marker position
/// </summary>
public PointLatLng CurrentPosition
{
get
{
return currentPosition;
}
set
{
if(!IsDragging)
{
currentPosition = value;
CurrentPositionGPixel = Projection.FromLatLngToPixel(value, Zoom);
if(started)
{
GoToCurrentPosition();
if(OnCurrentPositionChanged != null)
OnCurrentPositionChanged(currentPosition);
}
}
else
{
currentPosition = value;
CurrentPositionGPixel = Projection.FromLatLngToPixel(value, Zoom);
if(started)
{
if(OnCurrentPositionChanged != null)
OnCurrentPositionChanged(currentPosition);
}
}
}
}
internal bool zoomToArea = true;
MapType mapType;
public MapType MapType
{
get
{
return mapType;
}
set
{
if(value != MapType)
{
mapType = value;
GMaps.Instance.AdjustProjection(mapType, ref Projection, out maxZoom);
tileRect = new Rectangle(new Point(0, 0), Projection.TileSize);
minOfTiles = Projection.GetTileMatrixMinXY(Zoom);
maxOfTiles = Projection.GetTileMatrixMaxXY(Zoom);
CurrentPositionGPixel = Projection.FromLatLngToPixel(CurrentPosition, Zoom);
if(started)
{
CancelAsyncTasks();
OnMapSizeChanged(Width, Height);
GoToCurrentPosition();
ReloadMap();
if(OnMapTypeChanged != null)
{
OnMapTypeChanged(value);
}
switch(mapType)
{
case MapType.MapsLT_Map_Hybrid:
case MapType.MapsLT_Map_Labels:
case MapType.MapsLT_Map:
case MapType.MapsLT_OrtoFoto:
{
RectLatLng area = new RectLatLng(56.431489960361, 20.8962105239809, 5.8924169643369, 2.58940626652217);
if(!area.Contains(CurrentPosition))
{
SetZoomToFitRect(area);
zoomToArea = false;
}
}
break;
case MapType.PergoTurkeyMap:
{
RectLatLng area = new RectLatLng(42.5830078125, 25.48828125, 19.05029296875, 6.83349609375);
if(!area.Contains(CurrentPosition))
{
SetZoomToFitRect(area);
zoomToArea = false;
}
}
break;
case MapType.SigPacSpainMap:
{
if(minZoom < 5)
{
minZoom = 5;
}
RectLatLng area = new RectLatLng(43.8741381814747, -9.700927734375, 14.34814453125, 7.8605775962932);
if(!area.Contains(CurrentPosition))
{
SetZoomToFitRect(area);
zoomToArea = false;
}
}
break;
case MapType.GoogleMapKorea:
case MapType.GoogleLabelsKorea:
case MapType.GoogleHybridKorea:
case MapType.GoogleSatelliteKorea:
{
RectLatLng area = new RectLatLng(38.6597777307125, 125.738525390625, 4.02099609375, 4.42072406219614);
if(!area.Contains(CurrentPosition))
{
SetZoomToFitRect(area);
zoomToArea = false;
}
}
break;
default:
{
zoomToArea = true;
}
break;
}
}
}
}
}
/// <summary>
/// sets zoom to max to fit rect
/// </summary>
/// <param name="rect"></param>
/// <returns></returns>
public bool SetZoomToFitRect(RectLatLng rect)
{
int mmaxZoom = GetMaxZoomToFitRect(rect);
if(mmaxZoom > 0)
{
PointLatLng center = new PointLatLng(rect.Lat-(rect.HeightLat/2), rect.Lng+(rect.WidthLng/2));
CurrentPosition = center;
if(mmaxZoom > maxZoom)
{
mmaxZoom = maxZoom;
}
if((int) Zoom != mmaxZoom)
{
Zoom = mmaxZoom;
}
return true;
}
return false;
}
/// <summary>
/// is polygons enabled
/// </summary>
public bool PolygonsEnabled = true;
/// <summary>
/// is routes enabled
/// </summary>
public bool RoutesEnabled = true;
/// <summary>
/// is markers enabled
/// </summary>
public bool MarkersEnabled = true;
/// <summary>
/// can user drag map
/// </summary>
public bool CanDragMap = true;
/// <summary>
/// retry count to get tile
/// </summary>
#if !PocketPC
public int RetryLoadTile = 0;
#else
public int RetryLoadTile = 1;
#endif
/// <summary>
/// how many levels of tiles are staying decompresed in memory
/// </summary>
#if !PocketPC
public int LevelsKeepInMemmory = 5;
#else
public int LevelsKeepInMemmory = 1;
#endif
/// <summary>
/// map render mode
/// </summary>
public RenderMode RenderMode = RenderMode.GDI_PLUS;
/// <summary>
/// occurs when current position is changed
/// </summary>
public event CurrentPositionChanged OnCurrentPositionChanged;
/// <summary>
/// occurs when tile set load is complete
/// </summary>
public event TileLoadComplete OnTileLoadComplete;
/// <summary>
/// occurs when tile set is starting to load
/// </summary>
public event TileLoadStart OnTileLoadStart;
/// <summary>
/// occurs on empty tile displayed
/// </summary>
public event EmptyTileError OnEmptyTileError;
/// <summary>
/// occurs on tile loaded
/// </summary>
public event NeedInvalidation OnNeedInvalidation;
/// <summary>
/// occurs on map drag
/// </summary>
public event MapDrag OnMapDrag;
/// <summary>
/// occurs on map zoom changed
/// </summary>
public event MapZoomChanged OnMapZoomChanged;
/// <summary>
/// occurs on map type changed
/// </summary>
public event MapTypeChanged OnMapTypeChanged;
Semaphore loaderLimit;
#if DEBUG
Stopwatch timer;
#endif
#if !DESIGN
public Core()
{
ProcessLoadTaskCallback = new WaitCallback(ProcessLoadTask);
#if PocketPC
loaderLimit = new Semaphore(2, 2);
#else
loaderLimit = new Semaphore(5, 5);
#endif
#if DEBUG
timer = new Stopwatch();
#endif
}
#endif
// windows forms or wpf
internal string SystemType;
internal static readonly Guid SessionIdGuid = Guid.NewGuid();
internal static readonly Guid CompanyIdGuid = new Guid("3E35F098-CE43-4F82-9E9D-05C8B1046A45");
internal static readonly Guid ApplicationIdGuid = new Guid("797dca7d-fb9f-49a2-87b6-5c9f26bdef25");
internal static volatile bool AnalyticsStartDone = false;
internal static volatile bool AnalyticsStopDone = false;
/// <summary>
/// starts core system
/// </summary>
public void StartSystem()
{
if(!started)
{
started = true;
ReloadMap();
GoToCurrentPosition();
#if !DEBUG
#if !PocketPC
// in case there a few controls in one app
if(!AnalyticsStartDone)
{
AnalyticsStartDone = true;
// send start ping to codeplex Analytics service
ThreadPool.QueueUserWorkItem(new WaitCallback(delegate(object o)
{
try
{
using(Analytics.MessagingServiceV2 s = new Analytics.MessagingServiceV2())
{
if(GMaps.Instance.Proxy != null)
{
s.Proxy = GMaps.Instance.Proxy;
s.PreAuthenticate = true;
}
Analytics.MessageCache info = new Analytics.MessageCache();
{
FillAnalyticsInfo(info);
info.Messages = new Analytics.Message[2];
Analytics.ApplicationLifeCycle alc = new Analytics.ApplicationLifeCycle();
{
alc.Id = Guid.NewGuid();
alc.SessionId = SessionIdGuid;
alc.TimeStampUtc = DateTime.UtcNow;
alc.Event = new GMap.NET.Analytics.EventInformation();
{
alc.Event.Code = "Application.Start";
alc.Event.PrivacySetting = GMap.NET.Analytics.PrivacySettings.SupportOptout;
}
alc.Binary = new Analytics.BinaryInformation();
{
System.Reflection.AssemblyName app = System.Reflection.Assembly.GetEntryAssembly().GetName();
alc.Binary.Name = app.Name;
alc.Binary.Version = app.Version.ToString();
}
alc.Host = new GMap.NET.Analytics.HostInfo();
{
alc.Host.RuntimeVersion = Environment.Version.ToString();
}
alc.Host.OS = new GMap.NET.Analytics.OSInformation();
{
alc.Host.OS.OsName = Environment.OSVersion.VersionString;
}
}
info.Messages[0] = alc;
Analytics.SessionLifeCycle slc = new Analytics.SessionLifeCycle();
{
slc.Id = Guid.NewGuid();
slc.SessionId = SessionIdGuid;
slc.TimeStampUtc = DateTime.UtcNow;
slc.Event = new GMap.NET.Analytics.EventInformation();
{
slc.Event.Code = "Session.Start";
slc.Event.PrivacySetting = GMap.NET.Analytics.PrivacySettings.SupportOptout;
}
}
info.Messages[1] = slc;
}
s.Publish(info);
}
}
catch(Exception ex)
{
Debug.WriteLine("Analytics Start: " + ex.ToString());
}
}));
}
#endif
#endif
}
}
internal void ApplicationExit()
{
#if !DEBUG
#if !PocketPC
// send end ping to codeplex Analytics service
try
{
if(!AnalyticsStopDone)
{
AnalyticsStopDone = true;
using(Analytics.MessagingServiceV2 s = new Analytics.MessagingServiceV2())
{
s.Timeout = 10 * 1000;
if(GMaps.Instance.Proxy != null)
{
s.Proxy = GMaps.Instance.Proxy;
s.PreAuthenticate = true;
}
Analytics.MessageCache info = new Analytics.MessageCache();
{
FillAnalyticsInfo(info);
info.Messages = new Analytics.Message[2];
Analytics.SessionLifeCycle slc = new Analytics.SessionLifeCycle();
{
slc.Id = Guid.NewGuid();
slc.SessionId = SessionIdGuid;
slc.TimeStampUtc = DateTime.UtcNow;
slc.Event = new GMap.NET.Analytics.EventInformation();
{
slc.Event.Code = "Session.Stop";
slc.Event.PrivacySetting = GMap.NET.Analytics.PrivacySettings.SupportOptout;
}
}
info.Messages[0] = slc;
Analytics.ApplicationLifeCycle alc = new Analytics.ApplicationLifeCycle();
{
alc.Id = Guid.NewGuid();
alc.SessionId = SessionIdGuid;
alc.TimeStampUtc = DateTime.UtcNow;
alc.Event = new GMap.NET.Analytics.EventInformation();
{
alc.Event.Code = "Application.Stop";
alc.Event.PrivacySetting = GMap.NET.Analytics.PrivacySettings.SupportOptout;
}
alc.Binary = new Analytics.BinaryInformation();
{
System.Reflection.AssemblyName app = System.Reflection.Assembly.GetEntryAssembly().GetName();
alc.Binary.Name = app.Name;
alc.Binary.Version = app.Version.ToString();
}
alc.Host = new GMap.NET.Analytics.HostInfo();
{
alc.Host.RuntimeVersion = Environment.Version.ToString();
}
alc.Host.OS = new GMap.NET.Analytics.OSInformation();
{
alc.Host.OS.OsName = Environment.OSVersion.VersionString;
}
}
info.Messages[1] = alc;
}
s.Publish(info);
}
}
}
catch(Exception ex)
{
Debug.WriteLine("Analytics Stop: " + ex.ToString());
}
#endif
#endif
}
#if !PocketPC
void FillAnalyticsInfo(Analytics.MessageCache info)
{
info.SchemaVersion = GMap.NET.Analytics.SchemaVersionValue.Item020000;
info.Id = Guid.NewGuid();
info.ApplicationGroupId = SessionIdGuid;
info.Business = new GMap.NET.Analytics.BusinessInformation();
info.Business.CompanyId = CompanyIdGuid;
info.Business.CompanyName = "email@radioman.lt";
info.TimeSentUtc = DateTime.UtcNow;
info.ApiLanguage = ".NET CLR";
info.ApiVersion = "2.1.4.0";
info.Application = new Analytics.ApplicationInformation();
info.Application.Id = ApplicationIdGuid;
info.Application.Name = "GMap.NET";
info.Application.ApplicationType = SystemType;
info.Application.Version = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString();
}
#endif
public void UpdateCenterTileXYLocation()
{
PointLatLng center = FromLocalToLatLng(Width/2, Height/2);
GMap.NET.Point centerPixel = Projection.FromLatLngToPixel(center, Zoom);
centerTileXYLocation = Projection.FromPixelToTileXY(centerPixel);
}
public void OnMapSizeChanged(int width, int height)
{
this.Width = width;
this.Height = height;
sizeOfMapArea.Width = 1 + (Width/Projection.TileSize.Width)/2;
sizeOfMapArea.Height = 1 + (Height/Projection.TileSize.Height)/2;
UpdateCenterTileXYLocation();
if(started)
{
UpdateBounds();
if(OnCurrentPositionChanged != null)
OnCurrentPositionChanged(currentPosition);
}
}
public void OnMapClose()
{
if(waitOnEmptyTasks != null)
{
try
{
waitOnEmptyTasks.Set();
waitOnEmptyTasks.Close();
}
catch
{
}
}
CancelAsyncTasks();
}
/// <summary>
/// sets current position by geocoding
/// </summary>
/// <param name="keys"></param>
/// <returns></returns>
public GeoCoderStatusCode SetCurrentPositionByKeywords(string keys)
{
GeoCoderStatusCode status = GeoCoderStatusCode.Unknow;
PointLatLng? pos = GMaps.Instance.GetLatLngFromGeocoder(keys, out status);
if(pos.HasValue && status == GeoCoderStatusCode.G_GEO_SUCCESS)
{
CurrentPosition = pos.Value;
}
return status;
}
/// <summary>
/// gets current map view top/left coordinate, width in Lng, height in Lat
/// </summary>
/// <returns></returns>
public RectLatLng CurrentViewArea
{
get
{
if(Projection != null)
{
PointLatLng p = Projection.FromPixelToLatLng(-renderOffset.X, -renderOffset.Y, Zoom);
double rlng = Projection.FromPixelToLatLng(-renderOffset.X + Width, -renderOffset.Y, Zoom).Lng;
double blat = Projection.FromPixelToLatLng(-renderOffset.X, -renderOffset.Y + Height, Zoom).Lat;
return RectLatLng.FromLTRB(p.Lng, p.Lat, rlng, blat);
}
return RectLatLng.Empty;
}
}
/// <summary>
/// gets lat/lng from local control coordinates
/// </summary>
/// <param name="x"></param>
/// <param name="y"></param>
/// <returns></returns>
public PointLatLng FromLocalToLatLng(int x, int y)
{
return Projection.FromPixelToLatLng(new Point(x - renderOffset.X, y - renderOffset.Y), Zoom);
}
/// <summary>
/// return local coordinates from lat/lng
/// </summary>
/// <param name="latlng"></param>
/// <returns></returns>
public Point FromLatLngToLocal(PointLatLng latlng)
{
Point pLocal = Projection.FromLatLngToPixel(latlng, Zoom);
pLocal.Offset(renderOffset);
return pLocal;
}
/// <summary>
/// gets max zoom level to fit rectangle
/// </summary>
/// <param name="rect"></param>
/// <returns></returns>
public int GetMaxZoomToFitRect(RectLatLng rect)
{
int zoom = minZoom;
for(int i = zoom; i <= maxZoom; i++)
{
Point p1 = Projection.FromLatLngToPixel(rect.LocationTopLeft, i);
Point p2 = Projection.FromLatLngToPixel(rect.LocationRightBottom, i);
if(((p2.X - p1.X) <= Width+10) && (p2.Y - p1.Y) <= Height+10)
{
zoom = i;
}
else
{
break;
}
}
return zoom;
}
/// <summary>
/// initiates map dragging
/// </summary>
/// <param name="pt"></param>
public void BeginDrag(Point pt)
{
dragPoint.X = pt.X - renderOffset.X;
dragPoint.Y = pt.Y - renderOffset.Y;
IsDragging = true;
}
/// <summary>
/// ends map dragging
/// </summary>
public void EndDrag()
{
IsDragging = false;
if(OnNeedInvalidation != null)
{
OnNeedInvalidation();
}
}
/// <summary>
/// reloads map
/// </summary>
public void ReloadMap()
{
if(started)
{
Debug.WriteLine("------------------");
lock(tileLoadQueue)
{
tileLoadQueue.Clear();
}
Matrix.ClearAllLevels();
lock(FailedLoads)
{
FailedLoads.Clear();
RaiseEmptyTileError = true;
}
if(OnNeedInvalidation != null)
{
OnNeedInvalidation();
}
UpdateBounds();
}
}
/// <summary>
/// moves current position into map center
/// </summary>
public void GoToCurrentPosition()
{
// reset stuff
renderOffset = Point.Empty;
centerTileXYLocationLast = Point.Empty;
dragPoint = Point.Empty;
// goto location
this.Drag(new Point(-(CurrentPositionGPixel.X - Width/2), -(CurrentPositionGPixel.Y - Height/2)));
}
public bool MouseWheelZooming = false;
/// <summary>
/// moves current position into map center
/// </summary>
internal void GoToCurrentPositionOnZoom()
{
// reset stuff
renderOffset = Point.Empty;
centerTileXYLocationLast = Point.Empty;
dragPoint = Point.Empty;
// goto location and centering
if(MouseWheelZooming)
{
if(MouseWheelZoomType != MouseWheelZoomType.MousePositionWithoutCenter)
{
Point pt = new Point(-(CurrentPositionGPixel.X - Width/2), -(CurrentPositionGPixel.Y - Height/2));
renderOffset.X = pt.X - dragPoint.X;
renderOffset.Y = pt.Y - dragPoint.Y;
}
else // without centering
{
renderOffset.X = -CurrentPositionGPixel.X - dragPoint.X;
renderOffset.Y = -CurrentPositionGPixel.Y - dragPoint.Y;
renderOffset.Offset(mouseLastZoom);
}
}
else // use current map center
{
mouseLastZoom = Point.Empty;
Point pt = new Point(-(CurrentPositionGPixel.X - Width/2), -(CurrentPositionGPixel.Y - Height/2));
renderOffset.X = pt.X - dragPoint.X;
renderOffset.Y = pt.Y - dragPoint.Y;
}
UpdateCenterTileXYLocation();
}
/// <summary>
/// darg map by offset in pixels
/// </summary>
/// <param name="offset"></param>
public void DragOffset(Point offset)
{
renderOffset.Offset(offset);
UpdateCenterTileXYLocation();
if(centerTileXYLocation != centerTileXYLocationLast)
{
centerTileXYLocationLast = centerTileXYLocation;
UpdateBounds();
}
{
LastLocationInBounds = CurrentPosition;
CurrentPosition = FromLocalToLatLng((int) Width/2, (int) Height/2);
}
if(OnNeedInvalidation != null)
{
OnNeedInvalidation();
}
if(OnMapDrag != null)
{
OnMapDrag();
}
}
/// <summary>
/// drag map
/// </summary>
/// <param name="pt"></param>
public void Drag(Point pt)
{
renderOffset.X = pt.X - dragPoint.X;
renderOffset.Y = pt.Y - dragPoint.Y;
UpdateCenterTileXYLocation();
if(centerTileXYLocation != centerTileXYLocationLast)
{
centerTileXYLocationLast = centerTileXYLocation;
UpdateBounds();
}
if(IsDragging)
{
LastLocationInBounds = CurrentPosition;
CurrentPosition = FromLocalToLatLng((int) Width/2, (int) Height/2);
}
if(OnNeedInvalidation != null)
{
OnNeedInvalidation();
}
if(OnMapDrag != null)
{
OnMapDrag();
}
}
/// <summary>
/// cancels tile loaders and bounds checker
/// </summary>
public void CancelAsyncTasks()
{
if(started)
{
lock(tileLoadQueue)
{
tileLoadQueue.Clear();
}
}
}
bool RaiseEmptyTileError = false;
internal readonly Dictionary<LoadTask, Exception> FailedLoads = new Dictionary<LoadTask, Exception>();
void ProcessLoadTask(object obj)
{
bool last = false;
LoadTask? task = null;
lock(tileLoadQueue)
{
if(tileLoadQueue.Count > 0)
{
task = tileLoadQueue.Dequeue();
{
last = tileLoadQueue.Count == 0;
//Debug.WriteLine("TileLoadQueue: " + tileLoadQueue.Count);
}
}
}
if(loaderLimit.WaitOne(GMaps.Instance.Timeout, false))
{
if(task.HasValue)
{
try
{
var m = Matrix.GetTileWithReadLock(task.Value.Zoom, task.Value.Pos);
if(m == null || m.Overlays.Count == 0)
{
Debug.WriteLine("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("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;
}
}
catch(Exception ex)
{
Debug.WriteLine("ProcessLoadTask: " + ex.ToString());
}
finally
{
// last buddy cleans stuff ;}
if(last)
{
GMaps.Instance.kiberCacheLock.AcquireWriterLock(-1);
try
{
GMaps.Instance.TilesInMemory.RemoveMemoryOverload();
}
finally
{
GMaps.Instance.kiberCacheLock.ReleaseWriterLock();
}
lock(tileDrawingList)
{
Matrix.ClearLevelAndPointsNotIn(Zoom, tileDrawingList);
}
#if UseGC
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
#endif
#if DEBUG
lock(tileLoadQueue)
{
timer.Stop();
}
Debug.WriteLine("OnTileLoadComplete: " + timer.ElapsedMilliseconds + "ms, MemoryCacheSize: " + GMaps.Instance.MemoryCacheSize + "MB");
Debug.Flush();
#endif
if(OnTileLoadComplete != null)
{
OnTileLoadComplete();
}
}
if(OnNeedInvalidation != null)
{
OnNeedInvalidation();
}
}
}
loaderLimit.Release();
}
}
/// <summary>
/// updates map bounds
/// </summary>
void UpdateBounds()
{
lock(tileDrawingList)
{
FindTilesAround(ref tileDrawingList);
Debug.WriteLine("OnTileLoadStart: " + tileDrawingList.Count + " tiles to load at zoom " + Zoom + ", time: " + DateTime.Now.TimeOfDay);
if(OnTileLoadStart != null)
{
OnTileLoadStart();
}
#if DEBUG
lock(tileLoadQueue)
{
timer.Reset();
timer.Start();
}
#endif
foreach(Point p in tileDrawingList)
{
LoadTask task = new LoadTask(p, Zoom);
{
lock(tileLoadQueue)
{
if(!tileLoadQueue.Contains(task))
{
tileLoadQueue.Enqueue(task);
ThreadPool.QueueUserWorkItem(ProcessLoadTaskCallback);
}
}
}
}
}
UpdateGroundResolution();
}
/// <summary>
/// find tiles around to fill screen
/// </summary>
/// <param name="list"></param>
void FindTilesAround(ref List<Point> list)
{
list.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(!list.Contains(p))
{
list.Add(p);
}
}
}
}
if(GMaps.Instance.ShuffleTilesOnLoad)
{
Stuff.Shuffle<Point>(list);
}
}
/// <summary>
/// updates ground resolution info
/// </summary>
void UpdateGroundResolution()
{
double rez = Projection.GetGroundResolution(Zoom, CurrentPosition.Lat);
pxRes100m = (int) (100.0 / rez); // 100 meters
pxRes1000m = (int) (1000.0 / rez); // 1km
pxRes10km = (int) (10000.0 / rez); // 10km
pxRes100km = (int) (100000.0 / rez); // 100km
pxRes1000km = (int) (1000000.0 / rez); // 1000km
pxRes5000km = (int) (5000000.0 / rez); // 5000km
}
}
}
|