diff --git a/Caching/FileDbCache/Properties/AssemblyInfo.cs b/Caching/FileDbCache/Properties/AssemblyInfo.cs index b341c093..20cac65e 100644 --- a/Caching/FileDbCache/Properties/AssemblyInfo.cs +++ b/Caching/FileDbCache/Properties/AssemblyInfo.cs @@ -7,8 +7,8 @@ using System.Runtime.InteropServices; [assembly: AssemblyCompany("Clemens Fischer")] [assembly: AssemblyCopyright("Copyright © 2014 Clemens Fischer")] [assembly: AssemblyTrademark("")] -[assembly: AssemblyVersion("2.0.0")] -[assembly: AssemblyFileVersion("2.0.0")] +[assembly: AssemblyVersion("2.1.0")] +[assembly: AssemblyFileVersion("2.1.0")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCulture("")] [assembly: ComVisible(false)] diff --git a/Caching/ImageFileCache/Properties/AssemblyInfo.cs b/Caching/ImageFileCache/Properties/AssemblyInfo.cs index a43f045b..97575eaf 100644 --- a/Caching/ImageFileCache/Properties/AssemblyInfo.cs +++ b/Caching/ImageFileCache/Properties/AssemblyInfo.cs @@ -7,8 +7,8 @@ using System.Runtime.InteropServices; [assembly: AssemblyCompany("Clemens Fischer")] [assembly: AssemblyCopyright("Copyright © 2014 Clemens Fischer")] [assembly: AssemblyTrademark("")] -[assembly: AssemblyVersion("2.0.0")] -[assembly: AssemblyFileVersion("2.0.0")] +[assembly: AssemblyVersion("2.1.0")] +[assembly: AssemblyFileVersion("2.1.0")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCulture("")] [assembly: ComVisible(false)] diff --git a/MapControl/GlyphRunText.cs b/MapControl/GlyphRunText.cs index ec04a8a9..1c55a5b9 100644 --- a/MapControl/GlyphRunText.cs +++ b/MapControl/GlyphRunText.cs @@ -38,16 +38,15 @@ namespace MapControl public static void DrawGlyphRun(this DrawingContext drawingContext, Brush foreground, GlyphRun glyphRun, Point position, HorizontalAlignment horizontalAlignment, VerticalAlignment verticalAlignment) { - var bbox = glyphRun.ComputeInkBoundingBox(); - var transform = new TranslateTransform(position.X - bbox.X, position.Y - bbox.Y); + var boundingBox = glyphRun.ComputeInkBoundingBox(); switch (horizontalAlignment) { case HorizontalAlignment.Center: - transform.X -= bbox.Width / 2d; + position.X -= boundingBox.Width / 2d; break; case HorizontalAlignment.Right: - transform.X -= bbox.Width; + position.X -= boundingBox.Width; break; default: break; @@ -56,16 +55,16 @@ namespace MapControl switch (verticalAlignment) { case VerticalAlignment.Center: - transform.Y -= bbox.Height / 2d; + position.Y -= boundingBox.Height / 2d; break; case VerticalAlignment.Bottom: - transform.Y -= bbox.Height; + position.Y -= boundingBox.Height; break; default: break; } - drawingContext.PushTransform(transform); + drawingContext.PushTransform(new TranslateTransform(position.X - boundingBox.X, position.Y - boundingBox.Y)); drawingContext.DrawGlyphRun(foreground, glyphRun); drawingContext.Pop(); } diff --git a/MapControl/IObjectCache.WinRT.cs b/MapControl/IObjectCache.WinRT.cs new file mode 100644 index 00000000..ed1844f5 --- /dev/null +++ b/MapControl/IObjectCache.WinRT.cs @@ -0,0 +1,14 @@ +// XAML Map Control - http://xamlmapcontrol.codeplex.com/ +// Copyright © 2014 Clemens Fischer +// Licensed under the Microsoft Public License (Ms-PL) + +using System.Threading.Tasks; + +namespace MapControl +{ + public interface IObjectCache + { + Task GetAsync(string key); + Task SetAsync(string key, object value); + } +} diff --git a/MapControl/ImageFileCache.WinRT.cs b/MapControl/ImageFileCache.WinRT.cs new file mode 100644 index 00000000..500d9473 --- /dev/null +++ b/MapControl/ImageFileCache.WinRT.cs @@ -0,0 +1,62 @@ +// XAML Map Control - http://xamlmapcontrol.codeplex.com/ +// Copyright © 2014 Clemens Fischer +// Licensed under the Microsoft Public License (Ms-PL) + +using System; +using System.Diagnostics; +using System.IO; +using System.Threading.Tasks; +using Windows.Storage; +using Windows.Storage.Streams; + +namespace MapControl +{ + public class ImageFileCache : IObjectCache + { + private readonly IStorageFolder rootFolder; + + public ImageFileCache() + { + rootFolder = ApplicationData.Current.TemporaryFolder; + } + + public ImageFileCache(IStorageFolder folder) + { + rootFolder = folder; + } + + public async Task GetAsync(string key) + { + try + { + return await PathIO.ReadBufferAsync(Path.Combine(rootFolder.Path, key)); + } + catch + { + return null; + } + } + + public async Task SetAsync(string key, object value) + { + try + { + var buffer = (IBuffer)value; + var names = key.Split('\\'); + var folder = rootFolder; + + for (int i = 0; i < names.Length - 1; i++) + { + folder = await folder.CreateFolderAsync(names[i], CreationCollisionOption.OpenIfExists); + } + + var file = await folder.CreateFileAsync(names[names.Length - 1], CreationCollisionOption.ReplaceExisting); + await FileIO.WriteBufferAsync(file, buffer); + } + catch (Exception ex) + { + Debug.WriteLine(ex.Message); + } + } + } +} diff --git a/MapControl/Location.cs b/MapControl/Location.cs index 47f38fb9..23265abc 100644 --- a/MapControl/Location.cs +++ b/MapControl/Location.cs @@ -10,7 +10,7 @@ namespace MapControl /// /// A geographic location with latitude and longitude values in degrees. /// - public partial class Location + public partial class Location : IEquatable { private double latitude; private double longitude; @@ -37,6 +37,23 @@ namespace MapControl set { longitude = value; } } + public bool Equals(Location location) + { + return location != null + && location.latitude == latitude + && location.longitude == longitude; + } + + public override bool Equals(object obj) + { + return Equals(obj as Location); + } + + public override int GetHashCode() + { + return latitude.GetHashCode() ^ longitude.GetHashCode(); + } + public override string ToString() { return string.Format(CultureInfo.InvariantCulture, "{0:F5},{1:F5}", latitude, longitude); diff --git a/MapControl/MapBase.cs b/MapControl/MapBase.cs index de840b01..d2e91e51 100644 --- a/MapControl/MapBase.cs +++ b/MapControl/MapBase.cs @@ -579,7 +579,7 @@ namespace MapControl { AdjustCenterProperty(TargetCenterProperty, ref targetCenter); - if (targetCenter.Latitude != Center.Latitude || targetCenter.Longitude != Center.Longitude) + if (!targetCenter.Equals(Center)) { if (centerAnimation != null) { diff --git a/MapControl/MapControl.Silverlight.csproj b/MapControl/MapControl.Silverlight.csproj index 864aa374..924b39b3 100644 --- a/MapControl/MapControl.Silverlight.csproj +++ b/MapControl/MapControl.Silverlight.csproj @@ -106,7 +106,7 @@ - + diff --git a/MapControl/MapGraticule.Silverlight.WinRT.cs b/MapControl/MapGraticule.Silverlight.WinRT.cs index 8ae43dd2..db47839f 100644 --- a/MapControl/MapGraticule.Silverlight.WinRT.cs +++ b/MapControl/MapGraticule.Silverlight.WinRT.cs @@ -3,10 +3,10 @@ // Licensed under the Microsoft Public License (Ms-PL) using System; -using System.Collections.Generic; using System.Linq; #if WINDOWS_RUNTIME using Windows.Foundation; +using Windows.UI; using Windows.UI.Xaml; using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Media; @@ -31,7 +31,7 @@ namespace MapControl public MapGraticule() { IsHitTestVisible = false; - StrokeThickness = 0.5; + Stroke = new SolidColorBrush(Color.FromArgb(127, 0, 0, 0)); path = new Path { @@ -55,7 +55,6 @@ namespace MapControl protected override void OnViewportChanged() { - var geometry = (PathGeometry)path.Data; var bounds = ParentMap.ViewportTransform.Inverse.TransformBounds(new Rect(new Point(), ParentMap.RenderSize)); var start = ParentMap.MapTransform.Transform(new Point(bounds.X, bounds.Y)); var end = ParentMap.MapTransform.Transform(new Point(bounds.X + bounds.Width, bounds.Y + bounds.Height)); @@ -88,28 +87,22 @@ namespace MapControl graticuleStart = lineStart; graticuleEnd = lineEnd; + var geometry = (PathGeometry)path.Data; geometry.Figures.Clear(); geometry.Transform = ParentMap.ViewportTransform; - var latLocations = new List((int)((end.Latitude - labelStart.Latitude) / spacing) + 1); - for (var lat = labelStart.Latitude; lat <= end.Latitude; lat += spacing) { - var location = new Location(lat, lineStart.Longitude); - latLocations.Add(location); - var figure = new PathFigure { - StartPoint = ParentMap.MapTransform.Transform(location), + StartPoint = ParentMap.MapTransform.Transform(new Location(lat, lineStart.Longitude)), IsClosed = false, IsFilled = false }; - location.Longitude = lineEnd.Longitude; - figure.Segments.Add(new LineSegment { - Point = ParentMap.MapTransform.Transform(location), + Point = ParentMap.MapTransform.Transform(new Location(lat, lineEnd.Longitude)), }); geometry.Figures.Add(figure); @@ -134,14 +127,11 @@ namespace MapControl var childIndex = 1; // 0 for Path var format = spacing < 1d ? "{0} {1}°{2:00}'" : "{0} {1}°"; - var measureSize = new Size(double.PositiveInfinity, double.PositiveInfinity); - foreach (var location in latLocations) + for (var lat = labelStart.Latitude; lat <= end.Latitude; lat += spacing) { for (var lon = labelStart.Longitude; lon <= end.Longitude; lon += spacing) { - location.Longitude = lon; - TextBlock label; if (childIndex < Children.Count) @@ -150,9 +140,14 @@ namespace MapControl } else { + var renderTransform = new TransformGroup(); + renderTransform.Children.Add(new TranslateTransform()); + renderTransform.Children.Add(ParentMap.RotateTransform); + renderTransform.Children.Add(new TranslateTransform()); + label = new TextBlock { - RenderTransform = new TransformGroup() + RenderTransform = renderTransform }; label.SetBinding(TextBlock.ForegroundProperty, new Binding @@ -175,30 +170,13 @@ namespace MapControl label.FontStyle = FontStyle; label.FontStretch = FontStretch; label.FontWeight = FontWeight; + label.Text = string.Format("{0}\n{1}", CoordinateString(lat, format, "NS"), CoordinateString(Location.NormalizeLongitude(lon), format, "EW")); + label.Tag = new Location(lat, lon); + label.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity)); - label.Text = string.Format("{0}\n{1}", - CoordinateString(location.Latitude, format, "NS"), - CoordinateString(Location.NormalizeLongitude(location.Longitude), format, "EW")); - - label.Measure(measureSize); - - var transformGroup = (TransformGroup)label.RenderTransform; - - if (transformGroup.Children.Count == 0) - { - transformGroup.Children.Add(new TranslateTransform()); - transformGroup.Children.Add(ParentMap.RotateTransform); - transformGroup.Children.Add(new TranslateTransform()); - } - - var translateTransform = (TranslateTransform)transformGroup.Children[0]; + var translateTransform = (TranslateTransform)((TransformGroup)label.RenderTransform).Children[0]; translateTransform.X = StrokeThickness / 2d + 2d; translateTransform.Y = -label.DesiredSize.Height / 2d; - - var viewportPosition = ParentMap.LocationToViewportPoint(location); - translateTransform = (TranslateTransform)transformGroup.Children[2]; - translateTransform.X = viewportPosition.X; - translateTransform.Y = viewportPosition.Y; } } @@ -208,6 +186,18 @@ namespace MapControl } } + // don't use MapPanel.Location because labels may be at more than 180° distance from map center + + for (int i = 1; i < Children.Count; i++) + { + var label = (TextBlock)Children[i]; + var location = (Location)label.Tag; + var viewportTransform = (TranslateTransform)((TransformGroup)label.RenderTransform).Children[2]; + var viewportPosition = ParentMap.LocationToViewportPoint(location); + viewportTransform.X = viewportPosition.X; + viewportTransform.Y = viewportPosition.Y; + } + base.OnViewportChanged(); } } diff --git a/MapControl/MapGraticule.cs b/MapControl/MapGraticule.cs index c5003d9a..e75f439a 100644 --- a/MapControl/MapGraticule.cs +++ b/MapControl/MapGraticule.cs @@ -2,6 +2,7 @@ // Copyright © 2014 Clemens Fischer // Licensed under the Microsoft Public License (Ms-PL) +using System; #if WINDOWS_RUNTIME using Windows.UI.Xaml; #else @@ -43,7 +44,7 @@ namespace MapControl hemisphere = hemispheres[1]; } - var minutes = (int)(value * 60d + 0.5); + var minutes = (int)Math.Round(value * 60d); return string.Format(format, hemisphere, minutes / 60, (double)(minutes % 60)); } diff --git a/MapControl/Properties/AssemblyInfo.cs b/MapControl/Properties/AssemblyInfo.cs index 1eda3a64..e25ef18a 100644 --- a/MapControl/Properties/AssemblyInfo.cs +++ b/MapControl/Properties/AssemblyInfo.cs @@ -14,8 +14,8 @@ using System.Windows; [assembly: AssemblyCompany("Clemens Fischer")] [assembly: AssemblyCopyright("Copyright © 2014 Clemens Fischer")] [assembly: AssemblyTrademark("")] -[assembly: AssemblyVersion("2.0.0")] -[assembly: AssemblyFileVersion("2.0.0")] +[assembly: AssemblyVersion("2.1.0")] +[assembly: AssemblyFileVersion("2.1.0")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCulture("")] [assembly: ComVisible(false)] diff --git a/MapControl/TileContainer.Silverlight.WinRT.cs b/MapControl/TileContainer.Silverlight.WinRT.cs index 96372f2c..c5a4a44c 100644 --- a/MapControl/TileContainer.Silverlight.WinRT.cs +++ b/MapControl/TileContainer.Silverlight.WinRT.cs @@ -13,12 +13,6 @@ namespace MapControl { internal partial class TileContainer { - private Matrix GetViewportTransformMatrix(double scale, double offsetX, double offsetY) - { - return new Matrix(scale, 0d, 0d, -scale, offsetX, offsetY) - .RotateAt(rotation, viewportOrigin.X, viewportOrigin.Y); - } - private Matrix GetTileIndexMatrix(int numTiles) { var scale = (double)numTiles / 360d; @@ -29,6 +23,13 @@ namespace MapControl .Scale(scale, -scale); // map coordinates to tile indices } + private void UpdateViewportTransform(double scale, double offsetX, double offsetY) + { + ViewportTransform.Matrix = + new Matrix(scale, 0d, 0d, -scale, offsetX, offsetY) + .RotateAt(rotation, viewportOrigin.X, viewportOrigin.Y); + } + /// /// Sets a RenderTransform with origin at tileGrid.X and tileGrid.Y to minimize rounding errors. /// diff --git a/MapControl/TileContainer.WPF.cs b/MapControl/TileContainer.WPF.cs index 9dd5a348..c5174c69 100644 --- a/MapControl/TileContainer.WPF.cs +++ b/MapControl/TileContainer.WPF.cs @@ -9,14 +9,6 @@ namespace MapControl { internal partial class TileContainer { - private Matrix GetViewportTransformMatrix(double scale, double offsetX, double offsetY) - { - var transform = new Matrix(scale, 0d, 0d, -scale, offsetX, offsetY); - transform.RotateAt(rotation, viewportOrigin.X, viewportOrigin.Y); - - return transform; - } - private Matrix GetTileIndexMatrix(int numTiles) { var scale = (double)numTiles / 360d; @@ -28,6 +20,14 @@ namespace MapControl return transform; } + private void UpdateViewportTransform(double scale, double offsetX, double offsetY) + { + var transform = new Matrix(scale, 0d, 0d, -scale, offsetX, offsetY); + transform.RotateAt(rotation, viewportOrigin.X, viewportOrigin.Y); + + ViewportTransform.Matrix = transform; + } + /// /// Sets a RenderTransform with origin at tileGrid.X and tileGrid.Y to minimize rounding errors. /// diff --git a/MapControl/TileContainer.cs b/MapControl/TileContainer.cs index e4080181..cc4e47b7 100644 --- a/MapControl/TileContainer.cs +++ b/MapControl/TileContainer.cs @@ -22,7 +22,7 @@ namespace MapControl // relative scaled tile size ranges from 0.75 to 1.5 (192 to 384 pixels) private static double zoomLevelSwitchDelta = -Math.Log(0.75, 2d); - internal static TimeSpan UpdateInterval = TimeSpan.FromSeconds(0.5); + public static TimeSpan UpdateInterval = TimeSpan.FromSeconds(0.5); private readonly DispatcherTimer updateTimer; private Size viewportSize; @@ -102,7 +102,7 @@ namespace MapControl var transformOffsetX = viewportOrigin.X - mapOrigin.X * scale; var transformOffsetY = viewportOrigin.Y + mapOrigin.Y * scale; - ViewportTransform.Matrix = GetViewportTransformMatrix(scale, transformOffsetX, transformOffsetY); + UpdateViewportTransform(scale, transformOffsetX, transformOffsetY); tileLayerOffset.X = transformOffsetX - 180d * scale; tileLayerOffset.Y = transformOffsetY - 180d * scale; diff --git a/MapControl/TileImageLoader.Silverlight.WinRT.cs b/MapControl/TileImageLoader.Silverlight.WinRT.cs deleted file mode 100644 index 9bc58a05..00000000 --- a/MapControl/TileImageLoader.Silverlight.WinRT.cs +++ /dev/null @@ -1,64 +0,0 @@ -// XAML Map Control - http://xamlmapcontrol.codeplex.com/ -// Copyright © 2014 Clemens Fischer -// Licensed under the Microsoft Public License (Ms-PL) - -using System; -using System.Collections.Generic; -using System.Diagnostics; -#if WINDOWS_RUNTIME -using Windows.UI.Xaml.Media; -using Windows.UI.Xaml.Media.Imaging; -#else -using System.Windows.Media; -using System.Windows.Media.Imaging; -#endif - -namespace MapControl -{ - /// - /// Loads map tile images. - /// - internal class TileImageLoader - { - internal void BeginGetTiles(TileLayer tileLayer, IEnumerable tiles) - { - var imageTileSource = tileLayer.TileSource as ImageTileSource; - - if (imageTileSource != null) - { - foreach (var tile in tiles) - { - try - { - var image = imageTileSource.LoadImage(tile.XIndex, tile.Y, tile.ZoomLevel); - tile.SetImageSource(image, tileLayer.AnimateTileOpacity); - } - catch (Exception ex) - { - Debug.WriteLine("Loading tile image failed: {0}", ex.Message); - } - } - } - else - { - foreach (var tile in tiles) - { - try - { - var uri = tileLayer.TileSource.GetUri(tile.XIndex, tile.Y, tile.ZoomLevel); - var image = uri != null ? new BitmapImage(uri) : null; - tile.SetImageSource(image, tileLayer.AnimateTileOpacity); - } - catch (Exception ex) - { - Debug.WriteLine("Creating tile image failed: {0}", ex.Message); - } - } - } - } - - public void CancelGetTiles() - { - } - } -} diff --git a/MapControl/TileImageLoader.Silverlight.cs b/MapControl/TileImageLoader.Silverlight.cs new file mode 100644 index 00000000..37e06286 --- /dev/null +++ b/MapControl/TileImageLoader.Silverlight.cs @@ -0,0 +1,55 @@ +// XAML Map Control - http://xamlmapcontrol.codeplex.com/ +// Copyright © 2014 Clemens Fischer +// Licensed under the Microsoft Public License (Ms-PL) + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Windows.Media; +using System.Windows.Media.Imaging; + +namespace MapControl +{ + /// + /// Loads map tile images. + /// + internal class TileImageLoader + { + internal void BeginGetTiles(TileLayer tileLayer, IEnumerable tiles) + { + var imageTileSource = tileLayer.TileSource as ImageTileSource; + + foreach (var tile in tiles) + { + try + { + ImageSource image = null; + + if (imageTileSource != null) + { + image = imageTileSource.LoadImage(tile.XIndex, tile.Y, tile.ZoomLevel); + } + else + { + var uri = tileLayer.TileSource.GetUri(tile.XIndex, tile.Y, tile.ZoomLevel); + + if (uri != null) + { + image = new BitmapImage(uri); + } + } + + tile.SetImageSource(image, tileLayer.AnimateTileOpacity); + } + catch (Exception ex) + { + Debug.WriteLine("Loading tile image failed: {0}", ex.Message); + } + } + } + + internal void CancelGetTiles() + { + } + } +} diff --git a/MapControl/TileImageLoader.WinRT.cs b/MapControl/TileImageLoader.WinRT.cs new file mode 100644 index 00000000..9bf00dd8 --- /dev/null +++ b/MapControl/TileImageLoader.WinRT.cs @@ -0,0 +1,196 @@ +// XAML Map Control - http://xamlmapcontrol.codeplex.com/ +// Copyright © 2014 Clemens Fischer +// Licensed under the Microsoft Public License (Ms-PL) + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Threading.Tasks; +using Windows.Foundation; +using Windows.Storage.Streams; +using Windows.UI.Core; +using Windows.UI.Xaml.Media; +using Windows.UI.Xaml.Media.Imaging; +using Windows.Web.Http; +using Windows.Web.Http.Filters; + +namespace MapControl +{ + /// + /// Loads map tile images. + /// + public class TileImageLoader + { + public static IObjectCache Cache { get; set; } + + private HttpClient httpClient; + + internal void BeginGetTiles(TileLayer tileLayer, IEnumerable tiles) + { + var imageTileSource = tileLayer.TileSource as ImageTileSource; + + foreach (var tile in tiles) + { + try + { + ImageSource image = null; + + if (imageTileSource != null) + { + image = imageTileSource.LoadImage(tile.XIndex, tile.Y, tile.ZoomLevel); + } + else + { + var uri = tileLayer.TileSource.GetUri(tile.XIndex, tile.Y, tile.ZoomLevel); + + if (uri != null) + { + if (Cache == null || string.IsNullOrEmpty(tileLayer.SourceName)) + { + image = new BitmapImage(uri); + } + else + { + var bitmap = new BitmapImage(); + image = bitmap; + + Task.Run(async () => await LoadCachedImage(tileLayer, tile, uri, bitmap)); + } + } + } + + tile.SetImageSource(image, tileLayer.AnimateTileOpacity); + } + catch (Exception ex) + { + Debug.WriteLine("Loading tile image failed: {0}", ex.Message); + } + } + } + + internal void CancelGetTiles() + { + } + + private async Task LoadCachedImage(TileLayer tileLayer, Tile tile, Uri uri, BitmapImage bitmap) + { + var cacheKey = string.Format(@"{0}\{1}\{2}\{3}{4}", + tileLayer.SourceName, tile.ZoomLevel, tile.XIndex, tile.Y, Path.GetExtension(uri.LocalPath)); + + var buffer = await Cache.GetAsync(cacheKey) as IBuffer; + + if (buffer != null) + { + await LoadImageFromBuffer(buffer, bitmap); + //Debug.WriteLine("Loaded cached image {0}", cacheKey); + } + else + { + DownloadAndCacheImage(uri, bitmap, cacheKey); + } + } + + private async Task LoadImageFromBuffer(IBuffer buffer, BitmapImage bitmap) + { + using (var stream = new InMemoryRandomAccessStream()) + { + await stream.WriteAsync(buffer); + await stream.FlushAsync(); + stream.Seek(0); + + await bitmap.Dispatcher.RunAsync(CoreDispatcherPriority.Low, async () => + { + try + { + await bitmap.SetSourceAsync(stream); + } + catch (Exception ex) + { + Debug.WriteLine(ex.Message); + } + }); + } + } + + private void DownloadAndCacheImage(Uri uri, BitmapImage bitmap, string cacheKey) + { + try + { + if (httpClient == null) + { + var filter = new HttpBaseProtocolFilter(); + filter.AllowAutoRedirect = false; + filter.CacheControl.ReadBehavior = HttpCacheReadBehavior.Default; + filter.CacheControl.WriteBehavior = HttpCacheWriteBehavior.NoCache; + + httpClient = new HttpClient(filter); + } + + httpClient.GetAsync(uri).Completed = async (request, status) => + { + if (status == AsyncStatus.Completed) + { + using (var response = request.GetResults()) + { + await LoadImageFromHttpResponse(response, bitmap, cacheKey); + } + } + else + { + Debug.WriteLine("{0}: {1}", uri, request.ErrorCode != null ? request.ErrorCode.Message : status.ToString()); + } + }; + } + catch (Exception ex) + { + Debug.WriteLine("{0}: {1}", uri, ex.Message); + } + } + + private async Task LoadImageFromHttpResponse(HttpResponseMessage response, BitmapImage bitmap, string cacheKey) + { + if (response.IsSuccessStatusCode) + { + var stream = new InMemoryRandomAccessStream(); + + using (var content = response.Content) + { + await content.WriteToStreamAsync(stream); + } + + await stream.FlushAsync(); + stream.Seek(0); + + await bitmap.Dispatcher.RunAsync(CoreDispatcherPriority.Low, async () => + { + try + { + await bitmap.SetSourceAsync(stream); + + // cache image asynchronously, after successful decoding + var task = Task.Run(async () => + { + var buffer = new Windows.Storage.Streams.Buffer((uint)stream.Size); + + stream.Seek(0); + await stream.ReadAsync(buffer, buffer.Capacity, InputStreamOptions.None); + stream.Dispose(); + + await Cache.SetAsync(cacheKey, buffer); + }); + } + catch (Exception ex) + { + Debug.WriteLine("{0}: {1}", response.RequestMessage.RequestUri, ex.Message); + stream.Dispose(); + } + }); + } + else + { + Debug.WriteLine("{0}: {1}", response.RequestMessage.RequestUri, response.StatusCode); + } + } + } +} diff --git a/MapControl/WinRT/MapControl.WinRT.csproj b/MapControl/WinRT/MapControl.WinRT.csproj index fc95fecc..5fc867d2 100644 --- a/MapControl/WinRT/MapControl.WinRT.csproj +++ b/MapControl/WinRT/MapControl.WinRT.csproj @@ -42,6 +42,9 @@ Extensions.WinRT.cs + + ImageFileCache.WinRT.cs + ImageTileSource.Silverlight.WinRT.cs @@ -51,6 +54,9 @@ Int32Rect.cs + + IObjectCache.WinRT.cs + Location.cs @@ -138,8 +144,8 @@ TileContainer.Silverlight.WinRT.cs - - TileImageLoader.Silverlight.WinRT.cs + + TileImageLoader.WinRT.cs TileLayer.cs diff --git a/MapControl/WinRT/Properties/AssemblyInfo.cs b/MapControl/WinRT/Properties/AssemblyInfo.cs index b2659bae..06d513f6 100644 --- a/MapControl/WinRT/Properties/AssemblyInfo.cs +++ b/MapControl/WinRT/Properties/AssemblyInfo.cs @@ -7,8 +7,8 @@ using System.Runtime.InteropServices; [assembly: AssemblyCompany("Clemens Fischer")] [assembly: AssemblyCopyright("Copyright © 2014 Clemens Fischer")] [assembly: AssemblyTrademark("")] -[assembly: AssemblyVersion("2.0.0")] -[assembly: AssemblyFileVersion("2.0.0")] +[assembly: AssemblyVersion("2.1.0")] +[assembly: AssemblyFileVersion("2.1.0")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCulture("")] [assembly: ComVisible(false)] diff --git a/SampleApps/PhoneApplication/MainPage.xaml b/SampleApps/PhoneApplication/MainPage.xaml index e2c9b597..ce92100c 100644 --- a/SampleApps/PhoneApplication/MainPage.xaml +++ b/SampleApps/PhoneApplication/MainPage.xaml @@ -35,7 +35,7 @@ - + + + + + + @@ -124,7 +130,7 @@ - + @@ -190,6 +196,8 @@ OCM Transport OCM Landscape MapQuest OSM + Bing Maps + Bing Images diff --git a/SampleApps/StoreApplication/MainPage.xaml.cs b/SampleApps/StoreApplication/MainPage.xaml.cs index 1cd81486..5b628107 100644 --- a/SampleApps/StoreApplication/MainPage.xaml.cs +++ b/SampleApps/StoreApplication/MainPage.xaml.cs @@ -1,4 +1,5 @@ using MapControl; +using Windows.Storage; using Windows.UI.Xaml; using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Controls.Primitives; @@ -9,7 +10,12 @@ namespace StoreApplication { public MainPage() { + TileImageLoader.Cache = new ImageFileCache(); + this.InitializeComponent(); + + var tileLayers = (TileLayerCollection)Resources["TileLayers"]; + map.TileLayer = tileLayers[0]; } private void ImageOpacitySliderValueChanged(object sender, RangeBaseValueChangedEventArgs e) diff --git a/SampleApps/StoreApplication/Properties/AssemblyInfo.cs b/SampleApps/StoreApplication/Properties/AssemblyInfo.cs index f9feb655..317d64de 100644 --- a/SampleApps/StoreApplication/Properties/AssemblyInfo.cs +++ b/SampleApps/StoreApplication/Properties/AssemblyInfo.cs @@ -7,8 +7,8 @@ using System.Runtime.InteropServices; [assembly: AssemblyCompany("Clemens Fischer")] [assembly: AssemblyCopyright("Copyright © 2014 Clemens Fischer")] [assembly: AssemblyTrademark("")] -[assembly: AssemblyVersion("2.0.0")] -[assembly: AssemblyFileVersion("2.0.0")] +[assembly: AssemblyVersion("2.1.0")] +[assembly: AssemblyFileVersion("2.1.0")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCulture("")] [assembly: ComVisible(false)] diff --git a/SampleApps/SurfaceApplication/App.config b/SampleApps/SurfaceApplication/App.config deleted file mode 100644 index c5e1daef..00000000 --- a/SampleApps/SurfaceApplication/App.config +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/SampleApps/SurfaceApplication/App.xaml b/SampleApps/SurfaceApplication/App.xaml deleted file mode 100644 index 486a4398..00000000 --- a/SampleApps/SurfaceApplication/App.xaml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - diff --git a/SampleApps/SurfaceApplication/App.xaml.cs b/SampleApps/SurfaceApplication/App.xaml.cs deleted file mode 100644 index 35b64ad0..00000000 --- a/SampleApps/SurfaceApplication/App.xaml.cs +++ /dev/null @@ -1,8 +0,0 @@ -using System.Windows; - -namespace SurfaceApplication -{ - public partial class App : Application - { - } -} \ No newline at end of file diff --git a/SampleApps/SurfaceApplication/MainWindow.xaml b/SampleApps/SurfaceApplication/MainWindow.xaml deleted file mode 100644 index 8e816984..00000000 --- a/SampleApps/SurfaceApplication/MainWindow.xaml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - diff --git a/SampleApps/SurfaceApplication/MainWindow.xaml.cs b/SampleApps/SurfaceApplication/MainWindow.xaml.cs deleted file mode 100644 index 14401b3c..00000000 --- a/SampleApps/SurfaceApplication/MainWindow.xaml.cs +++ /dev/null @@ -1,28 +0,0 @@ -using System.Windows.Input; -using Microsoft.Surface; -using Microsoft.Surface.Presentation.Controls; -using Microsoft.Surface.Presentation.Input; - -namespace SurfaceApplication -{ - public partial class MainWindow : SurfaceWindow - { - public MainWindow() - { - InitializeComponent(); - } - - private void MapTouchDown(object sender, TouchEventArgs e) - { - if (SurfaceEnvironment.IsSurfaceEnvironmentAvailable && - !e.Device.GetIsFingerRecognized()) - { - // If touch event is from a blob or tag, prevent touch capture by setting - // TouchEventArgs.Handled = true. Hence no manipulation will be started. - // See http://msdn.microsoft.com/en-us/library/ms754010#touch_and_manipulation - - e.Handled = true; - } - } - } -} \ No newline at end of file diff --git a/SampleApps/SurfaceApplication/Properties/AssemblyInfo.cs b/SampleApps/SurfaceApplication/Properties/AssemblyInfo.cs deleted file mode 100644 index be1f7b7c..00000000 --- a/SampleApps/SurfaceApplication/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System.Reflection; -using System.Runtime.InteropServices; - -[assembly: AssemblyTitle("Surface Sample Application")] -[assembly: AssemblyDescription("XAML Map Control Sample Application for PixelSense (Surface 2)")] - -[assembly: AssemblyProduct("XAML Map Control")] -[assembly: AssemblyCompany("Clemens Fischer")] -[assembly: AssemblyCopyright("Copyright © 2014 Clemens Fischer")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyVersion("2.0.0")] -[assembly: AssemblyFileVersion("2.0.0")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCulture("")] -[assembly: ComVisible(false)] diff --git a/SampleApps/SurfaceApplication/SurfaceApplication.csproj b/SampleApps/SurfaceApplication/SurfaceApplication.csproj deleted file mode 100644 index b17e7def..00000000 --- a/SampleApps/SurfaceApplication/SurfaceApplication.csproj +++ /dev/null @@ -1,97 +0,0 @@ - - - - Debug - AnyCPU - 8.0.30703 - 2.0 - {6285FB9D-B7EA-469A-B464-224077967167} - WinExe - Properties - SurfaceApplication - SurfaceApplication - v4.5 - - - 512 - {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} - 4 - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - false - - - none - true - bin\Release\ - TRACE - prompt - 4 - false - - - - - - 4.0 - - - - - - - - - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - App.xaml - Code - - - MainWindow.xaml - Code - - - - - Code - - - - - - - PreserveNewest - - - - - - {226f3575-b683-446d-a2f0-181291dc8787} - MapControl.WPF - - - - - \ No newline at end of file diff --git a/SampleApps/SurfaceApplication/SurfaceApplication.xml b/SampleApps/SurfaceApplication/SurfaceApplication.xml deleted file mode 100644 index d1870585..00000000 --- a/SampleApps/SurfaceApplication/SurfaceApplication.xml +++ /dev/null @@ -1,48 +0,0 @@ - - - - - SurfaceApplication - SurfaceApplication - SurfaceApplication.exe - - - Resources\icon.png - - - - - - - - - \ No newline at end of file diff --git a/SampleApps/WpfApplication/MainWindow.xaml.cs b/SampleApps/WpfApplication/MainWindow.xaml.cs index 51894797..b6992f8c 100644 --- a/SampleApps/WpfApplication/MainWindow.xaml.cs +++ b/SampleApps/WpfApplication/MainWindow.xaml.cs @@ -2,7 +2,6 @@ using System.Globalization; using System.Runtime.Caching; using System.Windows; -using System.Windows.Controls; using System.Windows.Input; using Caching; using MapControl; @@ -56,14 +55,27 @@ namespace WpfApplication private void MapMouseMove(object sender, MouseEventArgs e) { var location = map.ViewportPointToLocation(e.GetPosition(map)); - var longitude = Location.NormalizeLongitude(location.Longitude); - var latString = location.Latitude < 0 ? - string.Format(CultureInfo.InvariantCulture, "S {0:00.00000}", -location.Latitude) : - string.Format(CultureInfo.InvariantCulture, "N {0:00.00000}", location.Latitude); - var lonString = longitude < 0 ? - string.Format(CultureInfo.InvariantCulture, "W {0:000.00000}", -longitude) : - string.Format(CultureInfo.InvariantCulture, "E {0:000.00000}", longitude); - mouseLocation.Text = latString + "\n" + lonString; + var latitude = (int)Math.Round(location.Latitude * 60000d); + var longitude = (int)Math.Round(Location.NormalizeLongitude(location.Longitude) * 60000d); + var latHemisphere = 'N'; + var lonHemisphere = 'E'; + + if (latitude < 0) + { + latitude = -latitude; + latHemisphere = 'S'; + } + + if (longitude < 0) + { + longitude = -longitude; + lonHemisphere = 'W'; + } + + mouseLocation.Text = string.Format(CultureInfo.InvariantCulture, + "{0} {1:00} {2:00.000}\n{3} {4:000} {5:00.000}", + latHemisphere, latitude / 60000, (double)(latitude % 60000) / 1000d, + lonHemisphere, longitude / 60000, (double)(longitude % 60000) / 1000d); } private void MapManipulationInertiaStarting(object sender, ManipulationInertiaStartingEventArgs e) diff --git a/SampleApps/WpfApplication/Properties/AssemblyInfo.cs b/SampleApps/WpfApplication/Properties/AssemblyInfo.cs index 7fc78994..a3470caa 100644 --- a/SampleApps/WpfApplication/Properties/AssemblyInfo.cs +++ b/SampleApps/WpfApplication/Properties/AssemblyInfo.cs @@ -7,8 +7,8 @@ using System.Runtime.InteropServices; [assembly: AssemblyCompany("Clemens Fischer")] [assembly: AssemblyCopyright("Copyright © 2014 Clemens Fischer")] [assembly: AssemblyTrademark("")] -[assembly: AssemblyVersion("2.0.0")] -[assembly: AssemblyFileVersion("2.0.0")] +[assembly: AssemblyVersion("2.1.0")] +[assembly: AssemblyFileVersion("2.1.0")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCulture("")] [assembly: ComVisible(false)]