diff --git a/MapControl/Shared/AutoEquirectangularProjection.cs b/MapControl/Shared/AutoEquirectangularProjection.cs index 55613596..81518007 100644 --- a/MapControl/Shared/AutoEquirectangularProjection.cs +++ b/MapControl/Shared/AutoEquirectangularProjection.cs @@ -18,10 +18,10 @@ namespace MapControl { public const string DefaultCrsId = "AUTO2:42004"; - public AutoEquirectangularProjection() + public AutoEquirectangularProjection(string crsId = DefaultCrsId) { Type = MapProjectionType.NormalCylindrical; - CrsId = DefaultCrsId; + CrsId = crsId; } public override Point? LocationToMap(Location location) diff --git a/MapControl/Shared/AzimuthalEquidistantProjection.cs b/MapControl/Shared/AzimuthalEquidistantProjection.cs index 96cba54c..9c98767a 100644 --- a/MapControl/Shared/AzimuthalEquidistantProjection.cs +++ b/MapControl/Shared/AzimuthalEquidistantProjection.cs @@ -15,7 +15,9 @@ namespace MapControl /// public class AzimuthalEquidistantProjection : AzimuthalProjection { - public AzimuthalEquidistantProjection(string crsId) + public const string DefaultCrsId = "AUTO2:97003"; // proprietary CRS ID + + public AzimuthalEquidistantProjection(string crsId = DefaultCrsId) { CrsId = crsId; } diff --git a/MapControl/Shared/EquirectangularProjection.cs b/MapControl/Shared/EquirectangularProjection.cs index f2a4e415..ad0725ac 100644 --- a/MapControl/Shared/EquirectangularProjection.cs +++ b/MapControl/Shared/EquirectangularProjection.cs @@ -17,13 +17,12 @@ namespace MapControl /// public class EquirectangularProjection : MapProjection { - public const int DefaultEpsgCode = 4326; - public static readonly string DefaultCrsId = $"EPSG:{DefaultEpsgCode}"; + public const int EpsgCode = 4326; - public EquirectangularProjection() + public EquirectangularProjection(string crsId = "EPSG:4326") { Type = MapProjectionType.NormalCylindrical; - CrsId = DefaultCrsId; + CrsId = crsId; } public override Point GetRelativeScale(Location location) diff --git a/MapControl/Shared/Etrs89UtmProjection.cs b/MapControl/Shared/Etrs89UtmProjection.cs index b61836d2..fc758036 100644 --- a/MapControl/Shared/Etrs89UtmProjection.cs +++ b/MapControl/Shared/Etrs89UtmProjection.cs @@ -26,7 +26,7 @@ namespace MapControl } Zone = zone; - CrsId = $"EPSG:{Zone - FirstZone + FirstZoneEpsgCode}"; + CrsId = $"EPSG:{25800 + Zone}"; // GRS 1980 EquatorialRadius = 6378137d; diff --git a/MapControl/Shared/GnomonicProjection.cs b/MapControl/Shared/GnomonicProjection.cs index 7f9c5cb5..46952ed6 100644 --- a/MapControl/Shared/GnomonicProjection.cs +++ b/MapControl/Shared/GnomonicProjection.cs @@ -17,9 +17,9 @@ namespace MapControl { public const string DefaultCrsId = "AUTO2:97001"; // GeoServer non-standard CRS ID - public GnomonicProjection() + public GnomonicProjection(string crsId = DefaultCrsId) { - CrsId = DefaultCrsId; + CrsId = crsId; } public override Point? LocationToMap(Location location) diff --git a/MapControl/Shared/MapProjection.cs b/MapControl/Shared/MapProjection.cs index 86679dbc..57efd971 100644 --- a/MapControl/Shared/MapProjection.cs +++ b/MapControl/Shared/MapProjection.cs @@ -42,7 +42,7 @@ namespace MapControl /// /// Gets or sets an optional projection center. /// - public virtual Location Center { get; set; } = new Location(); + public virtual Location Center { get; protected internal set; } = new Location(); /// /// Gets the relative map scale at the specified Location. @@ -118,7 +118,7 @@ namespace MapControl /// public virtual string GetCrsValue() { - return CrsId.StartsWith("AUTO:") || CrsId.StartsWith("AUTO2:") + return CrsId.StartsWith("AUTO2:") || CrsId.StartsWith("AUTO:") ? string.Format(CultureInfo.InvariantCulture, "{0},1,{1},{2}", CrsId, Center.Longitude, Center.Latitude) : CrsId; } diff --git a/MapControl/Shared/MapProjectionFactory.cs b/MapControl/Shared/MapProjectionFactory.cs index 417d40a3..cbc13062 100644 --- a/MapControl/Shared/MapProjectionFactory.cs +++ b/MapControl/Shared/MapProjectionFactory.cs @@ -16,93 +16,67 @@ namespace MapControl public virtual MapProjection GetProjection(int epsgCode) { - MapProjection projection = null; - switch (epsgCode) { - case WorldMercatorProjection.DefaultEpsgCode: - projection = new WorldMercatorProjection(); - break; + case WorldMercatorProjection.EpsgCode: + return new WorldMercatorProjection(); - case WebMercatorProjection.DefaultEpsgCode: - projection = new WebMercatorProjection(); - break; + case WebMercatorProjection.EpsgCode: + return new WebMercatorProjection(); - case EquirectangularProjection.DefaultEpsgCode: - projection = new EquirectangularProjection(); - break; + case EquirectangularProjection.EpsgCode: + return new EquirectangularProjection(); - case UpsNorthProjection.DefaultEpsgCode: - projection = new UpsNorthProjection(); - break; + case UpsNorthProjection.EpsgCode: + return new UpsNorthProjection(); - case UpsSouthProjection.DefaultEpsgCode: - projection = new UpsSouthProjection(); - break; + case UpsSouthProjection.EpsgCode: + return new UpsSouthProjection(); case var c when c >= Etrs89UtmProjection.FirstZoneEpsgCode && c <= Etrs89UtmProjection.LastZoneEpsgCode: - projection = new Etrs89UtmProjection(epsgCode % 100); - break; + return new Etrs89UtmProjection(epsgCode % 100); case var c when c >= Nad83UtmProjection.FirstZoneEpsgCode && c <= Nad83UtmProjection.LastZoneEpsgCode: - projection = new Nad83UtmProjection(epsgCode % 100); - break; + return new Nad83UtmProjection(epsgCode % 100); case var c when c >= Wgs84UtmProjection.FirstZoneNorthEpsgCode && c <= Wgs84UtmProjection.LastZoneNorthEpsgCode: - projection = new Wgs84UtmProjection(epsgCode % 100, true); - break; + return new Wgs84UtmProjection(epsgCode % 100, true); case var c when c >= Wgs84UtmProjection.FirstZoneSouthEpsgCode && c <= Wgs84UtmProjection.LastZoneSouthEpsgCode: - projection = new Wgs84UtmProjection(epsgCode % 100, false); - break; + return new Wgs84UtmProjection(epsgCode % 100, false); default: - break; + return null; } - - return projection; } public virtual MapProjection GetProjection(string crsId) { - if (crsId.StartsWith("EPSG:") && int.TryParse(crsId.Substring(5), out int epsgCode)) - { - return GetProjection(epsgCode); - } - - MapProjection projection = null; - switch (crsId) { case Wgs84AutoUtmProjection.DefaultCrsId: - projection = new Wgs84AutoUtmProjection(); - break; + return new Wgs84AutoUtmProjection(); case OrthographicProjection.DefaultCrsId: - projection = new OrthographicProjection(); - break; + return new OrthographicProjection(); case AutoEquirectangularProjection.DefaultCrsId: - projection = new AutoEquirectangularProjection(); - break; + return new AutoEquirectangularProjection(); case GnomonicProjection.DefaultCrsId: - projection = new GnomonicProjection(); - break; + return new GnomonicProjection(); case StereographicProjection.DefaultCrsId: - projection = new StereographicProjection(); - break; + return new StereographicProjection(); - case "AUTO2:97003": // proprietary CRS ID - projection = new AzimuthalEquidistantProjection(crsId); - break; + case AzimuthalEquidistantProjection.DefaultCrsId: + return new AzimuthalEquidistantProjection(); default: - break; + return crsId.StartsWith("EPSG:") && int.TryParse(crsId.Substring(5), out int epsgCode) + ? GetProjection(epsgCode) + : null; } - - return projection; } } } diff --git a/MapControl/Shared/Nad83UtmProjection.cs b/MapControl/Shared/Nad83UtmProjection.cs index b85f434d..7a502863 100644 --- a/MapControl/Shared/Nad83UtmProjection.cs +++ b/MapControl/Shared/Nad83UtmProjection.cs @@ -26,7 +26,7 @@ namespace MapControl } Zone = zone; - CrsId = $"EPSG:{Zone - FirstZone + FirstZoneEpsgCode}"; + CrsId = $"EPSG:{26900 + Zone}"; // GRS 1980 EquatorialRadius = 6378137d; diff --git a/MapControl/Shared/OrthographicProjection.cs b/MapControl/Shared/OrthographicProjection.cs index 1b58dc2b..1caffe23 100644 --- a/MapControl/Shared/OrthographicProjection.cs +++ b/MapControl/Shared/OrthographicProjection.cs @@ -17,9 +17,9 @@ namespace MapControl { public const string DefaultCrsId = "AUTO2:42003"; - public OrthographicProjection() + public OrthographicProjection(string crsId = DefaultCrsId) { - CrsId = DefaultCrsId; + CrsId = crsId; } public override Point? LocationToMap(Location location) diff --git a/MapControl/Shared/PolarStereographicProjection.cs b/MapControl/Shared/PolarStereographicProjection.cs index 6b205ecf..93c56a65 100644 --- a/MapControl/Shared/PolarStereographicProjection.cs +++ b/MapControl/Shared/PolarStereographicProjection.cs @@ -117,12 +117,11 @@ namespace MapControl /// public class UpsNorthProjection : PolarStereographicProjection { - public const int DefaultEpsgCode = 32661; - public static readonly string DefaultCrsId = $"EPSG:{DefaultEpsgCode}"; + public const int EpsgCode = 32661; - public UpsNorthProjection() + public UpsNorthProjection(string crsId = "EPSG:32661") { - CrsId = DefaultCrsId; + CrsId = crsId; IsNorth = true; } } @@ -132,12 +131,11 @@ namespace MapControl /// public class UpsSouthProjection : PolarStereographicProjection { - public const int DefaultEpsgCode = 32761; - public static readonly string DefaultCrsId = $"EPSG:{DefaultEpsgCode}"; + public const int EpsgCode = 32761; - public UpsSouthProjection() + public UpsSouthProjection(string crsId = "EPSG:32761") { - CrsId = DefaultCrsId; + CrsId = crsId; IsNorth = false; } } diff --git a/MapControl/Shared/StereographicProjection.cs b/MapControl/Shared/StereographicProjection.cs index be92f845..f7a216df 100644 --- a/MapControl/Shared/StereographicProjection.cs +++ b/MapControl/Shared/StereographicProjection.cs @@ -17,9 +17,9 @@ namespace MapControl { public const string DefaultCrsId = "AUTO2:97002"; // GeoServer non-standard CRS ID - public StereographicProjection() + public StereographicProjection(string crsId = DefaultCrsId) { - CrsId = DefaultCrsId; + CrsId = crsId; } public override Point? LocationToMap(Location location) diff --git a/MapControl/Shared/WebMercatorProjection.cs b/MapControl/Shared/WebMercatorProjection.cs index 5fa114ce..290e2abd 100644 --- a/MapControl/Shared/WebMercatorProjection.cs +++ b/MapControl/Shared/WebMercatorProjection.cs @@ -15,13 +15,12 @@ namespace MapControl /// public class WebMercatorProjection : MapProjection { - public const int DefaultEpsgCode = 3857; - public static readonly string DefaultCrsId = $"EPSG:{DefaultEpsgCode}"; + public const int EpsgCode = 3857; - public WebMercatorProjection() + public WebMercatorProjection(string crsId = "EPSG:3857") { Type = MapProjectionType.WebMercator; - CrsId = DefaultCrsId; + CrsId = crsId; } public override Point GetRelativeScale(Location location) diff --git a/MapControl/Shared/Wgs84UtmProjection.cs b/MapControl/Shared/Wgs84UtmProjection.cs index cae78d0e..f7d7a875 100644 --- a/MapControl/Shared/Wgs84UtmProjection.cs +++ b/MapControl/Shared/Wgs84UtmProjection.cs @@ -21,27 +21,21 @@ namespace MapControl public int Zone { get; private set; } public bool IsNorth { get; private set; } - protected Wgs84UtmProjection() - { - } - public Wgs84UtmProjection(int zone, bool north) { SetZone(zone, north); } - protected void SetZone(int zone, bool north, string crsId = null) + protected void SetZone(int zone, bool north) { if (zone < FirstZone || zone > LastZone) { throw new ArgumentException($"Invalid WGS84 UTM zone {zone}.", nameof(zone)); } - var epsgCode = zone - FirstZone + (north ? FirstZoneNorthEpsgCode : FirstZoneSouthEpsgCode); - Zone = zone; IsNorth = north; - CrsId = crsId ?? $"EPSG:{epsgCode}"; + CrsId = $"EPSG:{(north ? 32600 : 32700) + zone}"; EquatorialRadius = Wgs84EquatorialRadius; Flattening = Wgs84Flattening; ScaleFactor = DefaultScaleFactor; @@ -58,38 +52,43 @@ namespace MapControl { public const string DefaultCrsId = "AUTO2:42001"; - public Wgs84AutoUtmProjection(bool useZoneCrsId = false) - { - UseZoneCrsId = useZoneCrsId; - UpdateZone(); - } + private readonly string autoCrsId; - public bool UseZoneCrsId { get; } + public Wgs84AutoUtmProjection(string crsId = DefaultCrsId) + : base(31, true) + { + autoCrsId = crsId; + + if (!string.IsNullOrEmpty(autoCrsId)) + { + CrsId = autoCrsId; + } + } public override Location Center { get => base.Center; - set + protected internal set { if (!Equals(base.Center, value)) { base.Center = value; - UpdateZone(); + + var lon = Location.NormalizeLongitude(value.Longitude); + var zone = (int)Math.Floor(lon / 6d) + 31; + var north = value.Latitude >= 0d; + + if (Zone != zone || IsNorth != north) + { + SetZone(zone, north); + + if (!string.IsNullOrEmpty(autoCrsId)) + { + CrsId = autoCrsId; + } + } } } } - - private void UpdateZone() - { - var lon = Location.NormalizeLongitude(Center.Longitude); - var zone = (int)Math.Floor(lon / 6d) + 31; - var north = Center.Latitude >= 0d; - - if (Zone != zone || IsNorth != north || string.IsNullOrEmpty(CrsId)) - { - SetZone(zone, north, UseZoneCrsId ? null : DefaultCrsId); - } - } - } } diff --git a/MapControl/Shared/WorldMercatorProjection.cs b/MapControl/Shared/WorldMercatorProjection.cs index 133ffb9e..26d9b297 100644 --- a/MapControl/Shared/WorldMercatorProjection.cs +++ b/MapControl/Shared/WorldMercatorProjection.cs @@ -15,13 +15,12 @@ namespace MapControl /// public class WorldMercatorProjection : MapProjection { - public const int DefaultEpsgCode = 3395; - public static readonly string DefaultCrsId = $"EPSG:{DefaultEpsgCode}"; + public const int EpsgCode = 3395; - public WorldMercatorProjection() + public WorldMercatorProjection(string crsId = "EPSG:3395") { Type = MapProjectionType.NormalCylindrical; - CrsId = DefaultCrsId; + CrsId = crsId; } public override Point GetRelativeScale(Location location) diff --git a/MapProjections/Shared/GeoApiProjectionFactory.cs b/MapProjections/Shared/GeoApiProjectionFactory.cs index 8fe075a7..23531404 100644 --- a/MapProjections/Shared/GeoApiProjectionFactory.cs +++ b/MapProjections/Shared/GeoApiProjectionFactory.cs @@ -8,75 +8,64 @@ namespace MapControl.Projections { public class GeoApiProjectionFactory : MapProjectionFactory { + public static GeoApiProjectionFactory GetInstance() + { + if (!(Instance is GeoApiProjectionFactory factory)) + { + factory = new GeoApiProjectionFactory(); + Instance = factory; + } + + return factory; + } + public Dictionary CoordinateSystemWkts { get; } = new Dictionary(); public override MapProjection GetProjection(int epsgCode) { - MapProjection projection = null; - - if (CoordinateSystemWkts.TryGetValue(epsgCode, out string wkt)) + switch (epsgCode) { - projection = new GeoApiProjection(wkt); + case WorldMercatorProjection.EpsgCode: + return new WorldMercatorProjection(); + + case WebMercatorProjection.EpsgCode: + return new WebMercatorProjection(); + + case int c when c >= Ed50UtmProjection.FirstZoneEpsgCode && c <= Ed50UtmProjection.LastZoneEpsgCode: + return new Ed50UtmProjection(epsgCode % 100); + + case var c when c >= Etrs89UtmProjection.FirstZoneEpsgCode && c <= Etrs89UtmProjection.LastZoneEpsgCode: + return new Etrs89UtmProjection(epsgCode % 100); + + case var c when c >= Nad27UtmProjection.FirstZoneEpsgCode && c <= Nad27UtmProjection.LastZoneEpsgCode: + return new Nad27UtmProjection(epsgCode % 100); + + case var c when c >= Nad83UtmProjection.FirstZoneEpsgCode && c <= Nad83UtmProjection.LastZoneEpsgCode: + return new Nad83UtmProjection(epsgCode % 100); + + case var c when c >= Wgs84UtmProjection.FirstZoneNorthEpsgCode && c <= Wgs84UtmProjection.LastZoneNorthEpsgCode: + return new Wgs84UtmProjection(epsgCode % 100, true); + + case var c when c >= Wgs84UtmProjection.FirstZoneSouthEpsgCode && c <= Wgs84UtmProjection.LastZoneSouthEpsgCode: + return new Wgs84UtmProjection(epsgCode % 100, false); + + default: + return CoordinateSystemWkts.TryGetValue(epsgCode, out string wkt) + ? new GeoApiProjection(wkt) + : base.GetProjection(epsgCode); } - else - { - switch (epsgCode) - { - case WorldMercatorProjection.DefaultEpsgCode: - projection = new WorldMercatorProjection(); - break; - - case WebMercatorProjection.DefaultEpsgCode: - projection = new WebMercatorProjection(); - break; - - case int c when c >= Ed50UtmProjection.FirstZoneEpsgCode && c <= Ed50UtmProjection.LastZoneEpsgCode: - projection = new Ed50UtmProjection(epsgCode % 100); - break; - - case var c when c >= Etrs89UtmProjection.FirstZoneEpsgCode && c <= Etrs89UtmProjection.LastZoneEpsgCode: - projection = new Etrs89UtmProjection(epsgCode % 100); - break; - - case var c when c >= Nad27UtmProjection.FirstZoneEpsgCode && c <= Nad27UtmProjection.LastZoneEpsgCode: - projection = new Nad27UtmProjection(epsgCode % 100); - break; - - case var c when c >= Nad83UtmProjection.FirstZoneEpsgCode && c <= Nad83UtmProjection.LastZoneEpsgCode: - projection = new Nad83UtmProjection(epsgCode % 100); - break; - - case var c when c >= Wgs84UtmProjection.FirstZoneNorthEpsgCode && c <= Wgs84UtmProjection.LastZoneNorthEpsgCode: - projection = new Wgs84UtmProjection(epsgCode % 100, true); - break; - - case var c when c >= Wgs84UtmProjection.FirstZoneSouthEpsgCode && c <= Wgs84UtmProjection.LastZoneSouthEpsgCode: - projection = new Wgs84UtmProjection(epsgCode % 100, false); - break; - - default: - break; - } - } - - return projection ?? base.GetProjection(epsgCode); } public override MapProjection GetProjection(string crsId) { - MapProjection projection = null; - switch (crsId) { case Wgs84AutoUtmProjection.DefaultCrsId: - projection = new Wgs84AutoUtmProjection(); - break; + return new Wgs84AutoUtmProjection(); default: - break; + return base.GetProjection(crsId); } - - return projection ?? base.GetProjection(crsId); } } } diff --git a/MapProjections/Shared/WebMercatorProjection.cs b/MapProjections/Shared/WebMercatorProjection.cs index e85bdba1..ccd4575d 100644 --- a/MapProjections/Shared/WebMercatorProjection.cs +++ b/MapProjections/Shared/WebMercatorProjection.cs @@ -18,7 +18,7 @@ namespace MapControl.Projections /// public class WebMercatorProjection : GeoApiProjection { - public const int DefaultEpsgCode = 3857; + public const int EpsgCode = 3857; public WebMercatorProjection() { diff --git a/MapProjections/Shared/Wgs84UtmProjection.cs b/MapProjections/Shared/Wgs84UtmProjection.cs index 61d2d0ef..df7fd64b 100644 --- a/MapProjections/Shared/Wgs84UtmProjection.cs +++ b/MapProjections/Shared/Wgs84UtmProjection.cs @@ -22,10 +22,6 @@ namespace MapControl.Projections public int Zone { get; private set; } public bool IsNorth { get; private set; } - protected Wgs84UtmProjection() - { - } - public Wgs84UtmProjection(int zone, bool north) { SetZone(zone, north); @@ -51,40 +47,41 @@ namespace MapControl.Projections { public const string DefaultCrsId = "AUTO2:42001"; - public Wgs84AutoUtmProjection(bool useZoneCrsId = false) - { - UseZoneCrsId = useZoneCrsId; - UpdateZone(); - } + private readonly string autoCrsId; - public bool UseZoneCrsId { get; } + public Wgs84AutoUtmProjection(string crsId = DefaultCrsId) + : base(31, true) + { + autoCrsId = crsId; + + if (!string.IsNullOrEmpty(autoCrsId)) + { + CrsId = autoCrsId; + } + } public override Location Center { get => base.Center; - set + protected set { if (!Equals(base.Center, value)) { base.Center = value; - UpdateZone(); - } - } - } - private void UpdateZone() - { - var lon = Location.NormalizeLongitude(Center.Longitude); - var zone = (int)Math.Floor(lon / 6d) + 31; - var north = Center.Latitude >= 0d; + var lon = Location.NormalizeLongitude(value.Longitude); + var zone = (int)Math.Floor(lon / 6d) + 31; + var north = value.Latitude >= 0d; - if (Zone != zone || IsNorth != north || string.IsNullOrEmpty(CrsId)) - { - SetZone(zone, north); + if (Zone != zone || IsNorth != north) + { + SetZone(zone, north); - if (!UseZoneCrsId) - { - CrsId = DefaultCrsId; + if (!string.IsNullOrEmpty(autoCrsId)) + { + CrsId = autoCrsId; + } + } } } } diff --git a/MapProjections/Shared/WorldMercatorProjection.cs b/MapProjections/Shared/WorldMercatorProjection.cs index b1b57240..74b0827e 100644 --- a/MapProjections/Shared/WorldMercatorProjection.cs +++ b/MapProjections/Shared/WorldMercatorProjection.cs @@ -17,7 +17,7 @@ namespace MapControl.Projections /// public class WorldMercatorProjection : GeoApiProjection { - public const int DefaultEpsgCode = 3395; + public const int EpsgCode = 3395; public WorldMercatorProjection() { @@ -43,7 +43,7 @@ namespace MapControl.Projections + "AUTHORITY[\"EPSG\",\"9001\"]]," + "AXIS[\"Easting\",EAST]," + "AXIS[\"Northing\",NORTH]," - + "AUTHORITY[\"EPSG\",\"3395\"]]"; + + $"AUTHORITY[\"EPSG\",\"{EpsgCode}\"]]"; } public override Point GetRelativeScale(Location location)