mirror of
https://github.com/ClemensFischer/XAML-Map-Control.git
synced 2025-12-06 07:12:04 +01:00
Compare commits
5 commits
cb4dff8bcb
...
b44018ac8f
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b44018ac8f | ||
|
|
76f920a053 | ||
|
|
4912fa1e40 | ||
|
|
cb8fff0dd1 | ||
|
|
20e4fcce75 |
|
|
@ -32,14 +32,13 @@ namespace MapControl.MBTiles
|
|||
|
||||
await connection.OpenAsync();
|
||||
|
||||
using (var command = new SQLiteCommand("select * from metadata", connection))
|
||||
{
|
||||
var reader = await command.ExecuteReaderAsync();
|
||||
using var command = new SQLiteCommand("select * from metadata", connection);
|
||||
|
||||
while (await reader.ReadAsync())
|
||||
{
|
||||
Metadata[(string)reader["name"]] = (string)reader["value"];
|
||||
}
|
||||
var reader = await command.ExecuteReaderAsync();
|
||||
|
||||
while (await reader.ReadAsync())
|
||||
{
|
||||
Metadata[(string)reader["name"]] = (string)reader["value"];
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -58,24 +57,23 @@ namespace MapControl.MBTiles
|
|||
Close();
|
||||
}
|
||||
|
||||
public override async Task<ImageSource> LoadImageAsync(int x, int y, int zoomLevel)
|
||||
public override async Task<ImageSource> LoadImageAsync(int zoomLevel, int column, int row)
|
||||
{
|
||||
ImageSource image = null;
|
||||
|
||||
try
|
||||
{
|
||||
using (var command = new SQLiteCommand("select tile_data from tiles where zoom_level=@z and tile_column=@x and tile_row=@y", connection))
|
||||
using var command = new SQLiteCommand("select tile_data from tiles where zoom_level=@z and tile_column=@x and tile_row=@y", connection);
|
||||
|
||||
command.Parameters.AddWithValue("@z", zoomLevel);
|
||||
command.Parameters.AddWithValue("@x", column);
|
||||
command.Parameters.AddWithValue("@y", (1 << zoomLevel) - row - 1);
|
||||
|
||||
var buffer = (byte[])await command.ExecuteScalarAsync();
|
||||
|
||||
if (buffer?.Length > 0)
|
||||
{
|
||||
command.Parameters.AddWithValue("@z", zoomLevel);
|
||||
command.Parameters.AddWithValue("@x", x);
|
||||
command.Parameters.AddWithValue("@y", (1 << zoomLevel) - y - 1);
|
||||
|
||||
var buffer = (byte[])await command.ExecuteScalarAsync();
|
||||
|
||||
if (buffer?.Length > 0)
|
||||
{
|
||||
image = await LoadImageAsync(buffer);
|
||||
}
|
||||
image = await ImageLoader.LoadImageAsync(buffer);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
using Avalonia;
|
||||
global using DependencyProperty = Avalonia.AvaloniaProperty;
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Data;
|
||||
using System;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
using Avalonia;
|
||||
using Avalonia.Animation;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Media;
|
||||
using Avalonia.Styling;
|
||||
using Avalonia.Threading;
|
||||
|
|
@ -8,9 +9,12 @@ using System.Threading.Tasks;
|
|||
|
||||
namespace MapControl
|
||||
{
|
||||
public partial class Tile
|
||||
public class ImageTile(int zoomLevel, int x, int y, int columnCount)
|
||||
: Tile(zoomLevel, x, y, columnCount)
|
||||
{
|
||||
public async Task LoadImageAsync(Func<Task<IImage>> loadImageFunc)
|
||||
public Image Image { get; } = new Image { Stretch = Stretch.Fill };
|
||||
|
||||
public override async Task LoadImageAsync(Func<Task<IImage>> loadImageFunc)
|
||||
{
|
||||
var image = await loadImageFunc().ConfigureAwait(false);
|
||||
|
||||
|
|
@ -1,9 +1,4 @@
|
|||
global using DependencyProperty = Avalonia.AvaloniaProperty;
|
||||
global using FrameworkElement = Avalonia.Controls.Control;
|
||||
global using Brush = Avalonia.Media.IBrush;
|
||||
global using ImageSource = Avalonia.Media.IImage;
|
||||
global using PropertyPath = System.String;
|
||||
using Avalonia;
|
||||
using Avalonia;
|
||||
using Avalonia.Animation;
|
||||
using Avalonia.Animation.Easings;
|
||||
using Avalonia.Controls;
|
||||
|
|
@ -13,6 +8,7 @@ using Avalonia.Media;
|
|||
using Avalonia.Styling;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Brush = Avalonia.Media.IBrush;
|
||||
|
||||
namespace MapControl
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
global using FrameworkElement = Avalonia.Controls.Control;
|
||||
using Avalonia;
|
||||
using Avalonia.Media;
|
||||
|
||||
namespace MapControl
|
||||
|
|
@ -20,18 +20,18 @@ namespace MapControl
|
|||
AffectsParentArrange<MapPanel>(LocationProperty, BoundingBoxProperty);
|
||||
}
|
||||
|
||||
public static MapBase GetParentMap(Control element)
|
||||
public static MapBase GetParentMap(FrameworkElement element)
|
||||
{
|
||||
return (MapBase)element.GetValue(ParentMapProperty);
|
||||
}
|
||||
|
||||
public static void SetRenderTransform(Control element, Transform transform, double originX = 0d, double originY = 0d)
|
||||
public static void SetRenderTransform(FrameworkElement element, Transform transform, double originX = 0d, double originY = 0d)
|
||||
{
|
||||
element.RenderTransform = transform;
|
||||
element.RenderTransformOrigin = new RelativePoint(originX, originY, RelativeUnit.Relative);
|
||||
}
|
||||
|
||||
private static void SetVisible(Control element, bool visible)
|
||||
private static void SetVisible(FrameworkElement element, bool visible)
|
||||
{
|
||||
element.IsVisible = visible;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ using System.Text;
|
|||
|
||||
namespace MapControl
|
||||
{
|
||||
public class BoundingBoxTileSource : TileSource
|
||||
public class BoundingBoxTileSource : UriTileSource
|
||||
{
|
||||
public override Uri GetUri(int zoomLevel, int column, int row)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -9,6 +9,8 @@ using System.Windows.Media;
|
|||
using Windows.UI.Xaml.Media;
|
||||
#elif WINUI
|
||||
using Microsoft.UI.Xaml.Media;
|
||||
#elif AVALONIA
|
||||
using ImageSource = Avalonia.Media.IImage;
|
||||
#endif
|
||||
|
||||
namespace MapControl
|
||||
|
|
|
|||
|
|
@ -3,12 +3,12 @@ using System.Linq;
|
|||
|
||||
namespace MapControl
|
||||
{
|
||||
public partial class TileCollection : List<Tile>
|
||||
public partial class ImageTileList : List<ImageTile>
|
||||
{
|
||||
/// <summary>
|
||||
/// Adds existing Tiles from the source collection or newly created Tiles to fill the specified tile matrix.
|
||||
/// Adds existing ImageTile from the source collection or newly created ImageTile to fill the specified tile matrix.
|
||||
/// </summary>
|
||||
public void FillMatrix(TileCollection source, int zoomLevel, int xMin, int yMin, int xMax, int yMax, int columnCount)
|
||||
public void FillMatrix(ImageTileList source, int zoomLevel, int xMin, int yMin, int xMax, int yMax, int columnCount)
|
||||
{
|
||||
for (var y = yMin; y <= yMax; y++)
|
||||
{
|
||||
|
|
@ -18,7 +18,7 @@ namespace MapControl
|
|||
|
||||
if (tile == null)
|
||||
{
|
||||
tile = new Tile(zoomLevel, x, y, columnCount);
|
||||
tile = new ImageTile(zoomLevel, x, y, columnCount);
|
||||
|
||||
var equivalentTile = source.FirstOrDefault(
|
||||
t => t.Image.Source != null && t.ZoomLevel == tile.ZoomLevel && t.Column == tile.Column && t.Row == tile.Row);
|
||||
|
|
@ -14,6 +14,7 @@ using Microsoft.UI.Xaml;
|
|||
using Microsoft.UI.Xaml.Media;
|
||||
#elif AVALONIA
|
||||
using Avalonia.Controls;
|
||||
using Brush = Avalonia.Media.IBrush;
|
||||
#endif
|
||||
|
||||
namespace MapControl
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ using Microsoft.UI.Xaml;
|
|||
using Microsoft.UI.Xaml.Media;
|
||||
#elif AVALONIA
|
||||
using Avalonia;
|
||||
using Brush = Avalonia.Media.IBrush;
|
||||
#endif
|
||||
|
||||
namespace MapControl
|
||||
|
|
|
|||
|
|
@ -18,6 +18,8 @@ using Microsoft.UI.Xaml.Media;
|
|||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Media;
|
||||
using Brush = Avalonia.Media.IBrush;
|
||||
using ImageSource = Avalonia.Media.IImage;
|
||||
#endif
|
||||
|
||||
namespace MapControl
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ using Microsoft.UI.Xaml.Data;
|
|||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Data;
|
||||
using PropertyPath = System.String;
|
||||
#endif
|
||||
|
||||
namespace MapControl
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ using Avalonia.Controls.Shapes;
|
|||
using Avalonia.Data;
|
||||
using Avalonia.Layout;
|
||||
using PointCollection = System.Collections.Generic.List<Avalonia.Point>;
|
||||
using PropertyPath = System.String;
|
||||
#endif
|
||||
|
||||
namespace MapControl
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ namespace MapControl
|
|||
/// <summary>
|
||||
/// Displays a standard Web Mercator map tile pyramid, e.g. a OpenStreetMap tiles.
|
||||
/// </summary>
|
||||
public partial class MapTileLayer : MapTilePyramidLayer
|
||||
public partial class MapTileLayer : TilePyramidLayer
|
||||
{
|
||||
public static readonly DependencyProperty MinZoomLevelProperty =
|
||||
DependencyPropertyHelper.Register<MapTileLayer, int>(nameof(MinZoomLevel), 0);
|
||||
|
|
@ -43,7 +43,7 @@ namespace MapControl
|
|||
/// </summary>
|
||||
public static MapTileLayer OpenStreetMapTileLayer => new()
|
||||
{
|
||||
TileSource = new TileSource { UriTemplate = "https://tile.openstreetmap.org/{z}/{x}/{y}.png" },
|
||||
TileSource = TileSource.Parse("https://tile.openstreetmap.org/{z}/{x}/{y}.png"),
|
||||
SourceName = "OpenStreetMap",
|
||||
Description = "© [OpenStreetMap Contributors](http://www.openstreetmap.org/copyright)"
|
||||
};
|
||||
|
|
@ -52,7 +52,7 @@ namespace MapControl
|
|||
|
||||
public TileMatrix TileMatrix { get; private set; }
|
||||
|
||||
public TileCollection Tiles { get; private set; } = [];
|
||||
public ImageTileList Tiles { get; private set; } = [];
|
||||
|
||||
/// <summary>
|
||||
/// Minimum zoom level supported by the MapTileLayer. Default value is 0.
|
||||
|
|
@ -178,7 +178,7 @@ namespace MapControl
|
|||
|
||||
private void UpdateTiles(bool reset)
|
||||
{
|
||||
var tiles = new TileCollection();
|
||||
var tiles = new ImageTileList();
|
||||
|
||||
if (TileSource != null && TileMatrix != null)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,20 +1,18 @@
|
|||
#if WPF
|
||||
using System.Windows.Controls;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
#if WPF
|
||||
using System.Windows.Media;
|
||||
#elif UWP
|
||||
using Windows.UI.Xaml.Controls;
|
||||
using Windows.UI.Xaml.Media;
|
||||
#elif WINUI
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Microsoft.UI.Xaml.Media;
|
||||
#elif AVALONIA
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Media;
|
||||
using ImageSource = Avalonia.Media.IImage;
|
||||
#endif
|
||||
|
||||
namespace MapControl
|
||||
{
|
||||
public partial class Tile(int zoomLevel, int x, int y, int columnCount)
|
||||
public abstract class Tile(int zoomLevel, int x, int y, int columnCount)
|
||||
{
|
||||
public int ZoomLevel { get; } = zoomLevel;
|
||||
public int X { get; } = x;
|
||||
|
|
@ -22,7 +20,11 @@ namespace MapControl
|
|||
public int Column { get; } = ((x % columnCount) + columnCount) % columnCount;
|
||||
public int Row => Y;
|
||||
|
||||
public Image Image { get; } = new Image { Stretch = Stretch.Fill };
|
||||
public bool IsPending { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Runs a tile image download Task and passes the result to the UI thread.
|
||||
/// </summary>
|
||||
public abstract Task LoadImageAsync(Func<Task<ImageSource>> loadImageFunc);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,12 +11,19 @@ using System.Threading.Tasks;
|
|||
namespace MapControl
|
||||
{
|
||||
/// <summary>
|
||||
/// Loads and optionally caches map tile images for a MapTileLayer.
|
||||
/// Loads and optionally caches map tile images for a MapTilePyramidLayer.
|
||||
/// </summary>
|
||||
public interface ITileImageLoader
|
||||
{
|
||||
/// <summary>
|
||||
/// Starts asynchronous loading of all pending tiles from the tiles collection.
|
||||
/// Caching is enabled when cacheName is a non-empty string and tiles are loaded from http or https Uris.
|
||||
/// </summary>
|
||||
void BeginLoadTiles(IEnumerable<Tile> tiles, TileSource tileSource, string cacheName, IProgress<double> progress);
|
||||
|
||||
/// <summary>
|
||||
/// Terminates all running tile loading tasks.
|
||||
/// </summary>
|
||||
void CancelLoadTiles();
|
||||
}
|
||||
|
||||
|
|
@ -67,13 +74,9 @@ namespace MapControl
|
|||
private int tileCount;
|
||||
private int taskCount;
|
||||
|
||||
/// <summary>
|
||||
/// Loads all pending tiles from the tiles collection. Tile image caching is enabled when the Cache
|
||||
/// property is not null and tileSource.UriFormat starts with "http" and cacheName is a non-empty string.
|
||||
/// </summary>
|
||||
public void BeginLoadTiles(IEnumerable<Tile> tiles, TileSource tileSource, string cacheName, IProgress<double> progress)
|
||||
{
|
||||
if (Cache == null || tileSource.UriTemplate == null || !tileSource.UriTemplate.StartsWith("http"))
|
||||
if (Cache == null)
|
||||
{
|
||||
cacheName = null; // disable caching
|
||||
}
|
||||
|
|
@ -119,6 +122,7 @@ namespace MapControl
|
|||
if (tileQueue.Count > 0)
|
||||
{
|
||||
tile = tileQueue.Dequeue();
|
||||
tile.IsPending = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -132,34 +136,12 @@ namespace MapControl
|
|||
|
||||
while (TryDequeueTile(out Tile tile))
|
||||
{
|
||||
tile.IsPending = false;
|
||||
|
||||
Logger?.LogDebug("Thread {thread,2}: Loading tile ({zoom}/{column}/{row})",
|
||||
Environment.CurrentManagedThreadId, tile.ZoomLevel, tile.Column, tile.Row);
|
||||
|
||||
try
|
||||
{
|
||||
// Pass tileSource.LoadImageAsync calls to platform-specific method
|
||||
// tile.LoadImageAsync(Func<Task<ImageSource>>) for completion in the UI thread.
|
||||
Logger?.LogDebug("Thread {thread,2}: Loading tile ({zoom}/{column}/{row})",
|
||||
Environment.CurrentManagedThreadId, tile.ZoomLevel, tile.Column, tile.Row);
|
||||
|
||||
if (string.IsNullOrEmpty(cacheName))
|
||||
{
|
||||
await tile.LoadImageAsync(() => tileSource.LoadImageAsync(tile.ZoomLevel, tile.Column, tile.Row)).ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
var uri = tileSource.GetUri(tile.ZoomLevel, tile.Column, tile.Row);
|
||||
|
||||
if (uri != null)
|
||||
{
|
||||
var buffer = await LoadCachedBuffer(tile, uri, cacheName).ConfigureAwait(false);
|
||||
|
||||
if (buffer?.Length > 0)
|
||||
{
|
||||
await tile.LoadImageAsync(() => tileSource.LoadImageAsync(buffer)).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
await LoadTileImage(tile, tileSource, cacheName);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
|
@ -170,6 +152,32 @@ namespace MapControl
|
|||
}
|
||||
}
|
||||
|
||||
private static async Task LoadTileImage(Tile tile, TileSource tileSource, string cacheName)
|
||||
{
|
||||
// Pass image loading callbacks to platform-specific method
|
||||
// tile.LoadImageAsync(Func<Task<ImageSource>>) for completion in the UI thread.
|
||||
|
||||
var uri = tileSource.GetUri(tile.ZoomLevel, tile.Column, tile.Row);
|
||||
|
||||
if (uri == null)
|
||||
{
|
||||
await tile.LoadImageAsync(() => tileSource.LoadImageAsync(tile.ZoomLevel, tile.Column, tile.Row)).ConfigureAwait(false);
|
||||
}
|
||||
else if (uri.Scheme != "http" && uri.Scheme != "https" || string.IsNullOrEmpty(cacheName))
|
||||
{
|
||||
await tile.LoadImageAsync(() => ImageLoader.LoadImageAsync(uri)).ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
var buffer = await LoadCachedBuffer(tile, uri, cacheName).ConfigureAwait(false);
|
||||
|
||||
if (buffer != null)
|
||||
{
|
||||
await tile.LoadImageAsync(() => ImageLoader.LoadImageAsync(buffer)).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static async Task<byte[]> LoadCachedBuffer(Tile tile, Uri uri, string cacheName)
|
||||
{
|
||||
var extension = Path.GetExtension(uri.LocalPath).ToLower();
|
||||
|
|
|
|||
|
|
@ -20,47 +20,48 @@ using Microsoft.UI.Xaml.Media;
|
|||
#elif AVALONIA
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Media;
|
||||
using Brush = Avalonia.Media.IBrush;
|
||||
#endif
|
||||
|
||||
namespace MapControl
|
||||
{
|
||||
public abstract class MapTilePyramidLayer : Panel, IMapLayer
|
||||
public abstract class TilePyramidLayer : Panel, IMapLayer
|
||||
{
|
||||
public static readonly DependencyProperty TileSourceProperty =
|
||||
DependencyPropertyHelper.Register<MapTilePyramidLayer, TileSource>(nameof(TileSource), null,
|
||||
DependencyPropertyHelper.Register<TilePyramidLayer, TileSource>(nameof(TileSource), null,
|
||||
(layer, oldValue, newValue) => layer.UpdateTiles(true));
|
||||
|
||||
public static readonly DependencyProperty SourceNameProperty =
|
||||
DependencyPropertyHelper.Register<MapTilePyramidLayer, string>(nameof(SourceName));
|
||||
DependencyPropertyHelper.Register<TilePyramidLayer, string>(nameof(SourceName));
|
||||
|
||||
public static readonly DependencyProperty DescriptionProperty =
|
||||
DependencyPropertyHelper.Register<MapTilePyramidLayer, string>(nameof(Description));
|
||||
DependencyPropertyHelper.Register<TilePyramidLayer, string>(nameof(Description));
|
||||
|
||||
public static readonly DependencyProperty MaxBackgroundLevelsProperty =
|
||||
DependencyPropertyHelper.Register<MapTilePyramidLayer, int>(nameof(MaxBackgroundLevels), 5);
|
||||
DependencyPropertyHelper.Register<TilePyramidLayer, int>(nameof(MaxBackgroundLevels), 5);
|
||||
|
||||
public static readonly DependencyProperty UpdateIntervalProperty =
|
||||
DependencyPropertyHelper.Register<MapTilePyramidLayer, TimeSpan>(nameof(UpdateInterval), TimeSpan.FromSeconds(0.2),
|
||||
DependencyPropertyHelper.Register<TilePyramidLayer, TimeSpan>(nameof(UpdateInterval), TimeSpan.FromSeconds(0.2),
|
||||
(layer, oldValue, newValue) => layer.updateTimer.Interval = newValue);
|
||||
|
||||
public static readonly DependencyProperty UpdateWhileViewportChangingProperty =
|
||||
DependencyPropertyHelper.Register<MapTilePyramidLayer, bool>(nameof(UpdateWhileViewportChanging));
|
||||
DependencyPropertyHelper.Register<TilePyramidLayer, bool>(nameof(UpdateWhileViewportChanging));
|
||||
|
||||
public static readonly DependencyProperty MapBackgroundProperty =
|
||||
DependencyPropertyHelper.Register<MapTilePyramidLayer, Brush>(nameof(MapBackground));
|
||||
DependencyPropertyHelper.Register<TilePyramidLayer, Brush>(nameof(MapBackground));
|
||||
|
||||
public static readonly DependencyProperty MapForegroundProperty =
|
||||
DependencyPropertyHelper.Register<MapTilePyramidLayer, Brush>(nameof(MapForeground));
|
||||
DependencyPropertyHelper.Register<TilePyramidLayer, Brush>(nameof(MapForeground));
|
||||
|
||||
public static readonly DependencyProperty LoadingProgressProperty =
|
||||
DependencyPropertyHelper.Register<MapTilePyramidLayer, double>(nameof(LoadingProgress), 1d);
|
||||
DependencyPropertyHelper.Register<TilePyramidLayer, double>(nameof(LoadingProgress), 1d);
|
||||
|
||||
private readonly Progress<double> loadingProgress;
|
||||
private readonly UpdateTimer updateTimer;
|
||||
private ITileImageLoader tileImageLoader;
|
||||
private MapBase parentMap;
|
||||
|
||||
protected MapTilePyramidLayer()
|
||||
protected TilePyramidLayer()
|
||||
{
|
||||
IsHitTestVisible = false;
|
||||
|
||||
|
|
@ -7,6 +7,8 @@ using System.Windows.Media;
|
|||
using Windows.UI.Xaml.Media;
|
||||
#elif WINUI
|
||||
using Microsoft.UI.Xaml.Media;
|
||||
#elif AVALONIA
|
||||
using ImageSource = Avalonia.Media.IImage;
|
||||
#endif
|
||||
|
||||
namespace MapControl
|
||||
|
|
@ -20,6 +22,28 @@ namespace MapControl
|
|||
[System.ComponentModel.TypeConverter(typeof(TileSourceConverter))]
|
||||
#endif
|
||||
public class TileSource
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the image request Uri for the specified zoom level and tile indices.
|
||||
/// May return null when the image shall be loaded by the LoadImageAsync method.
|
||||
/// </summary>
|
||||
public virtual Uri GetUri(int zoomLevel, int column, int row) => null;
|
||||
|
||||
/// <summary>
|
||||
/// Loads a tile image without an Uri.
|
||||
/// </summary>
|
||||
public virtual Task<ImageSource> LoadImageAsync(int zoomLevel, int column, int row) => null;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a TileSource instance from an Uri template string.
|
||||
/// </summary>
|
||||
public static TileSource Parse(string uriTemplate)
|
||||
{
|
||||
return new UriTileSource { UriTemplate = uriTemplate };
|
||||
}
|
||||
}
|
||||
|
||||
public class UriTileSource : TileSource
|
||||
{
|
||||
private string uriTemplate;
|
||||
|
||||
|
|
@ -35,20 +59,14 @@ namespace MapControl
|
|||
|
||||
if (uriTemplate != null && uriTemplate.Contains("{s}") && Subdomains == null)
|
||||
{
|
||||
Subdomains = new string[] { "a", "b", "c" }; // default OpenStreetMap subdomains
|
||||
Subdomains = ["a", "b", "c"]; // default OpenStreetMap subdomains
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets an array of request subdomain names that are replaced for the {s} format specifier.
|
||||
/// </summary>
|
||||
public string[] Subdomains { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the image Uri for the specified tile indices and zoom level.
|
||||
/// </summary>
|
||||
public virtual Uri GetUri(int zoomLevel, int column, int row)
|
||||
public override Uri GetUri(int zoomLevel, int column, int row)
|
||||
{
|
||||
Uri uri = null;
|
||||
|
||||
|
|
@ -71,41 +89,13 @@ namespace MapControl
|
|||
return uri;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Loads a tile ImageSource asynchronously from GetUri(zoomLevel, column, row).
|
||||
/// This method is called by TileImageLoader when caching is disabled.
|
||||
/// </summary>
|
||||
public virtual Task<ImageSource> LoadImageAsync(int zoomLevel, int column, int row)
|
||||
{
|
||||
var uri = GetUri(zoomLevel, column, row);
|
||||
|
||||
return uri != null ? ImageLoader.LoadImageAsync(uri) : Task.FromResult((ImageSource)null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Loads a tile ImageSource asynchronously from an encoded frame buffer in a byte array.
|
||||
/// This method is called by TileImageLoader when caching is enabled.
|
||||
/// </summary>
|
||||
public virtual Task<ImageSource> LoadImageAsync(byte[] buffer)
|
||||
{
|
||||
return ImageLoader.LoadImageAsync(buffer);
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return UriTemplate;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a TileSource instance from an Uri template string.
|
||||
/// </summary>
|
||||
public static TileSource Parse(string uriTemplate)
|
||||
{
|
||||
return new TileSource { UriTemplate = uriTemplate };
|
||||
}
|
||||
}
|
||||
|
||||
public class TmsTileSource : TileSource
|
||||
public class TmsTileSource : UriTileSource
|
||||
{
|
||||
public override Uri GetUri(int zoomLevel, int column, int row)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -110,7 +110,7 @@ namespace MapControl
|
|||
}
|
||||
}
|
||||
|
||||
public class MapProjectionConverter : TypeConverter, IValueConverter
|
||||
public partial class MapProjectionConverter : TypeConverter, IValueConverter
|
||||
{
|
||||
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ using Microsoft.UI.Xaml.Media;
|
|||
#elif AVALONIA
|
||||
using Avalonia;
|
||||
using Avalonia.Interactivity;
|
||||
using ImageSource = Avalonia.Media.IImage;
|
||||
#endif
|
||||
|
||||
namespace MapControl
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ namespace MapControl
|
|||
/// <summary>
|
||||
/// Displays map tiles from a Web Map Tile Service (WMTS).
|
||||
/// </summary>
|
||||
public partial class WmtsTileLayer : MapTilePyramidLayer
|
||||
public partial class WmtsTileLayer : TilePyramidLayer
|
||||
{
|
||||
private static ILogger logger;
|
||||
private static ILogger Logger => logger ??= ImageLoader.LoggerFactory?.CreateLogger(typeof(WmtsTileLayer));
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ namespace MapControl
|
|||
|
||||
public TileMatrix TileMatrix { get; private set; }
|
||||
|
||||
public TileCollection Tiles { get; private set; } = [];
|
||||
public ImageTileList Tiles { get; private set; } = [];
|
||||
|
||||
public void UpdateRenderTransform(ViewTransform viewTransform)
|
||||
{
|
||||
|
|
@ -85,7 +85,7 @@ namespace MapControl
|
|||
|
||||
TileMatrix = new TileMatrix(TileMatrix.ZoomLevel, xMin, yMin, xMax, yMax);
|
||||
|
||||
var tiles = new TileCollection();
|
||||
var tiles = new ImageTileList();
|
||||
tiles.FillMatrix(Tiles, TileMatrix.ZoomLevel, xMin, yMin, xMax, yMax, WmtsTileMatrix.MatrixWidth);
|
||||
|
||||
Tiles = tiles;
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ using System.Text;
|
|||
|
||||
namespace MapControl
|
||||
{
|
||||
public class WmtsTileSource : TileSource
|
||||
public class WmtsTileSource : UriTileSource
|
||||
{
|
||||
public WmtsTileMatrixSet TileMatrixSet { get; set; }
|
||||
|
||||
|
|
|
|||
|
|
@ -8,9 +8,12 @@ using System.Windows.Media.Imaging;
|
|||
|
||||
namespace MapControl
|
||||
{
|
||||
public partial class Tile
|
||||
public class ImageTile(int zoomLevel, int x, int y, int columnCount)
|
||||
: Tile(zoomLevel, x, y, columnCount)
|
||||
{
|
||||
public async Task LoadImageAsync(Func<Task<ImageSource>> loadImageFunc)
|
||||
public Image Image { get; } = new Image { Stretch = Stretch.Fill };
|
||||
|
||||
public override async Task LoadImageAsync(Func<Task<ImageSource>> loadImageFunc)
|
||||
{
|
||||
var image = await loadImageFunc().ConfigureAwait(false);
|
||||
|
||||
|
|
@ -3,12 +3,14 @@ using System.Threading.Tasks;
|
|||
#if UWP
|
||||
using Windows.UI.Core;
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
using Windows.UI.Xaml.Media;
|
||||
using Windows.UI.Xaml.Media.Animation;
|
||||
using Windows.UI.Xaml.Media.Imaging;
|
||||
#else
|
||||
using Microsoft.UI.Dispatching;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Microsoft.UI.Xaml.Media;
|
||||
using Microsoft.UI.Xaml.Media.Animation;
|
||||
using Microsoft.UI.Xaml.Media.Imaging;
|
||||
|
|
@ -16,9 +18,12 @@ using Microsoft.UI.Xaml.Media.Imaging;
|
|||
|
||||
namespace MapControl
|
||||
{
|
||||
public partial class Tile
|
||||
public class ImageTile(int zoomLevel, int x, int y, int columnCount)
|
||||
: Tile(zoomLevel, x, y, columnCount)
|
||||
{
|
||||
public async Task LoadImageAsync(Func<Task<ImageSource>> loadImageFunc)
|
||||
public Image Image { get; } = new Image { Stretch = Stretch.Fill };
|
||||
|
||||
public override async Task LoadImageAsync(Func<Task<ImageSource>> loadImageFunc)
|
||||
{
|
||||
var tcs = new TaskCompletionSource<object>();
|
||||
|
||||
Loading…
Reference in a new issue