Version 4.12.1 Added AutoEquirectangularProjection

This commit is contained in:
ClemensF 2019-04-05 19:13:58 +02:00
parent 0a3ae81117
commit bd9a16e921
17 changed files with 174 additions and 140 deletions

View file

@ -46,7 +46,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.NETCore.UniversalWindowsPlatform"> <PackageReference Include="Microsoft.NETCore.UniversalWindowsPlatform">
<Version>6.2.2</Version> <Version>6.2.8</Version>
</PackageReference> </PackageReference>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View file

@ -54,10 +54,10 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.Data.SQLite"> <PackageReference Include="Microsoft.Data.SQLite">
<Version>2.2.0</Version> <Version>2.2.3</Version>
</PackageReference> </PackageReference>
<PackageReference Include="Microsoft.NETCore.UniversalWindowsPlatform"> <PackageReference Include="Microsoft.NETCore.UniversalWindowsPlatform">
<Version>6.2.2</Version> <Version>6.2.8</Version>
</PackageReference> </PackageReference>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View file

@ -3,7 +3,6 @@
// Licensed under the Microsoft Public License (Ms-PL) // Licensed under the Microsoft Public License (Ms-PL)
using System; using System;
using System.Globalization;
#if WINDOWS_UWP #if WINDOWS_UWP
using Windows.Foundation; using Windows.Foundation;
#else #else
@ -14,8 +13,6 @@ namespace MapControl
{ {
public class AutoEquirectangularProjection : MapProjection public class AutoEquirectangularProjection : MapProjection
{ {
public Location ProjectionCenter { get; private set; } = new Location();
public AutoEquirectangularProjection() public AutoEquirectangularProjection()
: this("AUTO2:42004") : this("AUTO2:42004")
{ {
@ -29,44 +26,20 @@ namespace MapControl
public override Point LocationToPoint(Location location) public override Point LocationToPoint(Location location)
{ {
var xScale = MetersPerDegree * Math.Cos(ProjectionCenter.Latitude * Math.PI / 180d); var xScale = Wgs84MetersPerDegree * Math.Cos(ProjectionCenter.Latitude * Math.PI / 180d);
return new Point( return new Point(
xScale * (location.Longitude - ProjectionCenter.Longitude), xScale * (location.Longitude - ProjectionCenter.Longitude),
MetersPerDegree * location.Latitude); Wgs84MetersPerDegree * location.Latitude);
} }
public override Location PointToLocation(Point point) public override Location PointToLocation(Point point)
{ {
var xScale = MetersPerDegree * Math.Cos(ProjectionCenter.Latitude * Math.PI / 180d); var xScale = Wgs84MetersPerDegree * Math.Cos(ProjectionCenter.Latitude * Math.PI / 180d);
return new Location( return new Location(
point.Y / MetersPerDegree, point.Y / Wgs84MetersPerDegree,
point.X / xScale + ProjectionCenter.Longitude); point.X / xScale + ProjectionCenter.Longitude);
} }
public override void SetViewportTransform(Location projectionCenter, Location mapCenter, Point viewportCenter, double zoomLevel, double heading)
{
ProjectionCenter = projectionCenter;
base.SetViewportTransform(projectionCenter, mapCenter, viewportCenter, zoomLevel, heading);
}
public override string WmsQueryParameters(BoundingBox boundingBox)
{
if (string.IsNullOrEmpty(CrsId))
{
return null;
}
var rect = BoundingBoxToRect(boundingBox);
var width = (int)Math.Round(ViewportScale * rect.Width);
var height = (int)Math.Round(ViewportScale * rect.Height);
return string.Format(CultureInfo.InvariantCulture,
"CRS={0},1,{1},{2}&BBOX={3},{4},{5},{6}&WIDTH={7}&HEIGHT={8}",
CrsId, ProjectionCenter.Longitude, ProjectionCenter.Latitude,
rect.X, rect.Y, (rect.X + rect.Width), (rect.Y + rect.Height), width, height);
}
} }
} }

View file

@ -35,9 +35,9 @@ namespace MapControl
GetAzimuthDistance(ProjectionCenter, location, out azimuth, out distance); GetAzimuthDistance(ProjectionCenter, location, out azimuth, out distance);
distance *= TrueScale * 180d / Math.PI; var mapDistance = distance * TrueScale * 180d / Math.PI;
return new Point(distance * Math.Sin(azimuth), distance * Math.Cos(azimuth)); return new Point(mapDistance * Math.Sin(azimuth), mapDistance * Math.Cos(azimuth));
} }
public override Location PointToLocation(Point point) public override Location PointToLocation(Point point)
@ -48,7 +48,9 @@ namespace MapControl
} }
var azimuth = Math.Atan2(point.X, point.Y); var azimuth = Math.Atan2(point.X, point.Y);
var distance = Math.Sqrt(point.X * point.X + point.Y * point.Y) / (TrueScale * 180d / Math.PI); var mapDistance = Math.Sqrt(point.X * point.X + point.Y * point.Y);
var distance = mapDistance / (TrueScale * 180d / Math.PI);
return GetLocation(ProjectionCenter, azimuth, distance); return GetLocation(ProjectionCenter, azimuth, distance);
} }

