mirror of
https://github.com/ClemensFischer/XAML-Map-Control.git
synced 2025-12-06 07:12:04 +01:00
TileSources, WMTS
This commit is contained in:
parent
605185db6e
commit
ce7c33f6e4
|
|
@ -1,5 +1,6 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
namespace MapControl
|
namespace MapControl
|
||||||
{
|
{
|
||||||
|
|
@ -23,9 +24,21 @@ namespace MapControl
|
||||||
var s = south.ToString("F2", CultureInfo.InvariantCulture);
|
var s = south.ToString("F2", CultureInfo.InvariantCulture);
|
||||||
var n = north.ToString("F2", CultureInfo.InvariantCulture);
|
var n = north.ToString("F2", CultureInfo.InvariantCulture);
|
||||||
|
|
||||||
uri = UriTemplate.Contains("{bbox}")
|
if (UriTemplate.Contains("{bbox}"))
|
||||||
? new Uri(UriTemplate.Replace("{bbox}", $"{w},{s},{e},{n}"))
|
{
|
||||||
: new Uri(UriTemplate.Replace("{west}", w).Replace("{south}", s).Replace("{east}", e).Replace("{north}", n));
|
uri = new Uri(UriTemplate.Replace("{bbox}", $"{w},{s},{e},{n}"));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var uriBuilder = new StringBuilder(UriTemplate);
|
||||||
|
|
||||||
|
uriBuilder.Replace("{west}", w);
|
||||||
|
uriBuilder.Replace("{south}", s);
|
||||||
|
uriBuilder.Replace("{east}", e);
|
||||||
|
uriBuilder.Replace("{north}", n);
|
||||||
|
|
||||||
|
uri = new Uri(uriBuilder.ToString());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return uri;
|
return uri;
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Threading;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
#if WPF
|
#if WPF
|
||||||
using System.Windows.Media;
|
using System.Windows.Media;
|
||||||
|
|
@ -54,17 +54,18 @@ namespace MapControl
|
||||||
|
|
||||||
if (UriTemplate != null)
|
if (UriTemplate != null)
|
||||||
{
|
{
|
||||||
var uriString = UriTemplate
|
var uriBuilder = new StringBuilder(UriTemplate);
|
||||||
.Replace("{z}", zoomLevel.ToString())
|
|
||||||
.Replace("{x}", column.ToString())
|
uriBuilder.Replace("{z}", zoomLevel.ToString());
|
||||||
.Replace("{y}", row.ToString());
|
uriBuilder.Replace("{x}", column.ToString());
|
||||||
|
uriBuilder.Replace("{y}", row.ToString());
|
||||||
|
|
||||||
if (Subdomains != null && Subdomains.Length > 0)
|
if (Subdomains != null && Subdomains.Length > 0)
|
||||||
{
|
{
|
||||||
uriString = uriString.Replace("{s}", Subdomains[(column + row) % Subdomains.Length]);
|
uriBuilder.Replace("{s}", Subdomains[(column + row) % Subdomains.Length]);
|
||||||
}
|
}
|
||||||
|
|
||||||
uri = new Uri(uriString, UriKind.RelativeOrAbsolute);
|
uri = new Uri(uriBuilder.ToString(), UriKind.RelativeOrAbsolute);
|
||||||
}
|
}
|
||||||
|
|
||||||
return uri;
|
return uri;
|
||||||
|
|
|
||||||
|
|
@ -23,28 +23,28 @@ namespace MapControl
|
||||||
private static readonly XNamespace xlink = "http://www.w3.org/1999/xlink";
|
private static readonly XNamespace xlink = "http://www.w3.org/1999/xlink";
|
||||||
|
|
||||||
public string Layer { get; private set; }
|
public string Layer { get; private set; }
|
||||||
public string UrlTemplate { get; private set; }
|
public string UriTemplate { get; private set; }
|
||||||
public List<WmtsTileMatrixSet> TileMatrixSets { get; private set; }
|
public List<WmtsTileMatrixSet> TileMatrixSets { get; private set; }
|
||||||
|
|
||||||
public static async Task<WmtsCapabilities> ReadCapabilitiesAsync(Uri uri, string layer)
|
public static async Task<WmtsCapabilities> ReadCapabilitiesAsync(Uri uri, string layer)
|
||||||
{
|
{
|
||||||
Stream xmlStream;
|
Stream xmlStream;
|
||||||
string defaultUrl = null;
|
string defaultUri = null;
|
||||||
|
|
||||||
if (!uri.IsAbsoluteUri)
|
if (!uri.IsAbsoluteUri)
|
||||||
{
|
{
|
||||||
xmlStream = File.OpenRead(uri.OriginalString);
|
xmlStream = File.OpenRead(uri.OriginalString);
|
||||||
}
|
}
|
||||||
else if (uri.Scheme == Uri.UriSchemeHttp || uri.Scheme == Uri.UriSchemeHttps)
|
|
||||||
{
|
|
||||||
defaultUrl = uri.OriginalString.Split('?')[0];
|
|
||||||
|
|
||||||
xmlStream = await ImageLoader.HttpClient.GetStreamAsync(uri);
|
|
||||||
}
|
|
||||||
else if (uri.IsFile)
|
else if (uri.IsFile)
|
||||||
{
|
{
|
||||||
xmlStream = File.OpenRead(uri.LocalPath);
|
xmlStream = File.OpenRead(uri.LocalPath);
|
||||||
}
|
}
|
||||||
|
else if (uri.Scheme == Uri.UriSchemeHttp || uri.Scheme == Uri.UriSchemeHttps)
|
||||||
|
{
|
||||||
|
defaultUri = uri.OriginalString.Split('?')[0];
|
||||||
|
|
||||||
|
xmlStream = await ImageLoader.HttpClient.GetStreamAsync(uri);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
throw new ArgumentException($"Invalid Capabilities URI: {uri}");
|
throw new ArgumentException($"Invalid Capabilities URI: {uri}");
|
||||||
|
|
@ -54,10 +54,10 @@ namespace MapControl
|
||||||
|
|
||||||
var element = await XDocument.LoadRootElementAsync(stream);
|
var element = await XDocument.LoadRootElementAsync(stream);
|
||||||
|
|
||||||
return ReadCapabilities(element, layer, defaultUrl);
|
return ReadCapabilities(element, layer, defaultUri);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static WmtsCapabilities ReadCapabilities(XElement capabilitiesElement, string layer, string defaultUrl)
|
public static WmtsCapabilities ReadCapabilities(XElement capabilitiesElement, string layer, string defaultUri)
|
||||||
{
|
{
|
||||||
var contentsElement = capabilitiesElement.Element(wmts + "Contents") ??
|
var contentsElement = capabilitiesElement.Element(wmts + "Contents") ??
|
||||||
throw new ArgumentException("Contents element not found.");
|
throw new ArgumentException("Contents element not found.");
|
||||||
|
|
@ -68,23 +68,15 @@ namespace MapControl
|
||||||
{
|
{
|
||||||
layerElement = contentsElement
|
layerElement = contentsElement
|
||||||
.Elements(wmts + "Layer")
|
.Elements(wmts + "Layer")
|
||||||
.FirstOrDefault(l => l.Element(ows + "Identifier")?.Value == layer);
|
.FirstOrDefault(l => l.Element(ows + "Identifier")?.Value == layer) ??
|
||||||
|
|
||||||
if (layerElement == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentException($"Layer element \"{layer}\" not found.");
|
throw new ArgumentException($"Layer element \"{layer}\" not found.");
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
layerElement = contentsElement
|
layerElement = contentsElement
|
||||||
.Elements(wmts + "Layer")
|
.Elements(wmts + "Layer")
|
||||||
.FirstOrDefault();
|
.FirstOrDefault() ??
|
||||||
|
|
||||||
if (layerElement == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentException("No Layer element found.");
|
throw new ArgumentException("No Layer element found.");
|
||||||
}
|
|
||||||
|
|
||||||
layer = layerElement.Element(ows + "Identifier")?.Value ?? "";
|
layer = layerElement.Element(ows + "Identifier")?.Value ?? "";
|
||||||
}
|
}
|
||||||
|
|
@ -98,7 +90,7 @@ namespace MapControl
|
||||||
|
|
||||||
var style = styleElement?.Element(ows + "Identifier")?.Value ?? "";
|
var style = styleElement?.Element(ows + "Identifier")?.Value ?? "";
|
||||||
|
|
||||||
var urlTemplate = ReadUrlTemplate(capabilitiesElement, layerElement, layer, style, defaultUrl);
|
var uriTemplate = ReadUriTemplate(capabilitiesElement, layerElement, layer, style, defaultUri);
|
||||||
|
|
||||||
var tileMatrixSetIds = layerElement
|
var tileMatrixSetIds = layerElement
|
||||||
.Elements(wmts + "TileMatrixSetLink")
|
.Elements(wmts + "TileMatrixSetLink")
|
||||||
|
|
@ -120,16 +112,16 @@ namespace MapControl
|
||||||
return new WmtsCapabilities
|
return new WmtsCapabilities
|
||||||
{
|
{
|
||||||
Layer = layer,
|
Layer = layer,
|
||||||
UrlTemplate = urlTemplate,
|
UriTemplate = uriTemplate,
|
||||||
TileMatrixSets = tileMatrixSets
|
TileMatrixSets = tileMatrixSets
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string ReadUrlTemplate(XElement capabilitiesElement, XElement layerElement, string layer, string style, string defaultUrl)
|
public static string ReadUriTemplate(XElement capabilitiesElement, XElement layerElement, string layer, string style, string defaultUri)
|
||||||
{
|
{
|
||||||
const string formatPng = "image/png";
|
const string formatPng = "image/png";
|
||||||
const string formatJpg = "image/jpeg";
|
const string formatJpg = "image/jpeg";
|
||||||
string urlTemplate = null;
|
string uriTemplate = null;
|
||||||
|
|
||||||
var resourceUrls = layerElement
|
var resourceUrls = layerElement
|
||||||
.Elements(wmts + "ResourceURL")
|
.Elements(wmts + "ResourceURL")
|
||||||
|
|
@ -141,15 +133,15 @@ namespace MapControl
|
||||||
|
|
||||||
if (resourceUrls.Count != 0)
|
if (resourceUrls.Count != 0)
|
||||||
{
|
{
|
||||||
var urlTemplates = resourceUrls.Contains(formatPng) ? resourceUrls[formatPng]
|
var uriTemplates = resourceUrls.Contains(formatPng) ? resourceUrls[formatPng]
|
||||||
: resourceUrls.Contains(formatJpg) ? resourceUrls[formatJpg]
|
: resourceUrls.Contains(formatJpg) ? resourceUrls[formatJpg]
|
||||||
: resourceUrls.First();
|
: resourceUrls.First();
|
||||||
|
|
||||||
urlTemplate = urlTemplates.First().Replace("{Style}", style);
|
uriTemplate = uriTemplates.First().Replace("{Style}", style);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
urlTemplate = capabilitiesElement
|
uriTemplate = capabilitiesElement
|
||||||
.Elements(ows + "OperationsMetadata")
|
.Elements(ows + "OperationsMetadata")
|
||||||
.Elements(ows + "Operation")
|
.Elements(ows + "Operation")
|
||||||
.Where(o => o.Attribute("name")?.Value == "GetTile")
|
.Where(o => o.Attribute("name")?.Value == "GetTile")
|
||||||
|
|
@ -163,9 +155,9 @@ namespace MapControl
|
||||||
.Where(h => !string.IsNullOrEmpty(h))
|
.Where(h => !string.IsNullOrEmpty(h))
|
||||||
.Select(h => h.Split('?')[0])
|
.Select(h => h.Split('?')[0])
|
||||||
.FirstOrDefault() ??
|
.FirstOrDefault() ??
|
||||||
defaultUrl;
|
defaultUri;
|
||||||
|
|
||||||
if (urlTemplate != null)
|
if (uriTemplate != null)
|
||||||
{
|
{
|
||||||
var formats = layerElement
|
var formats = layerElement
|
||||||
.Elements(wmts + "Format")
|
.Elements(wmts + "Format")
|
||||||
|
|
@ -180,7 +172,7 @@ namespace MapControl
|
||||||
format = formatPng;
|
format = formatPng;
|
||||||
}
|
}
|
||||||
|
|
||||||
urlTemplate += "?Service=WMTS"
|
uriTemplate += "?Service=WMTS"
|
||||||
+ "&Request=GetTile"
|
+ "&Request=GetTile"
|
||||||
+ "&Version=1.0.0"
|
+ "&Version=1.0.0"
|
||||||
+ "&Layer=" + layer
|
+ "&Layer=" + layer
|
||||||
|
|
@ -193,12 +185,12 @@ namespace MapControl
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(urlTemplate))
|
if (string.IsNullOrEmpty(uriTemplate))
|
||||||
{
|
{
|
||||||
throw new ArgumentException($"No ResourceURL element in Layer \"{layer}\" and no GetTile KVP Operation Metadata found.");
|
throw new ArgumentException($"No ResourceURL element in Layer \"{layer}\" and no GetTile KVP Operation Metadata found.");
|
||||||
}
|
}
|
||||||
|
|
||||||
return urlTemplate;
|
return uriTemplate;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static WmtsTileMatrixSet ReadTileMatrixSet(XElement tileMatrixSetElement)
|
public static WmtsTileMatrixSet ReadTileMatrixSet(XElement tileMatrixSetElement)
|
||||||
|
|
@ -301,8 +293,12 @@ namespace MapControl
|
||||||
? new Point(MapProjection.Wgs84MeterPerDegree * top, MapProjection.Wgs84MeterPerDegree * left)
|
? new Point(MapProjection.Wgs84MeterPerDegree * top, MapProjection.Wgs84MeterPerDegree * left)
|
||||||
: new Point(left, top);
|
: new Point(left, top);
|
||||||
|
|
||||||
return new WmtsTileMatrix(
|
// See 07-057r7_Web_Map_Tile_Service_Standard.pdf, section 6.1.a, page 8:
|
||||||
identifier, scaleDenominator, topLeft, tileWidth, tileHeight, matrixWidth, matrixHeight);
|
// "standardized rendering pixel size" is 0.28 mm.
|
||||||
|
//
|
||||||
|
return new WmtsTileMatrix(identifier,
|
||||||
|
1d / (scaleDenominator * 0.00028),
|
||||||
|
topLeft, tileWidth, tileHeight, matrixWidth, matrixHeight);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -80,8 +80,6 @@ namespace MapControl
|
||||||
|
|
||||||
protected IEnumerable<WmtsTileMatrixLayer> ChildLayers => Children.Cast<WmtsTileMatrixLayer>();
|
protected IEnumerable<WmtsTileMatrixLayer> ChildLayers => Children.Cast<WmtsTileMatrixLayer>();
|
||||||
|
|
||||||
protected virtual WmtsTileSource CreateTileSource(string uriTemplate) => new() { UriTemplate = uriTemplate };
|
|
||||||
|
|
||||||
protected override Size MeasureOverride(Size availableSize)
|
protected override Size MeasureOverride(Size availableSize)
|
||||||
{
|
{
|
||||||
foreach (var layer in ChildLayers)
|
foreach (var layer in ChildLayers)
|
||||||
|
|
@ -126,8 +124,11 @@ namespace MapControl
|
||||||
cacheName += "/" + Layer.Replace(':', '_');
|
cacheName += "/" + Layer.Replace(':', '_');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(tileMatrixSet.Identifier))
|
||||||
|
{
|
||||||
cacheName += "/" + tileMatrixSet.Identifier.Replace(':', '_');
|
cacheName += "/" + tileMatrixSet.Identifier.Replace(':', '_');
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
BeginLoadTiles(ChildLayers.SelectMany(layer => layer.Tiles), cacheName);
|
BeginLoadTiles(ChildLayers.SelectMany(layer => layer.Tiles), cacheName);
|
||||||
}
|
}
|
||||||
|
|
@ -207,7 +208,7 @@ namespace MapControl
|
||||||
}
|
}
|
||||||
|
|
||||||
Layer = capabilities.Layer;
|
Layer = capabilities.Layer;
|
||||||
TileSource = CreateTileSource(capabilities.UrlTemplate);
|
TileSource = new WmtsTileSource { UriTemplate = capabilities.UriTemplate };
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -6,15 +6,12 @@ using Avalonia;
|
||||||
|
|
||||||
namespace MapControl
|
namespace MapControl
|
||||||
{
|
{
|
||||||
// See 07-057r7_Web_Map_Tile_Service_Standard.pdf, section 6.1.a, page 8:
|
|
||||||
// "standardized rendering pixel size" is 0.28 mm
|
|
||||||
//
|
|
||||||
public class WmtsTileMatrix(
|
public class WmtsTileMatrix(
|
||||||
string identifier, double scaleDenominator, Point topLeft,
|
string identifier, double scale, Point topLeft,
|
||||||
int tileWidth, int tileHeight, int matrixWidth, int matrixHeight)
|
int tileWidth, int tileHeight, int matrixWidth, int matrixHeight)
|
||||||
{
|
{
|
||||||
public string Identifier { get; } = identifier;
|
public string Identifier { get; } = identifier;
|
||||||
public double Scale { get; } = 1 / (scaleDenominator * 0.00028); // 0.28 mm
|
public double Scale { get; } = scale;
|
||||||
public Point TopLeft { get; } = topLeft;
|
public Point TopLeft { get; } = topLeft;
|
||||||
public int TileWidth { get; } = tileWidth;
|
public int TileWidth { get; } = tileWidth;
|
||||||
public int TileHeight { get; } = tileHeight;
|
public int TileHeight { get; } = tileHeight;
|
||||||
|
|
|
||||||
|
|
@ -8,11 +8,6 @@ namespace MapControl
|
||||||
{
|
{
|
||||||
public WmtsTileMatrixSet(string identifier, string supportedCrs, IEnumerable<WmtsTileMatrix> tileMatrixes)
|
public WmtsTileMatrixSet(string identifier, string supportedCrs, IEnumerable<WmtsTileMatrix> tileMatrixes)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(identifier))
|
|
||||||
{
|
|
||||||
throw new ArgumentException($"The {nameof(identifier)} argument must not be null or empty.", nameof(identifier));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(supportedCrs))
|
if (string.IsNullOrEmpty(supportedCrs))
|
||||||
{
|
{
|
||||||
throw new ArgumentException($"The {nameof(supportedCrs)} argument must not be null or empty.", nameof(supportedCrs));
|
throw new ArgumentException($"The {nameof(supportedCrs)} argument must not be null or empty.", nameof(supportedCrs));
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
using System;
|
using System;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
namespace MapControl
|
namespace MapControl
|
||||||
{
|
{
|
||||||
|
|
@ -14,11 +15,14 @@ namespace MapControl
|
||||||
TileMatrixSet != null &&
|
TileMatrixSet != null &&
|
||||||
TileMatrixSet.TileMatrixes.Count > zoomLevel)
|
TileMatrixSet.TileMatrixes.Count > zoomLevel)
|
||||||
{
|
{
|
||||||
uri = new Uri(UriTemplate
|
var uriBuilder = new StringBuilder(UriTemplate);
|
||||||
.Replace("{TileMatrixSet}", TileMatrixSet.Identifier)
|
|
||||||
.Replace("{TileMatrix}", TileMatrixSet.TileMatrixes[zoomLevel].Identifier)
|
uriBuilder.Replace("{TileMatrixSet}", TileMatrixSet.Identifier);
|
||||||
.Replace("{TileCol}", column.ToString())
|
uriBuilder.Replace("{TileMatrix}", TileMatrixSet.TileMatrixes[zoomLevel].Identifier);
|
||||||
.Replace("{TileRow}", row.ToString()));
|
uriBuilder.Replace("{TileCol}", column.ToString());
|
||||||
|
uriBuilder.Replace("{TileRow}", row.ToString());
|
||||||
|
|
||||||
|
uri = new Uri(uriBuilder.ToString());
|
||||||
}
|
}
|
||||||
|
|
||||||
return uri;
|
return uri;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue