diff --git a/MapControl/Map.cs b/MapControl/Map.cs index 43255cb8..528632bd 100644 --- a/MapControl/Map.cs +++ b/MapControl/Map.cs @@ -567,22 +567,18 @@ namespace MapControl From = Center, To = targetCenter, Duration = TimeSpan.FromSeconds(0.5), - FillBehavior = FillBehavior.Stop, EasingFunction = new QuadraticEase { EasingMode = EasingMode.EaseOut } }; centerAnimation.Completed += CenterAnimationCompleted; - - updateTransform = false; - Center = targetCenter; - updateTransform = true; - BeginAnimation(CenterProperty, centerAnimation); } } private void CenterAnimationCompleted(object sender, EventArgs eventArgs) { + Center = TargetCenter; + BeginAnimation(CenterProperty, null); centerAnimation = null; } @@ -620,22 +616,18 @@ namespace MapControl From = ZoomLevel, To = targetZoomLevel, Duration = TimeSpan.FromSeconds(0.5), - FillBehavior = FillBehavior.Stop, EasingFunction = new QuadraticEase { EasingMode = EasingMode.EaseOut } }; zoomLevelAnimation.Completed += ZoomLevelAnimationCompleted; - - updateTransform = false; - ZoomLevel = targetZoomLevel; - updateTransform = true; - BeginAnimation(ZoomLevelProperty, zoomLevelAnimation); } } private void ZoomLevelAnimationCompleted(object sender, EventArgs eventArgs) { + ZoomLevel = TargetZoomLevel; + BeginAnimation(ZoomLevelProperty, null); zoomLevelAnimation = null; ResetTransformOrigin(); } @@ -683,22 +675,18 @@ namespace MapControl From = Heading, By = delta, Duration = TimeSpan.FromSeconds(0.5), - FillBehavior = FillBehavior.Stop, EasingFunction = new QuadraticEase { EasingMode = EasingMode.EaseOut } }; headingAnimation.Completed += HeadingAnimationCompleted; - - updateTransform = false; - Heading = targetHeading; - updateTransform = true; - BeginAnimation(HeadingProperty, headingAnimation); } } private void HeadingAnimationCompleted(object sender, EventArgs eventArgs) { + Heading = TargetHeading; + BeginAnimation(HeadingProperty, null); headingAnimation = null; } diff --git a/MapControl/MapControl.csproj b/MapControl/MapControl.csproj index 5f6c4dea..d8a3df6c 100644 --- a/MapControl/MapControl.csproj +++ b/MapControl/MapControl.csproj @@ -54,7 +54,6 @@ - @@ -62,6 +61,7 @@ + diff --git a/MapControl/MapInput.cs b/MapControl/MapInput.cs index 6e4af765..2d878918 100644 --- a/MapControl/MapInput.cs +++ b/MapControl/MapInput.cs @@ -10,7 +10,7 @@ namespace MapControl { public partial class Map { - private double mouseWheelZoom = 0.25; + private double mouseWheelZoom = 1d; private Point? mousePosition; public double MouseWheelZoom diff --git a/MapControl/Tile.cs b/MapControl/Tile.cs index 3af625e3..4464c208 100644 --- a/MapControl/Tile.cs +++ b/MapControl/Tile.cs @@ -9,8 +9,6 @@ using System.Windows.Media.Animation; namespace MapControl { - public enum TileLoadState { NotLoaded, Loading, Loaded }; - internal class Tile { private static readonly DoubleAnimation opacityAnimation = new DoubleAnimation(0d, 1d, TimeSpan.FromSeconds(0.5), FillBehavior.Stop); @@ -18,18 +16,16 @@ namespace MapControl public readonly int ZoomLevel; public readonly int X; public readonly int Y; - public readonly Uri Uri; public readonly ImageBrush Brush = new ImageBrush(); - public Tile(TileSource tileSource, int zoomLevel, int x, int y) + public Tile(int zoomLevel, int x, int y) { ZoomLevel = zoomLevel; X = x; Y = y; - Uri = tileSource.GetUri(XIndex, Y, ZoomLevel); } - public TileLoadState LoadState { get; set; } + public Uri Uri { get; set; } public int XIndex { diff --git a/MapControl/TileImageLoader.cs b/MapControl/TileImageLoader.cs index dca4c0c0..433074d4 100644 --- a/MapControl/TileImageLoader.cs +++ b/MapControl/TileImageLoader.cs @@ -28,18 +28,19 @@ namespace MapControl internal int MaxDownloads; internal string TileLayerName; + internal TileSource TileSource; - internal int TilesPending + private bool IsCached { - get { return pendingTiles.Count; } + get { return !string.IsNullOrEmpty(TileCacheFolder) && !string.IsNullOrEmpty(TileLayerName); } } - internal void BeginDownloadTiles(ICollection tiles) + internal void StartDownloadTiles(ICollection tiles) { - ThreadPool.QueueUserWorkItem(BeginDownloadTilesAsync, new List(tiles.Where(t => t.LoadState == TileLoadState.NotLoaded))); + ThreadPool.QueueUserWorkItem(StartDownloadTilesAsync, new List(tiles.Where(t => t.Image == null && t.Uri == null))); } - internal void EndDownloadTiles() + internal void StopDownloadTiles() { lock (pendingTiles) { @@ -47,14 +48,13 @@ namespace MapControl } } - private void BeginDownloadTilesAsync(object newTilesList) + private void StartDownloadTilesAsync(object newTilesList) { List newTiles = (List)newTilesList; lock (pendingTiles) { - if (!string.IsNullOrEmpty(TileCacheFolder) && - !string.IsNullOrEmpty(TileLayerName)) + if (IsCached) { List expiredTiles = new List(newTiles.Count); @@ -65,7 +65,6 @@ namespace MapControl if (image != null) { - tile.LoadState = TileLoadState.Loaded; Dispatcher.BeginInvoke((Action)(() => tile.Image = image)); if (cacheExpired) @@ -95,7 +94,7 @@ namespace MapControl while (pendingTiles.Count > 0 && numDownloads < MaxDownloads) { Tile tile = pendingTiles.Dequeue(); - tile.LoadState = TileLoadState.Loading; + tile.Uri = TileSource.GetUri(tile.XIndex, tile.Y, tile.ZoomLevel); numDownloads++; ThreadPool.QueueUserWorkItem(DownloadTileAsync, tile); @@ -109,16 +108,12 @@ namespace MapControl if (image != null) { - tile.LoadState = TileLoadState.Loaded; Dispatcher.BeginInvoke((Action)(() => tile.Image = image)); } - else - { - tile.LoadState = TileLoadState.NotLoaded; - } lock (pendingTiles) { + tile.Uri = null; numDownloads--; DownloadNextTiles(null); } @@ -134,25 +129,25 @@ namespace MapControl { if (Directory.Exists(tileDir)) { - string[] tilePath = Directory.GetFiles(tileDir, string.Format("{0}.*", tile.Y)); + string tilePath = Directory.GetFiles(tileDir, string.Format("{0}.*", tile.Y)).FirstOrDefault(); - if (tilePath.Length > 0) + if (tilePath != null) { try { - using (Stream fileStream = File.OpenRead(tilePath[0])) + using (Stream fileStream = File.OpenRead(tilePath)) { image = BitmapFrame.Create(fileStream, BitmapCreateOptions.None, BitmapCacheOption.OnLoad); } - expired = File.GetLastWriteTime(tilePath[0]) + TileCacheExpiryAge <= DateTime.Now; + expired = File.GetLastWriteTime(tilePath) + TileCacheExpiryAge <= DateTime.Now; - TraceInformation(expired ? "{0} - Cache Expired" : "{0} - Cached", tile.Uri); + TraceInformation(expired ? "{0} - Cache Expired" : "{0} - Cached", tilePath); } catch (Exception exc) { - TraceWarning("{0} - {1}", tilePath[0], exc.Message); - File.Delete(tilePath[0]); + TraceWarning("{0} - {1}", tilePath, exc.Message); + File.Delete(tilePath); } } } @@ -191,9 +186,7 @@ namespace MapControl string tilePath; - if (!string.IsNullOrEmpty(TileCacheFolder) && - !string.IsNullOrEmpty(TileLayerName) && - (tilePath = TilePath(tile, decoder)) != null) + if (IsCached && (tilePath = TilePath(tile, decoder)) != null) { Directory.CreateDirectory(Path.GetDirectoryName(tilePath)); diff --git a/MapControl/TileLayer.cs b/MapControl/TileLayer.cs index 9f6685b1..69a58ec2 100644 --- a/MapControl/TileLayer.cs +++ b/MapControl/TileLayer.cs @@ -35,7 +35,6 @@ namespace MapControl MaxDownloads = 8; } - public TileSource TileSource { get; set; } public bool HasDarkBackground { get; set; } public int MinZoomLevel { get; set; } public int MaxZoomLevel { get; set; } @@ -46,6 +45,12 @@ namespace MapControl set { tileImageLoader.MaxDownloads = value; } } + public TileSource TileSource + { + get { return tileImageLoader.TileSource; } + set { tileImageLoader.TileSource = value; } + } + public bool IsCached { get { return isCached; } @@ -83,68 +88,51 @@ namespace MapControl this.grid = grid; this.zoomLevel = zoomLevel; - tileImageLoader.EndDownloadTiles(); + tileImageLoader.StopDownloadTiles(); if (VisualParent != null && TileSource != null) { SelectTiles(); RenderTiles(); - tileImageLoader.BeginDownloadTiles(tiles); + tileImageLoader.StartDownloadTiles(tiles); } } public void ClearTiles() { tiles.Clear(); - tileImageLoader.EndDownloadTiles(); - } - - private Int32Rect GetTileGrid(int tileZoomLevel) - { - int tileSize = 1 << (zoomLevel - tileZoomLevel); - int max = (1 << tileZoomLevel) - 1; - int x1 = grid.X / tileSize - 1; - int x2 = (grid.X + grid.Width - 1) / tileSize + 1; - int y1 = Math.Max(0, grid.Y / tileSize - 1); - int y2 = Math.Min(max, (grid.Y + grid.Height - 1) / tileSize + 1); - - return new Int32Rect(x1, y1, x2 - x1 + 1, y2 - y1 + 1); + tileImageLoader.StopDownloadTiles(); } private void SelectTiles() { TileContainer tileContainer = VisualParent as TileContainer; - int maxZoom = Math.Min(zoomLevel, MaxZoomLevel); - int minZoom = maxZoom; + int maxZoomLevel = Math.Min(zoomLevel, MaxZoomLevel); + int minZoomLevel = maxZoomLevel; if (tileContainer != null && tileContainer.TileLayers.IndexOf(this) == 0) { - minZoom = MinZoomLevel; + minZoomLevel = MinZoomLevel; } - tiles.RemoveAll(t => + tiles.RemoveAll(t => t.ZoomLevel < minZoomLevel || t.ZoomLevel > maxZoomLevel); + + for (int z = minZoomLevel; z <= maxZoomLevel; z++) { - if (t.ZoomLevel > maxZoom || t.ZoomLevel < minZoom) + int tileSize = 1 << (zoomLevel - z); + int x1 = grid.X / tileSize; + int x2 = (grid.X + grid.Width - 1) / tileSize; + int y1 = Math.Max(0, grid.Y / tileSize); + int y2 = Math.Min((1 << z) - 1, (grid.Y + grid.Height - 1) / tileSize); + + for (int y = y1; y <= y2; y++) { - return true; - } - - Int32Rect tileGrid = GetTileGrid(t.ZoomLevel); - return t.X < tileGrid.X || t.X >= tileGrid.X + tileGrid.Width || t.Y < tileGrid.Y || t.Y >= tileGrid.Y + tileGrid.Height; - }); - - for (int tileZoomLevel = minZoom; tileZoomLevel <= maxZoom; tileZoomLevel++) - { - Int32Rect tileGrid = GetTileGrid(tileZoomLevel); - - for (int y = tileGrid.Y; y < tileGrid.Y + tileGrid.Height; y++) - { - for (int x = tileGrid.X; x < tileGrid.X + tileGrid.Width; x++) + for (int x = x1; x <= x2; x++) { - if (tiles.Find(t => t.ZoomLevel == tileZoomLevel && t.X == x && t.Y == y) == null) + if (tiles.Find(t => t.ZoomLevel == z && t.X == x && t.Y == y) == null) { - Tile tile = new Tile(TileSource, tileZoomLevel, x, y); + Tile tile = new Tile(z, x, y); Tile equivalent = tiles.Find(t => t.Image != null && t.ZoomLevel == tile.ZoomLevel && t.XIndex == tile.XIndex && t.Y == tile.Y); if (equivalent != null) @@ -156,11 +144,13 @@ namespace MapControl } } } + + tiles.RemoveAll(t => t.ZoomLevel == z && (t.X < x1 || t.X > x2 || t.Y < y1 || t.Y > y2)); } tiles.Sort((t1, t2) => t1.ZoomLevel - t2.ZoomLevel); - //System.Diagnostics.Trace.TraceInformation("{0} Tiles: {1}", tiles.Count, string.Join(", ", tiles.Select(t => t.ZoomLevel.ToString()))); + System.Diagnostics.Trace.TraceInformation("{0} Tiles: {1}", tiles.Count, string.Join(", ", tiles.Select(t => t.ZoomLevel.ToString()))); } private void RenderTiles()