View file

@ -3,7 +3,6 @@
// Licensed under the Microsoft Public License (Ms-PL) // Licensed under the Microsoft Public License (Ms-PL)
using System; using System;
using System.Globalization;
#if WINDOWS_UWP #if WINDOWS_UWP
using Windows.Foundation; using Windows.Foundation;
#else #else
@ -17,8 +16,6 @@ namespace MapControl
/// </summary> /// </summary>
public abstract class AzimuthalProjection : MapProjection public abstract class AzimuthalProjection : MapProjection
{ {
public Location ProjectionCenter { get; private set; } = new Location();
public override Rect BoundingBoxToRect(BoundingBox boundingBox) public override Rect BoundingBoxToRect(BoundingBox boundingBox)
{ {
var cbbox = boundingBox as CenteredBoundingBox; var cbbox = boundingBox as CenteredBoundingBox;
@ -42,30 +39,6 @@ namespace MapControl
return new CenteredBoundingBox(center, rect.Width, rect.Height); // width and height in meters return new CenteredBoundingBox(center, rect.Width, rect.Height); // width and height in meters
} }
public override void SetViewportTransform(Location projectionCenter, Location mapCenter, Point viewportCenter, double zoomLevel, double heading)
{
ProjectionCenter = projectionCenter;
base.SetViewportTransform(projectionCenter, mapCenter, viewportCenter, zoomLevel, heading);
}
public override string WmsQueryParameters(BoundingBox boundingBox)
{
if (string.IsNullOrEmpty(CrsId))
{
return null;
}
var rect = BoundingBoxToRect(boundingBox);
var width = (int)Math.Round(ViewportScale * rect.Width);
var height = (int)Math.Round(ViewportScale * rect.Height);
return string.Format(CultureInfo.InvariantCulture,
"CRS={0},1,{1},{2}&BBOX={3},{4},{5},{6}&WIDTH={7}&HEIGHT={8}",
CrsId, ProjectionCenter.Longitude, ProjectionCenter.Latitude,
rect.X, rect.Y, (rect.X + rect.Width), (rect.Y + rect.Height), width, height);
}
/// <summary> /// <summary>
/// Calculates azimuth and spherical distance in radians from location1 to location2. /// Calculates azimuth and spherical distance in radians from location1 to location2.
/// The returned distance has to be multiplied with an appropriate earth radius. /// The returned distance has to be multiplied with an appropriate earth radius.

View file

@ -30,8 +30,8 @@ namespace MapControl
public override Vector GetMapScale(Location location) public override Vector GetMapScale(Location location)
{ {
return new Vector( return new Vector(
ViewportScale / (MetersPerDegree * Math.Cos(location.Latitude * Math.PI / 180d)), ViewportScale / (Wgs84MetersPerDegree * Math.Cos(location.Latitude * Math.PI / 180d)),
ViewportScale / MetersPerDegree); ViewportScale / Wgs84MetersPerDegree);
} }
public override Point LocationToPoint(Location location) public override Point LocationToPoint(Location location)

View file

@ -51,6 +51,7 @@ namespace MapControl
var azimuth = Math.Atan2(point.X, point.Y); var azimuth = Math.Atan2(point.X, point.Y);
var mapDistance = Math.Sqrt(point.X * point.X + point.Y * point.Y); var mapDistance = Math.Sqrt(point.X * point.X + point.Y * point.Y);
var distance = Math.Atan(mapDistance / (TrueScale * 180d / Math.PI)); var distance = Math.Atan(mapDistance / (TrueScale * 180d / Math.PI));
return GetLocation(ProjectionCenter, azimuth, distance); return GetLocation(ProjectionCenter, azimuth, distance);

View file

@ -62,18 +62,25 @@ namespace MapControl
return string.Format(CultureInfo.InvariantCulture, "{0:F5},{1:F5}", latitude, longitude); return string.Format(CultureInfo.InvariantCulture, "{0:F5},{1:F5}", latitude, longitude);
} }
public static Location Parse(string s) public static Location Parse(string locationString)
{ {
var values = s.Split(new char[] { ',' }); Location location = null;
if (values.Length != 2) if (!string.IsNullOrEmpty(locationString))
{ {
throw new FormatException("Location string must be a comma-separated pair of double values."); var values = locationString.Split(new char[] { ',' });
if (values.Length != 2)
{
throw new FormatException("Location string must be a comma-separated pair of double values.");
}
location = new Location(
double.Parse(values[0], NumberStyles.Float, CultureInfo.InvariantCulture),
double.Parse(values[1], NumberStyles.Float, CultureInfo.InvariantCulture));
} }
return new Location( return location;
double.Parse(values[0], NumberStyles.Float, CultureInfo.InvariantCulture),
double.Parse(values[1], NumberStyles.Float, CultureInfo.InvariantCulture));
} }
/// <summary> /// <summary>

