Version 3.3. Improved WinRT TileImageLoader

This commit is contained in:
ClemensF 2017-07-18 18:20:57 +02:00
parent 8f5a0627fb
commit ace1057669
16 changed files with 110 additions and 95 deletions

View file

@ -7,8 +7,8 @@ using System.Runtime.InteropServices;
[assembly: AssemblyCompany("Clemens Fischer")]
[assembly: AssemblyCopyright("© 2017 Clemens Fischer")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyVersion("3.2.0")]
[assembly: AssemblyFileVersion("3.2.0")]
[assembly: AssemblyVersion("3.3.0")]
[assembly: AssemblyFileVersion("3.3.0")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCulture("")]
[assembly: ComVisible(false)]

View file

@ -7,8 +7,8 @@ using System.Runtime.InteropServices;
[assembly: AssemblyCompany("Clemens Fischer")]
[assembly: AssemblyCopyright("© 2017 Clemens Fischer")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyVersion("3.2.0")]
[assembly: AssemblyFileVersion("3.2.0")]
[assembly: AssemblyVersion("3.3.0")]
[assembly: AssemblyFileVersion("3.3.0")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCulture("")]
[assembly: ComVisible(false)]

View file

@ -7,8 +7,8 @@ using System.Runtime.InteropServices;
[assembly: AssemblyCompany("Clemens Fischer")]
[assembly: AssemblyCopyright("© 2017 Clemens Fischer")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyVersion("3.2.0")]
[assembly: AssemblyFileVersion("3.2.0")]
[assembly: AssemblyVersion("3.3.0")]
[assembly: AssemblyFileVersion("3.3.0")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCulture("")]
[assembly: ComVisible(false)]

View file

@ -7,8 +7,8 @@ using System.Runtime.InteropServices;
[assembly: AssemblyCompany("Clemens Fischer")]
[assembly: AssemblyCopyright("© 2017 Clemens Fischer")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyVersion("3.2.0")]
[assembly: AssemblyFileVersion("3.2.0")]
[assembly: AssemblyVersion("3.3.0")]
[assembly: AssemblyFileVersion("3.3.0")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCulture("")]
[assembly: ComVisible(false)]

View file

