From 5b9e5529f6bb5dcfd2136759b259bdb1f3b56811 Mon Sep 17 00:00:00 2001 From: Clemens Date: Wed, 19 Jan 2022 23:40:05 +0100 Subject: [PATCH] Added GeoApiProjectionFactory --- MapProjections/Shared/GeoApiProjection.cs | 9 +++ .../Shared/GeoApiProjectionFactory.cs | 70 +++++++++++++++++++ .../Shared/PolarStereographicProjection.cs | 6 +- MapProjections/Shared/UtmProjection.cs | 18 ++++- MapProjections/UWP/MapProjections.UWP.csproj | 3 + MapProjections/WPF/MapProjections.WPF.csproj | 4 ++ 6 files changed, 106 insertions(+), 4 deletions(-) create mode 100644 MapProjections/Shared/GeoApiProjectionFactory.cs diff --git a/MapProjections/Shared/GeoApiProjection.cs b/MapProjections/Shared/GeoApiProjection.cs index 00b2ad2e..62f55048 100644 --- a/MapProjections/Shared/GeoApiProjection.cs +++ b/MapProjections/Shared/GeoApiProjection.cs @@ -106,6 +106,15 @@ namespace MapControl.Projections get { return isWebMercator; } } + + public GeoApiProjection(string wkt = null) + { + if (wkt != null) + { + WKT = wkt; + } + } + public override Point LocationToMap(Location location) { if (LocationToMapTransform == null) diff --git a/MapProjections/Shared/GeoApiProjectionFactory.cs b/MapProjections/Shared/GeoApiProjectionFactory.cs new file mode 100644 index 00000000..e2d771a5 --- /dev/null +++ b/MapProjections/Shared/GeoApiProjectionFactory.cs @@ -0,0 +1,70 @@ +// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control +// © 2022 Clemens Fischer +// Licensed under the Microsoft Public License (Ms-PL) + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Net.Http; + +namespace MapControl.Projections +{ + public class GeoApiProjectionFactory : MapProjectionFactory + { + private readonly Dictionary wkts = new Dictionary(); + private readonly HttpClient httpClient = new HttpClient(); + + public override MapProjection CreateProjection(string projectionDefinition) + { + var projection = base.CreateProjection(projectionDefinition); + + if (projection == null && + projectionDefinition.StartsWith("EPSG:") && + int.TryParse(projectionDefinition.Substring(5), out int epsgCode)) + { + if (epsgCode >= 32601 && epsgCode <= 32660) + { + projection = new UtmProjection(epsgCode - 32600, true); + } + else if (epsgCode == 32661) + { + projection = new UpsNorthProjection(); + } + else if (epsgCode >= 32701 && epsgCode <= 32760) + { + projection = new UtmProjection(epsgCode - 32700, false); + } + else if (epsgCode == 32761) + { + projection = new UpsSouthProjection(); + } + else + { + projection = new GeoApiProjection(GetWkt(epsgCode)); + } + } + + return projection; + } + + private string GetWkt(int epsgCode) + { + if (!wkts.TryGetValue(epsgCode, out string wkt)) + { + var url = string.Format("https://epsg.io/{0}.wkt", epsgCode); + + try + { + wkt = httpClient.GetStringAsync(url).Result; // potential deadlock? + wkts[epsgCode] = wkt; + } + catch (Exception ex) + { + Debug.WriteLine($"GeoApiProjectionFactory.GetWkt({epsgCode}): {url}: {ex.Message}"); + } + } + + return wkt; + } + } +} diff --git a/MapProjections/Shared/PolarStereographicProjection.cs b/MapProjections/Shared/PolarStereographicProjection.cs index 33f4c5d3..374c2019 100644 --- a/MapProjections/Shared/PolarStereographicProjection.cs +++ b/MapProjections/Shared/PolarStereographicProjection.cs @@ -114,14 +114,16 @@ namespace MapControl.Projections public class UpsNorthProjection : PolarStereographicProjection { - public UpsNorthProjection() : base("EPSG:32661", true, 0.994, 2e6, 2e6) + public UpsNorthProjection() + : base("EPSG:32661", true, 0.994, 2e6, 2e6) { } } public class UpsSouthProjection : PolarStereographicProjection { - public UpsSouthProjection() : base("EPSG:32761", false, 0.994, 2e6, 2e6) + public UpsSouthProjection() + : base("EPSG:32761", false, 0.994, 2e6, 2e6) { } } diff --git a/MapProjections/Shared/UtmProjection.cs b/MapProjections/Shared/UtmProjection.cs index fa5260cc..b584b95f 100644 --- a/MapProjections/Shared/UtmProjection.cs +++ b/MapProjections/Shared/UtmProjection.cs @@ -36,9 +36,23 @@ namespace MapControl.Projections } } + public UtmProjection() + { + } + + public UtmProjection(int zoneNumber, bool north) + { + SetZone(zoneNumber, north); + } + + public UtmProjection(Location location) + { + SetZone(location); + } + public void SetZone(int zoneNumber, bool north) { - if (zoneNumber < 1 || zoneNumber > 61) + if (zoneNumber < 1 || zoneNumber > 60) { throw new ArgumentException("Invalid UTM zone number.", nameof(zoneNumber)); } @@ -56,7 +70,7 @@ namespace MapControl.Projections { var zoneNumber = Math.Min((int)(Location.NormalizeLongitude(location.Longitude) + 180d) / 6 + 1, 60); - SetZone(zoneNumber, location.Latitude >= 0); + SetZone(zoneNumber, location.Latitude >= 0d); } } } diff --git a/MapProjections/UWP/MapProjections.UWP.csproj b/MapProjections/UWP/MapProjections.UWP.csproj index 274ca59b..7ab95557 100644 --- a/MapProjections/UWP/MapProjections.UWP.csproj +++ b/MapProjections/UWP/MapProjections.UWP.csproj @@ -43,6 +43,9 @@ GeoApiProjection.cs + + GeoApiProjectionFactory.cs + PolarStereographicProjection.cs diff --git a/MapProjections/WPF/MapProjections.WPF.csproj b/MapProjections/WPF/MapProjections.WPF.csproj index 821e61d1..074d4de3 100644 --- a/MapProjections/WPF/MapProjections.WPF.csproj +++ b/MapProjections/WPF/MapProjections.WPF.csproj @@ -24,6 +24,10 @@ + + + +