View file

@ -63,7 +63,6 @@ namespace MapControl
nameof(MapForeground), typeof(Brush), typeof(MapImageLayer), new PropertyMetadata(null)); nameof(MapForeground), typeof(Brush), typeof(MapImageLayer), new PropertyMetadata(null));
private readonly DispatcherTimer updateTimer; private readonly DispatcherTimer updateTimer;
private BoundingBox boundingBox;
private bool updateInProgress; private bool updateInProgress;
public MapImageLayer() public MapImageLayer()
@ -180,9 +179,14 @@ namespace MapControl
} }
/// <summary> /// <summary>
/// Returns an ImageSource for the specified bounding box. /// The current BoundingBox
/// </summary> /// </summary>
protected abstract Task<ImageSource> GetImageAsync(BoundingBox boundingBox); public BoundingBox BoundingBox { get; private set; }
/// <summary>
/// Returns an ImageSource for the current BoundingBox.
/// </summary>
protected abstract Task<ImageSource> GetImageAsync();
protected override void OnViewportChanged(ViewportChangedEventArgs e) protected override void OnViewportChanged(ViewportChangedEventArgs e)
{ {
@ -228,11 +232,11 @@ namespace MapControl
ImageSource imageSource = null; ImageSource imageSource = null;
if (boundingBox != null) if (BoundingBox != null)
{ {
try try
{ {
imageSource = await GetImageAsync(boundingBox); imageSource = await GetImageAsync();
} }
catch (Exception ex) catch (Exception ex)
{ {
@ -254,47 +258,47 @@ namespace MapControl
var y = (ParentMap.RenderSize.Height - height) / 2d; var y = (ParentMap.RenderSize.Height - height) / 2d;
var rect = new Rect(x, y, width, height); var rect = new Rect(x, y, width, height);
boundingBox = ParentMap.MapProjection.ViewportRectToBoundingBox(rect); BoundingBox = ParentMap.MapProjection.ViewportRectToBoundingBox(rect);
if (boundingBox != null) if (BoundingBox != null)
{ {
if (!double.IsNaN(MinLatitude) && boundingBox.South < MinLatitude) if (!double.IsNaN(MinLatitude) && BoundingBox.South < MinLatitude)
{ {
boundingBox.South = MinLatitude; BoundingBox.South = MinLatitude;
} }
if (!double.IsNaN(MinLongitude) && boundingBox.West < MinLongitude) if (!double.IsNaN(MinLongitude) && BoundingBox.West < MinLongitude)
{ {
boundingBox.West = MinLongitude; BoundingBox.West = MinLongitude;
} }
if (!double.IsNaN(MaxLatitude) && boundingBox.North > MaxLatitude) if (!double.IsNaN(MaxLatitude) && BoundingBox.North > MaxLatitude)
{ {
boundingBox.North = MaxLatitude; BoundingBox.North = MaxLatitude;
} }
if (!double.IsNaN(MaxLongitude) && boundingBox.East > MaxLongitude) if (!double.IsNaN(MaxLongitude) && BoundingBox.East > MaxLongitude)
{ {
boundingBox.East = MaxLongitude; BoundingBox.East = MaxLongitude;
} }
if (!double.IsNaN(MaxBoundingBoxWidth) && boundingBox.Width > MaxBoundingBoxWidth) if (!double.IsNaN(MaxBoundingBoxWidth) && BoundingBox.Width > MaxBoundingBoxWidth)
{ {
var d = (boundingBox.Width - MaxBoundingBoxWidth) / 2d; var d = (BoundingBox.Width - MaxBoundingBoxWidth) / 2d;
boundingBox.West += d; BoundingBox.West += d;
boundingBox.East -= d; BoundingBox.East -= d;
} }
} }
} }
private void AdjustBoundingBox(double longitudeOffset) private void AdjustBoundingBox(double longitudeOffset)
{ {
if (Math.Abs(longitudeOffset) > 180d && boundingBox != null) if (Math.Abs(longitudeOffset) > 180d && BoundingBox != null)
{ {
var offset = 360d * Math.Sign(longitudeOffset); var offset = 360d * Math.Sign(longitudeOffset);
boundingBox.West += offset; BoundingBox.West += offset;
boundingBox.East += offset; BoundingBox.East += offset;
foreach (var element in Children.OfType<FrameworkElement>()) foreach (var element in Children.OfType<FrameworkElement>())
{ {
@ -326,7 +330,7 @@ namespace MapControl
Children.Insert(1, topImage); Children.Insert(1, topImage);
topImage.Source = imageSource; topImage.Source = imageSource;
SetBoundingBox(topImage, boundingBox?.Clone()); SetBoundingBox(topImage, BoundingBox?.Clone());
topImage.BeginAnimation(OpacityProperty, new DoubleAnimation topImage.BeginAnimation(OpacityProperty, new DoubleAnimation
{ {

View file

@ -3,7 +3,6 @@
// Licensed under the Microsoft Public License (Ms-PL) // Licensed under the Microsoft Public License (Ms-PL)
using System; using System;
using System.Globalization;
#if WINDOWS_UWP #if WINDOWS_UWP
using Windows.Foundation; using Windows.Foundation;
using Windows.UI.Xaml.Media; using Windows.UI.Xaml.Media;
@ -26,7 +25,7 @@ namespace MapControl
public const double Wgs84Flattening = 1d / 298.257223563; public const double Wgs84Flattening = 1d / 298.257223563;
public static readonly double Wgs84Eccentricity = Math.Sqrt((2d - Wgs84Flattening) * Wgs84Flattening); public static readonly double Wgs84Eccentricity = Math.Sqrt((2d - Wgs84Flattening) * Wgs84Flattening);
public const double MetersPerDegree = Wgs84EquatorialRadius * Math.PI / 180d; public const double Wgs84MetersPerDegree = Wgs84EquatorialRadius * Math.PI / 180d;
/// <summary> /// <summary>
/// Gets or sets the WMS 1.3.0 CRS Identifier. /// Gets or sets the WMS 1.3.0 CRS Identifier.
@ -47,13 +46,18 @@ namespace MapControl
/// Gets the scale factor from geographic to cartesian coordinates, on the line of true scale of a /// Gets the scale factor from geographic to cartesian coordinates, on the line of true scale of a
/// cylindrical projection (usually the equator), or at the projection center of an azimuthal projection. /// cylindrical projection (usually the equator), or at the projection center of an azimuthal projection.
/// </summary> /// </summary>
public double TrueScale { get; protected set; } = MetersPerDegree; public double TrueScale { get; protected set; } = Wgs84MetersPerDegree;
/// <summary> /// <summary>
/// Gets the absolute value of the minimum and maximum latitude that can be transformed. /// Gets the absolute value of the minimum and maximum latitude that can be transformed.
/// </summary> /// </summary>
public double MaxLatitude { get; protected set; } = 90d; public double MaxLatitude { get; protected set; } = 90d;
/// <summary>
/// Gets the projection center. Only relevant for azimuthal pprojections.
/// </summary>
public Location ProjectionCenter { get; private set; } = new Location();
/// <summary> /// <summary>
/// Gets the transform matrix from cartesian map coordinates to viewport coordinates (pixels). /// Gets the transform matrix from cartesian map coordinates to viewport coordinates (pixels).
/// </summary> /// </summary>
@ -136,10 +140,11 @@ namespace MapControl
} }
/// <summary> /// <summary>
/// Sets ViewportScale and ViewportTransform values. /// Sets ProjectionCenter, ViewportScale, ViewportTransform and InverseViewportTransform.
/// </summary> /// </summary>
public virtual void SetViewportTransform(Location projectionCenter, Location mapCenter, Point viewportCenter, double zoomLevel, double heading) public void SetViewportTransform(Location projectionCenter, Location mapCenter, Point viewportCenter, double zoomLevel, double heading)
{ {
ProjectionCenter = projectionCenter;
ViewportScale = Math.Pow(2d, zoomLevel) * PixelPerDegree / TrueScale; ViewportScale = Math.Pow(2d, zoomLevel) * PixelPerDegree / TrueScale;
var center = LocationToPoint(mapCenter); var center = LocationToPoint(mapCenter);
@ -150,27 +155,6 @@ namespace MapControl
InverseViewportTransform = matrix; InverseViewportTransform = matrix;
} }
/// <summary>
/// Gets a WMS query parameter string from the specified bounding box, e.g. "CRS=...&BBOX=...&WIDTH=...&HEIGHT=..."
/// </summary>
public virtual string WmsQueryParameters(BoundingBox boundingBox)
{
if (string.IsNullOrEmpty(CrsId))
{
return null;
}
var format = CrsId == "EPSG:4326"
? "CRS={0}&BBOX={2},{1},{4},{3}&WIDTH={5}&HEIGHT={6}"
: "CRS={0}&BBOX={1},{2},{3},{4}&WIDTH={5}&HEIGHT={6}";
var rect = BoundingBoxToRect(boundingBox);
var width = (int)Math.Round(ViewportScale * rect.Width);
var height = (int)Math.Round(ViewportScale * rect.Height);
return string.Format(CultureInfo.InvariantCulture, format, CrsId,
rect.X, rect.Y, (rect.X + rect.Width), (rect.Y + rect.Height), width, height);
}
internal static Matrix CreateTransformMatrix( internal static Matrix CreateTransformMatrix(
Point translation1, double scale, double rotation, Point translation2) Point translation1, double scale, double rotation, Point translation2)
{ {

View file

@ -35,7 +35,7 @@ namespace MapControl
GetAzimuthDistance(ProjectionCenter, location, out azimuth, out distance); GetAzimuthDistance(ProjectionCenter, location, out azimuth, out distance);
var mapDistance = Math.Tan(distance / 2d) * TrueScale * 360d / Math.PI; var mapDistance = Math.Tan(distance / 2d) * 2d * TrueScale * 180d / Math.PI;
return new Point(mapDistance * Math.Sin(azimuth), mapDistance * Math.Cos(azimuth)); return new Point(mapDistance * Math.Sin(azimuth), mapDistance * Math.Cos(azimuth));
} }
@ -49,7 +49,8 @@ namespace MapControl
var azimuth = Math.Atan2(point.X, point.Y); var azimuth = Math.Atan2(point.X, point.Y);
var mapDistance = Math.Sqrt(point.X * point.X + point.Y * point.Y); var mapDistance = Math.Sqrt(point.X * point.X + point.Y * point.Y);
var distance = 2d * Math.Atan(mapDistance / (TrueScale * 360d / Math.PI));
var distance = 2d * Math.Atan(mapDistance / (2d * TrueScale * 180d / Math.PI));
return GetLocation(ProjectionCenter, azimuth, distance); return GetLocation(ProjectionCenter, azimuth, distance);
} }

View file

@ -161,10 +161,10 @@ namespace MapControl
private string GetBoundingBoxUri(int x, int y, int zoomLevel) private string GetBoundingBoxUri(int x, int y, int zoomLevel)
{ {
var tileSize = 360d / (1 << zoomLevel); // tile width in degrees var tileSize = 360d / (1 << zoomLevel); // tile width in degrees
var west = MapProjection.MetersPerDegree * (x * tileSize - 180d); var west = MapProjection.Wgs84MetersPerDegree * (x * tileSize - 180d);
var east = MapProjection.MetersPerDegree * ((x + 1) * tileSize - 180d); var east = MapProjection.Wgs84MetersPerDegree * ((x + 1) * tileSize - 180d);
var south = MapProjection.MetersPerDegree * (180d - (y + 1) * tileSize); var south = MapProjection.Wgs84MetersPerDegree * (180d - (y + 1) * tileSize);
var north = MapProjection.MetersPerDegree * (180d - y * tileSize); var north = MapProjection.Wgs84MetersPerDegree * (180d - y * tileSize);
return uriFormat return uriFormat
.Replace("{W}", west.ToString(CultureInfo.InvariantCulture)) .Replace("{W}", west.ToString(CultureInfo.InvariantCulture))

View file

@ -7,6 +7,7 @@ using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Globalization;
#if WINDOWS_UWP #if WINDOWS_UWP
using Windows.Data.Xml.Dom; using Windows.Data.Xml.Dom;
using Windows.UI.Xaml; using Windows.UI.Xaml;
@ -37,6 +38,10 @@ namespace MapControl
nameof(Format), typeof(string), typeof(WmsImageLayer), nameof(Format), typeof(string), typeof(WmsImageLayer),
new PropertyMetadata("image/png", async (o, e) => await ((WmsImageLayer)o).UpdateImageAsync())); new PropertyMetadata("image/png", async (o, e) => await ((WmsImageLayer)o).UpdateImageAsync()));
public static readonly DependencyProperty CrsIdMapProperty = DependencyProperty.Register(
nameof(CrsIdMap), typeof(string), typeof(WmsImageLayer),
new PropertyMetadata(null, async (o, e) => await ((WmsImageLayer)o).CrsIdMapPropertyChanged((string)e.NewValue)));
public Uri ServiceUri public Uri ServiceUri
{ {
get { return (Uri)GetValue(ServiceUriProperty); } get { return (Uri)GetValue(ServiceUriProperty); }
@ -61,6 +66,17 @@ namespace MapControl
set { SetValue(FormatProperty, value); } set { SetValue(FormatProperty, value); }
} }
public string CrsIdMap
{
get { return (string)GetValue(CrsIdMapProperty); }
set { SetValue(CrsIdMapProperty, value); }
}
private Dictionary<string, string> crsIdMap;
/// <summary>
/// Gets a list of all layer names returned by a GetCapabilities response.
/// </summary>
public async Task<IList<string>> GetLayerNamesAsync() public async Task<IList<string>> GetLayerNamesAsync()
{ {
IList<string> layerNames = null; IList<string> layerNames = null;
@ -100,14 +116,24 @@ namespace MapControl
return layerNames; return layerNames;
} }
protected override async Task<ImageSource> GetImageAsync(BoundingBox boundingBox) protected override async Task<ImageSource> GetImageAsync()
{ {
ImageSource imageSource = null; var imageUri = GetImageUri();
var projectionParameters = ParentMap.MapProjection.WmsQueryParameters(boundingBox);
if (ServiceUri != null && !string.IsNullOrEmpty(projectionParameters)) return imageUri != null ? await ImageLoader.LoadImageAsync(imageUri) : null;
}
/// <summary>
/// Returns a GetMap request URL for the current BoundingBox.
/// </summary>
protected virtual Uri GetImageUri()
{
Uri imageUri = null;
var projection = ParentMap?.MapProjection;
if (ServiceUri != null && projection != null && !string.IsNullOrEmpty(projection.CrsId))
{ {
var uri = GetRequestUri("GetMap&" + projectionParameters); var uri = GetRequestUri("GetMap");
if (uri.IndexOf("LAYERS=", StringComparison.OrdinalIgnoreCase) < 0 && Layers != null) if (uri.IndexOf("LAYERS=", StringComparison.OrdinalIgnoreCase) < 0 && Layers != null)
{ {
@ -124,10 +150,51 @@ namespace MapControl
uri += "&FORMAT=" + Format; uri += "&FORMAT=" + Format;
} }
imageSource = await ImageLoader.LoadImageAsync(new Uri(uri.Replace(" ", "%20"))); var rect = projection.BoundingBoxToRect(BoundingBox);
uri += "&" + GetBboxParameters(rect);
uri += "&WIDTH=" + (int)Math.Round(projection.ViewportScale * rect.Width);
uri += "&HEIGHT=" + (int)Math.Round(projection.ViewportScale * rect.Height);
imageUri = new Uri(uri.Replace(" ", "%20"));
} }
return imageSource; return imageUri;
}
/// <summary>
/// Gets a query substring for the projected bounding box, which contains the CRS and BBOX or equivalent parameters.
/// </summary>
protected virtual string GetBboxParameters(Rect bbox)
{
var crsId = GetCrsValue();
return string.Format(CultureInfo.InvariantCulture,
crsId == "EPSG:4326" ? "CRS={0}&BBOX={2},{1},{4},{3}" : "CRS={0}&BBOX={1},{2},{3},{4}",
crsId, bbox.X, bbox.Y, (bbox.X + bbox.Width), (bbox.Y + bbox.Height));
}
/// <summary>
/// Gets the effective value of the CRS query parameter.
/// </summary>
/// <returns></returns>
protected virtual string GetCrsValue()
{
var projection = ParentMap.MapProjection;
var crsId = projection.CrsId;
if (crsIdMap != null && !crsIdMap.TryGetValue(crsId, out crsId))
{
crsId = projection.CrsId;
}
if (crsId.StartsWith("AUTO2:") || crsId.StartsWith("AUTO:"))
{
crsId = string.Format(CultureInfo.InvariantCulture, "{0},1,{1},{2}",
crsId, projection.ProjectionCenter.Longitude, projection.ProjectionCenter.Latitude);
}
return crsId;
} }
private string GetRequestUri(string request) private string GetRequestUri(string request)
@ -152,9 +219,31 @@ namespace MapControl
return uri + "REQUEST=" + request; return uri + "REQUEST=" + request;
} }
private Task CrsIdMapPropertyChanged(string crsIdMapString)
{
crsIdMap = null;
if (!string.IsNullOrEmpty(crsIdMapString))
{
var entries = crsIdMapString.Split(new char[] { ' ', ',', ';' }, StringSplitOptions.RemoveEmptyEntries);
if (entries.Length >= 2)
{
crsIdMap = new Dictionary<string, string>();
for (int i = 0; i < entries.Length - 1; i += 2)
{
crsIdMap[entries[i]] = entries[i + 1];
}
}
}
return UpdateImageAsync();
}
private static IEnumerable<XmlElement> ChildElements(XmlElement element, string name) private static IEnumerable<XmlElement> ChildElements(XmlElement element, string name)
{ {
return element.ChildNodes.OfType<XmlElement>().Where(e => (string)e.LocalName == name); return element.ChildNodes.OfType<XmlElement>().Where(e => e.LocalName == name);
} }
} }
} }

View file

@ -175,7 +175,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.NETCore.UniversalWindowsPlatform"> <PackageReference Include="Microsoft.NETCore.UniversalWindowsPlatform">
<Version>6.2.2</Version> <Version>6.2.8</Version>
</PackageReference> </PackageReference>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View file

@ -55,7 +55,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.NETCore.UniversalWindowsPlatform"> <PackageReference Include="Microsoft.NETCore.UniversalWindowsPlatform">
<Version>6.2.2</Version> <Version>6.2.8</Version>
</PackageReference> </PackageReference>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View file

@ -57,7 +57,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.NETCore.UniversalWindowsPlatform"> <PackageReference Include="Microsoft.NETCore.UniversalWindowsPlatform">
<Version>6.2.2</Version> <Version>6.2.8</Version>
</PackageReference> </PackageReference>
<PackageReference Include="ProjNET4GeoAPI"> <PackageReference Include="ProjNET4GeoAPI">
<Version>1.4.1</Version> <Version>1.4.1</Version>

View file

@ -152,7 +152,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.NETCore.UniversalWindowsPlatform"> <PackageReference Include="Microsoft.NETCore.UniversalWindowsPlatform">
<Version>6.2.2</Version> <Version>6.2.8</Version>
</PackageReference> </PackageReference>
</ItemGroup> </ItemGroup>
<PropertyGroup Condition=" '$(VisualStudioVersion)' == '' or '$(VisualStudioVersion)' &lt; '14.0' "> <PropertyGroup Condition=" '$(VisualStudioVersion)' == '' or '$(VisualStudioVersion)' &lt; '14.0' ">