@ -13,9 +13,9 @@ using System.Windows.Media.Imaging;
namespace MapControl
{
/// <summary>
/// Provides the image of a map tile. ImageTileSource bypasses image
/// downloading in TileImageLoader. By overriding the LoadImage method,
/// an application can provide tile images from an arbitrary source.
/// Provides the image of a map tile.
/// ImageTileSource bypasses image downloading and optional caching in TileImageLoader.
/// By overriding the LoadImage method, an application can provide tile images from an arbitrary source.
/// </summary>
public class ImageTileSource : TileSource
{

View file

@ -55,7 +55,7 @@ namespace MapControl
public static readonly DependencyProperty TileSourceProperty = DependencyProperty.Register(
nameof(TileSource), typeof(TileSource), typeof(MapTileLayer),
new PropertyMetadata(null, (o, e) => ((MapTileLayer)o).ResetTiles()));
new PropertyMetadata(null, (o, e) => ((MapTileLayer)o).TileSourcePropertyChanged()));
public static readonly DependencyProperty SourceNameProperty = DependencyProperty.Register(
nameof(SourceName), typeof(string), typeof(MapTileLayer), new PropertyMetadata(null));
@ -125,7 +125,7 @@ namespace MapControl
}
/// <summary>
/// Name of the TileSource. Used as key in a TileLayerCollection and as component of a tile cache key.
/// Name of the TileSource. Used as component of a tile cache key.
/// </summary>
public string SourceName
{
@ -134,8 +134,7 @@ namespace MapControl
}
/// <summary>
/// Description of the MapTileLayer.
/// Used to display copyright information on top of the map.
/// Description of the MapTileLayer. Used to display copyright information on top of the map.
/// </summary>
public string Description
{
@ -198,8 +197,7 @@ namespace MapControl
}
/// <summary>
/// Optional background brush.
/// Sets MapBase.Background if not null and the MapTileLayer is the base map layer.
/// Optional background brush. Sets MapBase.Background if not null and the MapTileLayer is the base map layer.
/// </summary>
public Brush MapBackground
{
@ -208,8 +206,7 @@ namespace MapControl
}
/// <summary>
/// Optional foreground brush.
/// Sets MapBase.Foreground if not null and the MapTileLayer is the base map layer.
/// Optional foreground brush. Sets MapBase.Foreground if not null and the MapTileLayer is the base map layer.
/// </summary>
public Brush MapForeground
{
@ -287,7 +284,16 @@ namespace MapControl
else
{
TileGrid = null;
ResetTiles();
UpdateTiles();
}
}
private void TileSourcePropertyChanged()
{
if (TileGrid != null)
{
Tiles.Clear();
UpdateTiles();
}
}
@ -295,8 +301,7 @@ namespace MapControl
{
if (TileGrid == null || e.ProjectionChanged || Math.Abs(e.LongitudeOffset) > 180d)
{
// update immediately when map projection has changed or map center has moved across 180° longitude
UpdateTileGrid();
UpdateTileGrid(); // update immediately when projection has changed or center has moved across 180° longitude
}
else
{
@ -314,9 +319,8 @@ namespace MapControl
}
}
private Point GetTileCenter(double tileScale)
private Point GetTileCenter(double tileScale) // map center in tile index coordinates
{
// map center in tile index coordinates
return new Point(
tileScale * (0.5 + parentMap.Center.Longitude / 360d),
tileScale * (0.5 - WebMercatorProjection.LatitudeToY(parentMap.Center.Latitude) / 360d));
@ -354,27 +358,7 @@ namespace MapControl
MatrixEx.TranslateScaleRotateTranslate(tileOrigin, scale, parentMap.Heading, viewCenter);
}
private void ResetTiles()
{
Tiles.Clear();
UpdateTiles();
}
private void UpdateTiles()
{
SelectTiles();
Children.Clear();
foreach (var tile in Tiles)
{
Children.Add(tile.Image);
}
TileImageLoader.LoadTiles(this);
}
private void SelectTiles()
{
var newTiles = new List<Tile>();
@ -406,8 +390,7 @@ namespace MapControl
if (equivalentTile != null)
{
// do not animate to avoid flicker when crossing 180°
tile.SetImage(equivalentTile.Image.Source, false);
tile.SetImage(equivalentTile.Image.Source, false); // do not animate to avoid flicker when crossing 180° longitude
}
}
@ -418,6 +401,15 @@ namespace MapControl
}
Tiles = newTiles;
Children.Clear();
foreach (var tile in Tiles)
{
Children.Add(tile.Image);
}
TileImageLoader.LoadTiles(this);
}
}
}

View file

@ -14,8 +14,8 @@ using System.Windows;
[assembly: AssemblyCompany("Clemens Fischer")]
[assembly: AssemblyCopyright("© 2017 Clemens Fischer")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyVersion("3.2.0")]
[assembly: AssemblyFileVersion("3.2.0")]
[assembly: AssemblyVersion("3.3.0")]
[assembly: AssemblyFileVersion("3.3.0")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCulture("")]
[assembly: ComVisible(false)]

View file

@ -13,7 +13,7 @@ namespace MapControl
/// <summary>
/// Loads map tile images.
/// </summary>
internal class TileImageLoader : ITileImageLoader
public class TileImageLoader : ITileImageLoader
{
public void LoadTiles(MapTileLayer tileLayer)
{

View file

@ -4,7 +4,6 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
@ -69,11 +68,11 @@ namespace MapControl
{
pendingTiles.Clear();
var tileStack = tileLayer.Tiles.Where(t => t.Pending).Reverse().ToArray();
var tiles = tileLayer.Tiles.Where(t => t.Pending);
if (tileStack.Length > 0)
if (tiles.Any())
{
pendingTiles.PushRange(tileStack);
pendingTiles.PushRange(tiles.Reverse().ToArray());
var tileSource = tileLayer.TileSource;
var sourceName = tileLayer.SourceName;

View file

@ -64,21 +64,20 @@ namespace MapControl
{
pendingTiles.Clear();
var tiles = tileLayer.Tiles.Where(t => t.Pending);
if (tiles.Any())
{
var tileSource = tileLayer.TileSource;
var imageTileSource = tileSource as ImageTileSource;
var tiles = tileLayer.Tiles.Where(t => t.Pending);
if (imageTileSource != null)
{
LoadTiles(imageTileSource, tiles);
LoadTiles(tiles, imageTileSource);
}
else
{
var tileStack = tiles.Reverse().ToArray();
if (tileStack.Length > 0)
{
pendingTiles.PushRange(tileStack);
pendingTiles.PushRange(tiles.Reverse().ToArray());
var sourceName = tileLayer.SourceName;
var maxDownloads = tileLayer.MaxParallelDownloads;
@ -98,7 +97,7 @@ namespace MapControl
}
}
private void LoadTiles(ImageTileSource tileSource, IEnumerable<Tile> tiles)
private void LoadTiles(IEnumerable<Tile> tiles, ImageTileSource tileSource)
{
foreach (var tile in tiles)
{
@ -134,7 +133,15 @@ namespace MapControl
if (uri != null)
{
if (Cache == null || sourceName == null)
if (!uri.IsAbsoluteUri)
{
await LoadImageFromFile(tile, uri.OriginalString);
}
else if (uri.Scheme == "file")
{
await LoadImageFromFile(tile, uri.LocalPath);
}
else if (Cache == null || sourceName == null)
{
await DownloadImage(tile, uri, null);
}
@ -186,7 +193,14 @@ namespace MapControl
{
if (response.IsSuccessStatusCode)
{
return await LoadImageFromHttpResponse(response, tile, cacheKey);
string tileInfo;
if (!response.Headers.TryGetValue("X-VE-Tile-Info", out tileInfo) || tileInfo != "no-tile") // set by Bing Maps
{
await LoadImageFromHttpResponse(response, tile, cacheKey);
}
return true;
}
Debug.WriteLine("{0}: {1} {2}", uri, (int)response.StatusCode, response.ReasonPhrase);
@ -200,15 +214,8 @@ namespace MapControl
return false;
}
private async Task<bool> LoadImageFromHttpResponse(HttpResponseMessage response, Tile tile, string cacheKey)
private async Task LoadImageFromHttpResponse(HttpResponseMessage response, Tile tile, string cacheKey)
{
string tileInfo;
if (response.Headers.TryGetValue("X-VE-Tile-Info", out tileInfo) && tileInfo == "no-tile") // set by Bing Maps
{
return true;
}
using (var stream = new InMemoryRandomAccessStream())
{
using (var content = response.Content)
@ -219,9 +226,9 @@ namespace MapControl
await stream.FlushAsync();
stream.Seek(0);
var loaded = await LoadImageFromStream(tile, stream);
await LoadImageFromStream(tile, stream);
if (loaded && cacheKey != null)
if (cacheKey != null)
{
var buffer = new Windows.Storage.Streams.Buffer((uint)stream.Size);
@ -242,14 +249,29 @@ namespace MapControl
await Cache.SetAsync(cacheKey, buffer, DateTime.UtcNow.Add(expiration));
}
return loaded;
}
}
private async Task<bool> LoadImageFromStream(Tile tile, IRandomAccessStream stream)
private async Task LoadImageFromFile(Tile tile, string path)
{
var tcs = new TaskCompletionSource<bool>();
try
{
var file = await StorageFile.GetFileFromPathAsync(path);
using (var stream = await file.OpenReadAsync())
{
await LoadImageFromStream(tile, stream);
}
}
catch (Exception ex)
{
Debug.WriteLine("{0}: {1}", path, ex.Message);
}
}
private async Task LoadImageFromStream(Tile tile, IRandomAccessStream stream)
{
var tcs = new TaskCompletionSource<object>();
await tile.Image.Dispatcher.RunAsync(CoreDispatcherPriority.Low, async () =>
{
@ -258,16 +280,16 @@ namespace MapControl
var image = new BitmapImage();
await image.SetSourceAsync(stream);
tile.SetImage(image, true, false);
tcs.SetResult(true);
tcs.SetResult(null);
}
catch (Exception ex)
{
Debug.WriteLine("{0}/{1}/{2}: {3}", tile.ZoomLevel, tile.XIndex, tile.Y, ex.Message);
tcs.SetResult(false);
tcs.SetException(ex);
}
});
return await tcs.Task;
await tcs.Task;
}
}
}

View file

@ -26,6 +26,7 @@
<DefineConstants>TRACE;DEBUG;NETFX_CORE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<GenerateLibraryLayout>true</GenerateLibraryLayout>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>none</DebugType>
@ -34,6 +35,7 @@
<DefineConstants>TRACE;NETFX_CORE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<GenerateLibraryLayout>true</GenerateLibraryLayout>
</PropertyGroup>
<ItemGroup>
<Compile Include="..\AzimuthalEquidistantProjection.cs">
@ -212,7 +214,7 @@
</PreBuildEvent>
</PropertyGroup>
<PropertyGroup>
<PostBuildEvent>copy "$(ProjectDir)MapControl.WinRT.xr.xml" "$(TargetDir)"</PostBuildEvent>
<PostBuildEvent>copy "$(ProjectDir)$(TargetName).xr.xml" "$(TargetDir)$(TargetName)\"</PostBuildEvent>
</PropertyGroup>
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.

View file

@ -7,8 +7,8 @@ using System.Runtime.InteropServices;
[assembly: AssemblyCompany("Clemens Fischer")]
[assembly: AssemblyCopyright("© 2017 Clemens Fischer")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyVersion("3.2.0")]
[assembly: AssemblyFileVersion("3.2.0")]
[assembly: AssemblyVersion("3.3.0")]
[assembly: AssemblyFileVersion("3.3.0")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCulture("")]
[assembly: ComVisible(false)]

View file

@ -7,8 +7,8 @@ using System.Runtime.InteropServices;
[assembly: AssemblyCompany("Clemens Fischer")]
[assembly: AssemblyCopyright("© 2017 Clemens Fischer")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyVersion("3.2.0")]
[assembly: AssemblyFileVersion("3.2.0")]
[assembly: AssemblyVersion("3.3.0")]
[assembly: AssemblyFileVersion("3.3.0")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCulture("")]
[assembly: ComVisible(false)]

View file

@ -7,8 +7,8 @@ using System.Runtime.InteropServices;
[assembly: AssemblyCompany("Clemens Fischer")]
[assembly: AssemblyCopyright("© 2017 Clemens Fischer")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyVersion("3.2.0")]
[assembly: AssemblyFileVersion("3.2.0")]
[assembly: AssemblyVersion("3.3.0")]
[assembly: AssemblyFileVersion("3.3.0")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCulture("")]
[assembly: ComVisible(false)]

View file

@ -8,7 +8,7 @@ using System.Runtime.InteropServices;
[assembly: AssemblyCopyright("© 2017 Clemens Fischer")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
[assembly: AssemblyVersion("3.2.0")]
[assembly: AssemblyFileVersion("3.2.0")]
[assembly: AssemblyVersion("3.3.0")]
[assembly: AssemblyFileVersion("3.3.0")]
[assembly: AssemblyConfiguration("")]
[assembly: ComVisible(false)]

View file

@ -7,8 +7,8 @@ using System.Runtime.InteropServices;
[assembly: AssemblyCompany("Clemens Fischer")]
[assembly: AssemblyCopyright("© 2017 Clemens Fischer")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyVersion("3.2.0")]
[assembly: AssemblyFileVersion("3.2.0")]
[assembly: AssemblyVersion("3.3.0")]
[assembly: AssemblyFileVersion("3.3.0")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCulture("")]
[assembly: ComVisible(false)]