From 0d70887d374901e5a1b89c778e70ba7c2c7a5728 Mon Sep 17 00:00:00 2001 From: ClemensF Date: Mon, 13 Jul 2020 17:48:06 +0200 Subject: [PATCH] Added WMS GetFeatureInfo support --- MapControl/Shared/MapScale.cs | 1 - MapControl/Shared/MapTileLayerBase.cs | 1 - MapControl/Shared/WmsImageLayer.cs | 125 ++++++++++++++++++++--- MapControl/Shared/WmtsTileLayer.cs | 2 - MapControl/Shared/WmtsTileMatrixLayer.cs | 1 - MapControl/UWP/MapGraticule.UWP.cs | 1 - MapControl/WPF/MapGraticule.WPF.cs | 1 - SampleApps/Shared/MapLayers.cs | 4 +- 8 files changed, 111 insertions(+), 25 deletions(-) diff --git a/MapControl/Shared/MapScale.cs b/MapControl/Shared/MapScale.cs index a2c8d36c..371146f6 100644 --- a/MapControl/Shared/MapScale.cs +++ b/MapControl/Shared/MapScale.cs @@ -37,7 +37,6 @@ namespace MapControl public MapScale() { - IsHitTestVisible = false; MinWidth = 100d; line.SetBinding(Shape.StrokeProperty, GetBinding(StrokeProperty, nameof(Stroke))); diff --git a/MapControl/Shared/MapTileLayerBase.cs b/MapControl/Shared/MapTileLayerBase.cs index 172ff119..61ae4b98 100644 --- a/MapControl/Shared/MapTileLayerBase.cs +++ b/MapControl/Shared/MapTileLayerBase.cs @@ -54,7 +54,6 @@ namespace MapControl protected MapTileLayerBase(ITileImageLoader tileImageLoader) { - IsHitTestVisible = false; RenderTransform = new MatrixTransform(); TileImageLoader = tileImageLoader; diff --git a/MapControl/Shared/WmsImageLayer.cs b/MapControl/Shared/WmsImageLayer.cs index 0d5191c9..cc6cbf7c 100644 --- a/MapControl/Shared/WmsImageLayer.cs +++ b/MapControl/Shared/WmsImageLayer.cs @@ -64,27 +64,21 @@ namespace MapControl } /// - /// Gets a list of all layer names returned by a GetCapabilities response. + /// Calls GetCapabilitiesRequestUri() and asynchronously loads an XElement from the returned URL. /// - public async Task> GetLayerNamesAsync() + public async Task GetCapabilitiesAsync() { - IEnumerable layerNames = null; + XElement element = null; if (ServiceUri != null) { - var uri = GetRequestUri("GetCapabilities").Replace(" ", "%20"); + var uri = GetCapabilitiesRequestUri(); try { using (var stream = await ImageLoader.HttpClient.GetStreamAsync(uri)) { - var capabilities = XDocument.Load(stream).Root; - var ns = capabilities.Name.Namespace; - - layerNames = capabilities - .Descendants(ns + "Layer") - .Select(e => e.Element(ns + "Name")?.Value) - .Where(n => !string.IsNullOrEmpty(n)); + element = XDocument.Load(stream).Root; } } catch (Exception ex) @@ -93,11 +87,60 @@ namespace MapControl } } + return element; + } + + /// + /// Calls GetFeatureInfoRequestUri() and asynchronously loads an XElement from the returned URL. + /// + public async Task GetFeatureInfoAsync(Point position) + { + XElement element = null; + + if (ServiceUri != null) + { + var uri = GetFeatureInfoRequestUri(position); + + try + { + using (var stream = await ImageLoader.HttpClient.GetStreamAsync(uri)) + { + element = XDocument.Load(stream).Root; + } + } + catch (Exception ex) + { + Debug.WriteLine("WmsImageLayer: {0}: {1}", uri, ex.Message); + } + } + + return element; + } + + /// + /// Gets a list of all layer names returned by a GetCapabilities response. + /// + public async Task> GetLayerNamesAsync() + { + IEnumerable layerNames = null; + + var capabilities = await GetCapabilitiesAsync(); + + if (capabilities != null) + { + var ns = capabilities.Name.Namespace; + + layerNames = capabilities + .Descendants(ns + "Layer") + .Select(e => e.Element(ns + "Name")?.Value) + .Where(n => !string.IsNullOrEmpty(n)); + } + return layerNames; } /// - /// Calls GetImageUri() and asynchronously loads an ImageSource from the returned GetMap URL. + /// Calls GetMapRequestUri() and asynchronously loads an ImageSource from the returned URL. /// protected override async Task GetImageAsync() { @@ -111,21 +154,29 @@ namespace MapControl Layers = (await GetLayerNamesAsync())?.FirstOrDefault() ?? ""; // get first Layer from Capabilities } - var uri = GetImageUri(); + var uri = GetMapRequestUri(); if (!string.IsNullOrEmpty(uri)) { - image = await ImageLoader.LoadImageAsync(new Uri(uri.Replace(" ", "%20"))); + image = await ImageLoader.LoadImageAsync(new Uri(uri)); } } return image; } + /// + /// Returns a GetCapabilities request URL string. + /// + protected virtual string GetCapabilitiesRequestUri() + { + return GetRequestUri("GetCapabilities").Replace(" ", "%20"); + } + /// /// Returns a GetMap request URL string. /// - protected virtual string GetImageUri() + protected virtual string GetMapRequestUri() { string uri = null; var projection = ParentMap?.MapProjection; @@ -157,7 +208,49 @@ namespace MapControl uri += "&HEIGHT=" + (int)Math.Round(ParentMap.ViewTransform.Scale * rect.Height); } - return uri; + return uri.Replace(" ", "%20"); + } + + /// + /// Returns a GetFeatureInfo request URL string. + /// + protected virtual string GetFeatureInfoRequestUri(Point position) + { + string uri = null; + var projection = ParentMap?.MapProjection; + + if (projection != null && !string.IsNullOrEmpty(projection.CrsId)) + { + uri = GetRequestUri("GetFeatureInfo"); + + var i = uri.IndexOf("LAYERS=", StringComparison.OrdinalIgnoreCase); + + if (i >= 0) + { + i += 7; + var j = uri.IndexOf('&', i); + var layers = j >= i ? uri.Substring(i, j - i) : uri.Substring(i); + uri += "&QUERY_LAYERS=" + layers; + } + else if (Layers != null) + { + uri += "&LAYERS=" + Layers; + uri += "&QUERY_LAYERS=" + Layers; + } + + var rect = projection.BoundingBoxToRect(BoundingBox); + var pos = ParentMap.TransformToVisual(Children[1]).Transform(position); // top Image element + + uri += "&CRS=" + projection.GetCrsValue(); + uri += "&BBOX=" + projection.GetBboxValue(rect); + uri += "&WIDTH=" + (int)Math.Round(ParentMap.ViewTransform.Scale * rect.Width); + uri += "&HEIGHT=" + (int)Math.Round(ParentMap.ViewTransform.Scale * rect.Height); + uri += "&I=" + (int)Math.Round(pos.X); + uri += "&J=" + (int)Math.Round(pos.Y); + uri += "&INFO_FORMAT=text/xml"; + } + + return uri.Replace(" ", "%20"); } private string GetRequestUri(string request) diff --git a/MapControl/Shared/WmtsTileLayer.cs b/MapControl/Shared/WmtsTileLayer.cs index 7a85ffdc..20d2df4a 100644 --- a/MapControl/Shared/WmtsTileLayer.cs +++ b/MapControl/Shared/WmtsTileLayer.cs @@ -35,8 +35,6 @@ namespace MapControl public WmtsTileLayer(ITileImageLoader tileImageLoader) : base(tileImageLoader) { - IsHitTestVisible = false; - Loaded += OnLoaded; } diff --git a/MapControl/Shared/WmtsTileMatrixLayer.cs b/MapControl/Shared/WmtsTileMatrixLayer.cs index 86a6dc46..560705dc 100644 --- a/MapControl/Shared/WmtsTileMatrixLayer.cs +++ b/MapControl/Shared/WmtsTileMatrixLayer.cs @@ -21,7 +21,6 @@ namespace MapControl { public WmtsTileMatrixLayer(WmtsTileMatrix tileMatrix, int zoomLevel) { - IsHitTestVisible = false; RenderTransform = new MatrixTransform(); TileMatrix = tileMatrix; ZoomLevel = zoomLevel; diff --git a/MapControl/UWP/MapGraticule.UWP.cs b/MapControl/UWP/MapGraticule.UWP.cs index f5d61348..4df47b9f 100644 --- a/MapControl/UWP/MapGraticule.UWP.cs +++ b/MapControl/UWP/MapGraticule.UWP.cs @@ -16,7 +16,6 @@ namespace MapControl public MapGraticule() { - IsHitTestVisible = false; StrokeThickness = 0.5; } diff --git a/MapControl/WPF/MapGraticule.WPF.cs b/MapControl/WPF/MapGraticule.WPF.cs index ad9ebfe0..797b7ee1 100644 --- a/MapControl/WPF/MapGraticule.WPF.cs +++ b/MapControl/WPF/MapGraticule.WPF.cs @@ -26,7 +26,6 @@ namespace MapControl static MapGraticule() { - IsHitTestVisibleProperty.OverrideMetadata(typeof(MapGraticule), new FrameworkPropertyMetadata(false)); StrokeThicknessProperty.OverrideMetadata(typeof(MapGraticule), new FrameworkPropertyMetadata(0.5)); } diff --git a/SampleApps/Shared/MapLayers.cs b/SampleApps/Shared/MapLayers.cs index 3abdf34d..17747423 100644 --- a/SampleApps/Shared/MapLayers.cs +++ b/SampleApps/Shared/MapLayers.cs @@ -195,9 +195,9 @@ namespace ViewModel MaxBoundingBoxWidth = 360; } - protected override string GetImageUri() + protected override string GetMapRequestUri() { - return base.GetImageUri() + return base.GetMapRequestUri() .Replace("&CRS=AUTO2:97001,", "&CRS=AUTO2:7CS01,") .Replace("&CRS=AUTO2:97002,", "&CRS=AUTO2:7CS02,"); }