diff --git a/MapControl/Shared/Etrs89UtmProjection.cs b/MapControl/Shared/Etrs89UtmProjection.cs
new file mode 100644
index 00000000..718aaa82
--- /dev/null
+++ b/MapControl/Shared/Etrs89UtmProjection.cs
@@ -0,0 +1,40 @@
+// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
+// © 2022 Clemens Fischer
+// Licensed under the Microsoft Public License (Ms-PL)
+
+using System;
+
+namespace MapControl
+{
+ ///
+ /// ETRS89 UTM Projection with zone number.
+ ///
+ public class Etrs89UtmProjection : TransverseMercatorProjection
+ {
+ public const int FirstZone = 28;
+ public const int LastZone = 38;
+ public const int FirstZoneEpsgCode = 25800 + FirstZone;
+ public const int LastZoneEpsgCode = 25800 + LastZone;
+
+ public int Zone { get; }
+
+ public Etrs89UtmProjection(int zone)
+ {
+ if (zone < FirstZone || zone > LastZone)
+ {
+ throw new ArgumentException($"Invalid ETRS89 UTM zone {zone}.", nameof(zone));
+ }
+
+ Zone = zone;
+ CrsId = $"EPSG:{Zone - FirstZone + FirstZoneEpsgCode}";
+
+ // GRS 1980
+ EquatorialRadius = 6378137d;
+ Flattening = 1d / 298.257222101;
+ ScaleFactor = DefaultScaleFactor;
+ CentralMeridian = Zone * 6d - 183d;
+ FalseEasting = 5e5;
+ FalseNorthing = 0d;
+ }
+ }
+}
diff --git a/MapControl/Shared/MapBase.cs b/MapControl/Shared/MapBase.cs
index 5e53baaa..b41509d2 100644
--- a/MapControl/Shared/MapBase.cs
+++ b/MapControl/Shared/MapBase.cs
@@ -381,15 +381,19 @@ namespace MapControl
public void ZoomToBounds(BoundingBox boundingBox)
{
var mapRect = MapProjection.BoundingBoxToMapRect(boundingBox);
- var targetCenter = MapProjection.MapToLocation(mapRect.Center);
- if (targetCenter != null)
+ if (mapRect != null)
{
- var scale = Math.Min(RenderSize.Width / mapRect.Width, RenderSize.Height / mapRect.Height);
+ var targetCenter = MapProjection.MapToLocation(mapRect.Center);
- TargetZoomLevel = ViewTransform.ScaleToZoomLevel(scale);
- TargetCenter = targetCenter;
- TargetHeading = 0d;
+ if (targetCenter != null)
+ {
+ var scale = Math.Min(RenderSize.Width / mapRect.Width, RenderSize.Height / mapRect.Height);
+
+ TargetZoomLevel = ViewTransform.ScaleToZoomLevel(scale);
+ TargetCenter = targetCenter;
+ TargetHeading = 0d;
+ }
}
}
diff --git a/MapControl/Shared/MapProjection.cs b/MapControl/Shared/MapProjection.cs
index fb5330c8..95b77c73 100644
--- a/MapControl/Shared/MapProjection.cs
+++ b/MapControl/Shared/MapProjection.cs
@@ -134,15 +134,11 @@ namespace MapControl
//
const double p = 0.01;
- var bbox = string.Format(CultureInfo.InvariantCulture, "{0:F2},{1:F2},{2:F2},{3:F2}",
+ return string.Format(CultureInfo.InvariantCulture, "{0:F2},{1:F2},{2:F2},{3:F2}",
p * Math.Ceiling(mapRect.XMin / p),
p * Math.Ceiling(mapRect.YMin / p),
p * Math.Floor(mapRect.XMax / p),
p * Math.Floor(mapRect.YMax / p));
-
- System.Diagnostics.Debug.WriteLine(bbox);
-
- return bbox;
}
}
}
diff --git a/MapControl/Shared/MapProjectionFactory.cs b/MapControl/Shared/MapProjectionFactory.cs
index 536d2119..950a002d 100644
--- a/MapControl/Shared/MapProjectionFactory.cs
+++ b/MapControl/Shared/MapProjectionFactory.cs
@@ -40,6 +40,10 @@ namespace MapControl
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;
diff --git a/MapControl/Shared/Nad27UtmProjection.cs b/MapControl/Shared/Nad27UtmProjection.cs
new file mode 100644
index 00000000..ab0fe7bf
--- /dev/null
+++ b/MapControl/Shared/Nad27UtmProjection.cs
@@ -0,0 +1,40 @@
+// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
+// © 2022 Clemens Fischer
+// Licensed under the Microsoft Public License (Ms-PL)
+
+using System;
+
+namespace MapControl
+{
+ ///
+ /// NAD27 UTM Projection with zone number.
+ ///
+ public class Nad27UtmProjection : TransverseMercatorProjection
+ {
+ public const int FirstZone = 1;
+ public const int LastZone = 22;
+ public const int FirstZoneEpsgCode = 26700 + FirstZone;
+ public const int LastZoneEpsgCode = 26700 + LastZone;
+
+ public int Zone { get; }
+
+ public Nad27UtmProjection(int zone)
+ {
+ if (zone < FirstZone || zone > LastZone)
+ {
+ throw new ArgumentException($"Invalid NAD27 UTM zone {zone}.", nameof(zone));
+ }
+
+ Zone = zone;
+ CrsId = $"EPSG:{Zone - FirstZone + FirstZoneEpsgCode}";
+
+ // Clarke 1866
+ EquatorialRadius = 6378206.4;
+ Flattening = 1d / 294.978698213898;
+ ScaleFactor = DefaultScaleFactor;
+ CentralMeridian = Zone * 6d - 183d;
+ FalseEasting = 5e5;
+ FalseNorthing = 0d;
+ }
+ }
+}
diff --git a/MapControl/Shared/Nad83UtmProjection.cs b/MapControl/Shared/Nad83UtmProjection.cs
new file mode 100644
index 00000000..61aebd5d
--- /dev/null
+++ b/MapControl/Shared/Nad83UtmProjection.cs
@@ -0,0 +1,40 @@
+// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
+// © 2022 Clemens Fischer
+// Licensed under the Microsoft Public License (Ms-PL)
+
+using System;
+
+namespace MapControl
+{
+ ///
+ /// NAD83 UTM Projection with zone number.
+ ///
+ public class Nad83UtmProjection : TransverseMercatorProjection
+ {
+ public const int FirstZone = 1;
+ public const int LastZone = 23;
+ public const int FirstZoneEpsgCode = 26900 + FirstZone;
+ public const int LastZoneEpsgCode = 26900 + LastZone;
+
+ public int Zone { get; }
+
+ public Nad83UtmProjection(int zone)
+ {
+ if (zone < FirstZone || zone > LastZone)
+ {
+ throw new ArgumentException($"Invalid NAD83 UTM zone {zone}.", nameof(zone));
+ }
+
+ Zone = zone;
+ CrsId = $"EPSG:{Zone - FirstZone + FirstZoneEpsgCode}";
+
+ // GRS 1980
+ EquatorialRadius = 6378137d;
+ Flattening = 1d / 298.257222101;
+ ScaleFactor = DefaultScaleFactor;
+ CentralMeridian = Zone * 6d - 183d;
+ FalseEasting = 5e5;
+ FalseNorthing = 0d;
+ }
+ }
+}
diff --git a/MapControl/Shared/UtmProjection.cs b/MapControl/Shared/Wgs84UtmProjection.cs
similarity index 58%
rename from MapControl/Shared/UtmProjection.cs
rename to MapControl/Shared/Wgs84UtmProjection.cs
index b34ce91d..29469289 100644
--- a/MapControl/Shared/UtmProjection.cs
+++ b/MapControl/Shared/Wgs84UtmProjection.cs
@@ -6,70 +6,6 @@ using System;
namespace MapControl
{
- ///
- /// ETRS89 UTM Projection with zone number.
- ///
- public class Etrs89UtmProjection : TransverseMercatorProjection
- {
- public const int FirstZone = 28;
- public const int LastZone = 38;
- public const int FirstZoneEpsgCode = 25800 + FirstZone;
- public const int LastZoneEpsgCode = 25800 + LastZone;
-
- public int Zone { get; }
-
- public Etrs89UtmProjection(int zone)
- {
- if (zone < FirstZone || zone > LastZone)
- {
- throw new ArgumentException($"Invalid ETRS89 UTM zone {zone}.", nameof(zone));
- }
-
- Zone = zone;
- CrsId = $"EPSG:{Zone - FirstZone + FirstZoneEpsgCode}";
-
- // GRS 1980
- EquatorialRadius = 6378137d;
- Flattening = 1d / 298.257222101;
- ScaleFactor = DefaultScaleFactor;
- CentralMeridian = Zone * 6d - 183d;
- FalseEasting = 5e5;
- FalseNorthing = 0d;
- }
- }
-
- ///
- /// NAD27 UTM Projection with zone number.
- ///
- public class Nad27UtmProjection : TransverseMercatorProjection
- {
- public const int FirstZone = 1;
- public const int LastZone = 22;
- public const int FirstZoneEpsgCode = 26700 + FirstZone;
- public const int LastZoneEpsgCode = 26700 + LastZone;
-
- public int Zone { get; }
-
- public Nad27UtmProjection(int zone)
- {
- if (zone < FirstZone || zone > LastZone)
- {
- throw new ArgumentException($"Invalid NAD27 UTM zone {zone}.", nameof(zone));
- }
-
- Zone = zone;
- CrsId = $"EPSG:{Zone - FirstZone + FirstZoneEpsgCode}";
-
- // Clarke 1866
- EquatorialRadius = 6378206.4;
- Flattening = 1d / 294.978698213898;
- ScaleFactor = DefaultScaleFactor;
- CentralMeridian = Zone * 6d - 183d;
- FalseEasting = 5e5;
- FalseNorthing = 0d;
- }
- }
-
///
/// WGS84 UTM Projection with zone number and north/south flag.
///
@@ -107,7 +43,7 @@ namespace MapControl
IsNorth = north;
CrsId = crsId ?? $"EPSG:{epsgCode}";
EquatorialRadius = Wgs84EquatorialRadius;
- Flattening = 1d / Wgs84Flattening;
+ Flattening = Wgs84Flattening;
ScaleFactor = DefaultScaleFactor;
CentralMeridian = Zone * 6d - 183d;
FalseEasting = 5e5;
diff --git a/MapControl/Shared/WmsImageLayer.cs b/MapControl/Shared/WmsImageLayer.cs
index a9ac5c95..ee199463 100644
--- a/MapControl/Shared/WmsImageLayer.cs
+++ b/MapControl/Shared/WmsImageLayer.cs
@@ -240,6 +240,12 @@ namespace MapControl
protected virtual string GetMapRequestUri(BoundingBox boundingBox)
{
var mapRect = ParentMap.MapProjection.BoundingBoxToMapRect(boundingBox);
+
+ if (mapRect == null)
+ {
+ return null;
+ }
+
var viewScale = ParentMap.ViewTransform.Scale;
return GetRequestUri(new Dictionary
@@ -265,6 +271,12 @@ namespace MapControl
var viewSize = ParentMap.RenderSize;
var boundingBox = ParentMap.ViewRectToBoundingBox(new Rect(0d, 0d, viewSize.Width, viewSize.Height));
var mapRect = ParentMap.MapProjection.BoundingBoxToMapRect(boundingBox);
+
+ if (mapRect == null)
+ {
+ return null;
+ }
+
var viewRect = GetViewRect(mapRect);
var transform = new Matrix(1, 0, 0, 1, -viewSize.Width / 2, -viewSize.Height / 2);
diff --git a/MapControl/UWP/MapControl.UWP.csproj b/MapControl/UWP/MapControl.UWP.csproj
index 61629a28..4ae146a5 100644
--- a/MapControl/UWP/MapControl.UWP.csproj
+++ b/MapControl/UWP/MapControl.UWP.csproj
@@ -71,6 +71,9 @@
EquirectangularProjection.cs
+
+ Etrs89UtmProjection.cs
+
FilePath.cs
@@ -143,6 +146,12 @@
MapTileLayerBase.cs
+
+ Nad27UtmProjection.cs
+
+
+ Nad83UtmProjection.cs
+
OrthographicProjection.cs
@@ -176,9 +185,6 @@
TransverseMercatorProjection.cs
-
- UtmProjection.cs
-
ViewportChangedEventArgs.cs
@@ -191,6 +197,9 @@
WebMercatorProjection.cs
+
+ Wgs84UtmProjection.cs
+
WmsImageLayer.cs
diff --git a/MapControl/WPF/MapItemsImageLayer.WPF.cs b/MapControl/WPF/MapItemsImageLayer.WPF.cs
index f0393372..1773b8eb 100644
--- a/MapControl/WPF/MapItemsImageLayer.WPF.cs
+++ b/MapControl/WPF/MapItemsImageLayer.WPF.cs
@@ -37,17 +37,21 @@ namespace MapControl
if (projection != null && items != null)
{
- image = await Task.Run(() => GetImage(projection, boundingBox, items));
+ var mapRect = projection.BoundingBoxToMapRect(boundingBox);
+
+ if (mapRect != null)
+ {
+ image = await Task.Run(() => GetImage(projection, mapRect, items));
+ }
}
return image;
}
- private DrawingImage GetImage(MapProjection projection, BoundingBox boundingBox, IEnumerable items)
+ private DrawingImage GetImage(MapProjection projection, MapRect mapRect, IEnumerable items)
{
var scale = ParentMap.ViewTransform.Scale;
var rotation = ParentMap.ViewTransform.Rotation;
- var mapRect = projection.BoundingBoxToMapRect(boundingBox);
var drawings = new DrawingGroup();
foreach (var item in items)
diff --git a/MapProjections/Shared/Ed50UtmProjection.cs b/MapProjections/Shared/Ed50UtmProjection.cs
index 3550656b..fbea40ae 100644
--- a/MapProjections/Shared/Ed50UtmProjection.cs
+++ b/MapProjections/Shared/Ed50UtmProjection.cs
@@ -6,15 +6,26 @@ using System;
namespace MapControl.Projections
{
+ ///
+ /// ED50 UTM Projection with zone number.
+ ///
public class Ed50UtmProjection : GeoApiProjection
{
+ public const int FirstZone = 28;
+ public const int LastZone = 38;
+ public const int FirstZoneEpsgCode = 23000 + FirstZone;
+ public const int LastZoneEpsgCode = 23000 + LastZone;
+
+ public int Zone { get; }
+
public Ed50UtmProjection(int zone)
{
- if (zone < 28 || zone > 38)
+ if (zone < FirstZone || zone > LastZone)
{
- throw new ArgumentException($"Invalid UTM zone {zone}.", nameof(zone));
+ throw new ArgumentException($"Invalid ED50 UTM zone {zone}.", nameof(zone));
}
+ Zone = zone;
CoordinateSystemWkt
= $"PROJCS[\"ED50 / UTM zone {zone}N\","
+ "GEOGCS[\"ED50\","
@@ -23,10 +34,8 @@ namespace MapControl.Projections
+ "AUTHORITY[\"EPSG\",\"7022\"]],"
+ "TOWGS84[-87,-98,-121,0,0,0,0],"
+ "AUTHORITY[\"EPSG\",\"6230\"]],"
- + "PRIMEM[\"Greenwich\",0,"
- + "AUTHORITY[\"EPSG\",\"8901\"]],"
- + "UNIT[\"degree\",0.0174532925199433,"
- + "AUTHORITY[\"EPSG\",\"9122\"]],"
+ + "PRIMEM[\"Greenwich\",0,AUTHORITY[\"EPSG\",\"8901\"]],"
+ + "UNIT[\"degree\",0.0174532925199433,AUTHORITY[\"EPSG\",\"9122\"]],"
+ "AUTHORITY[\"EPSG\",\"4230\"]],"
+ "PROJECTION[\"Transverse_Mercator\"],"
+ "PARAMETER[\"latitude_of_origin\",0],"
@@ -34,8 +43,7 @@ namespace MapControl.Projections
+ "PARAMETER[\"scale_factor\",0.9996],"
+ "PARAMETER[\"false_easting\",500000],"
+ "PARAMETER[\"false_northing\",0],"
- + "UNIT[\"metre\",1,"
- + "AUTHORITY[\"EPSG\",\"9001\"]],"
+ + "UNIT[\"metre\",1,AUTHORITY[\"EPSG\",\"9001\"]],"
+ "AXIS[\"Easting\",EAST],"
+ "AXIS[\"Northing\",NORTH],"
+ $"AUTHORITY[\"EPSG\",\"230{zone}\"]]";
diff --git a/MapProjections/Shared/Etrs89UtmProjection.cs b/MapProjections/Shared/Etrs89UtmProjection.cs
index ce707efb..fc62aa1e 100644
--- a/MapProjections/Shared/Etrs89UtmProjection.cs
+++ b/MapProjections/Shared/Etrs89UtmProjection.cs
@@ -6,15 +6,26 @@ using System;
namespace MapControl.Projections
{
+ ///
+ /// ETRS89 UTM Projection with zone number.
+ ///
public class Etrs89UtmProjection : GeoApiProjection
{
+ public const int FirstZone = 28;
+ public const int LastZone = 38;
+ public const int FirstZoneEpsgCode = 25800 + FirstZone;
+ public const int LastZoneEpsgCode = 25800 + LastZone;
+
+ public int Zone { get; }
+
public Etrs89UtmProjection(int zone)
{
- if (zone < 28 || zone > 38)
+ if (zone < FirstZone || zone > LastZone)
{
- throw new ArgumentException($"Invalid UTM zone {zone}.", nameof(zone));
+ throw new ArgumentException($"Invalid ETRS89 UTM zone {zone}.", nameof(zone));
}
+ Zone = zone;
CoordinateSystemWkt
= $"PROJCS[\"ETRS89 / UTM zone {zone}N\","
+ "GEOGCS[\"ETRS89\","
@@ -23,10 +34,8 @@ namespace MapControl.Projections
+ "AUTHORITY[\"EPSG\",\"7019\"]],"
+ "TOWGS84[0,0,0,0,0,0,0],"
+ "AUTHORITY[\"EPSG\",\"6258\"]],"
- + "PRIMEM[\"Greenwich\",0,"
- + "AUTHORITY[\"EPSG\",\"8901\"]],"
- + "UNIT[\"degree\",0.0174532925199433,"
- + "AUTHORITY[\"EPSG\",\"9122\"]],"
+ + "PRIMEM[\"Greenwich\",0,AUTHORITY[\"EPSG\",\"8901\"]],"
+ + "UNIT[\"degree\",0.0174532925199433,AUTHORITY[\"EPSG\",\"9122\"]],"
+ "AUTHORITY[\"EPSG\",\"4258\"]],"
+ "PROJECTION[\"Transverse_Mercator\"],"
+ "PARAMETER[\"latitude_of_origin\",0],"
@@ -34,8 +43,7 @@ namespace MapControl.Projections
+ "PARAMETER[\"scale_factor\",0.9996],"
+ "PARAMETER[\"false_easting\",500000],"
+ "PARAMETER[\"false_northing\",0],"
- + "UNIT[\"metre\",1,"
- + "AUTHORITY[\"EPSG\",\"9001\"]],"
+ + "UNIT[\"metre\",1,AUTHORITY[\"EPSG\",\"9001\"]],"
+ "AXIS[\"Easting\",EAST],"
+ "AXIS[\"Northing\",NORTH],"
+ $"AUTHORITY[\"EPSG\",\"258{zone}\"]]";
diff --git a/MapProjections/Shared/GeoApiProjectionFactory.cs b/MapProjections/Shared/GeoApiProjectionFactory.cs
index b6e56647..c7da9b0a 100644
--- a/MapProjections/Shared/GeoApiProjectionFactory.cs
+++ b/MapProjections/Shared/GeoApiProjectionFactory.cs
@@ -8,17 +8,6 @@ namespace MapControl.Projections
{
public class GeoApiProjectionFactory : MapProjectionFactory
{
- private const int WorldMercator = 3395;
- private const int WebMercator = 3857;
- private const int Ed50UtmFirst = 23028;
- private const int Ed50UtmLast = 23038;
- private const int Etrs89UtmFirst = 25828;
- private const int Etrs89UtmLast = 25838;
- private const int Wgs84UtmNorthFirst = 32601;
- private const int Wgs84UtmNorthLast = 32660;
- private const int Wgs84UtmSouthFirst = 32701;
- private const int Wgs84UtmSouthLast = 32760;
-
public Dictionary CoordinateSystemWkts { get; } = new Dictionary();
public override MapProjection GetProjection(int epsgCode)
@@ -33,27 +22,35 @@ namespace MapControl.Projections
{
switch (epsgCode)
{
- case WorldMercator:
+ case WorldMercatorProjection.DefaultEpsgCode:
projection = new WorldMercatorProjection();
break;
- case WebMercator:
+ case WebMercatorProjection.DefaultEpsgCode:
projection = new WebMercatorProjection();
break;
- case int c when c >= Ed50UtmFirst && c <= Ed50UtmLast:
+ case int c when c >= Ed50UtmProjection.FirstZoneEpsgCode && c <= Ed50UtmProjection.LastZoneEpsgCode:
projection = new Ed50UtmProjection(epsgCode % 100);
break;
- case int c when c >= Etrs89UtmFirst && c <= Etrs89UtmLast:
+ case var c when c >= Etrs89UtmProjection.FirstZoneEpsgCode && c <= Etrs89UtmProjection.LastZoneEpsgCode:
projection = new Etrs89UtmProjection(epsgCode % 100);
break;
- case int c when c >= Wgs84UtmNorthFirst && c <= Wgs84UtmNorthLast:
+ 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 int c when c >= Wgs84UtmSouthFirst && c <= Wgs84UtmSouthLast:
+ case var c when c >= Wgs84UtmProjection.FirstZoneSouthEpsgCode && c <= Wgs84UtmProjection.LastZoneSouthEpsgCode:
projection = new Wgs84UtmProjection(epsgCode % 100, false);
break;
diff --git a/MapProjections/Shared/Nad27UtmProjection.cs b/MapProjections/Shared/Nad27UtmProjection.cs
new file mode 100644
index 00000000..b3aae06e
--- /dev/null
+++ b/MapProjections/Shared/Nad27UtmProjection.cs
@@ -0,0 +1,50 @@
+// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
+// © 2022 Clemens Fischer
+// Licensed under the Microsoft Public License (Ms-PL)
+
+using System;
+
+namespace MapControl.Projections
+{
+ ///
+ /// NAD27 UTM Projection with zone number.
+ ///
+ public class Nad27UtmProjection : GeoApiProjection
+ {
+ public const int FirstZone = 1;
+ public const int LastZone = 22;
+ public const int FirstZoneEpsgCode = 26700 + FirstZone;
+ public const int LastZoneEpsgCode = 26700 + LastZone;
+
+ public int Zone { get; }
+
+ public Nad27UtmProjection(int zone)
+ {
+ if (zone < FirstZone || zone > LastZone)
+ {
+ throw new ArgumentException($"Invalid NAD27 UTM zone {zone}.", nameof(zone));
+ }
+
+ Zone = zone;
+ CoordinateSystemWkt
+ = $"PROJCS[\"NAD27 / UTM zone {zone}N\","
+ + "GEOGCS[\"NAD27\","
+ + "DATUM[\"North_American_Datum_1927\","
+ + "SPHEROID[\"Clarke 1866\",6378206.4,294.978698213898],"
+ + "]," //"EXTENSION[\"PROJ4_GRIDS\",\"NTv2_0.gsb\"]]," -- not recognized
+ + "PRIMEM[\"Greenwich\",0,AUTHORITY[\"EPSG\",\"8901\"]],"
+ + "UNIT[\"degree\",0.0174532925199433,AUTHORITY[\"EPSG\",\"9122\"]],"
+ + "AUTHORITY[\"EPSG\",\"4267\"]],"
+ + "PROJECTION[\"Transverse_Mercator\"],"
+ + "PARAMETER[\"latitude_of_origin\",0],"
+ + $"PARAMETER[\"central_meridian\",{6 * zone - 183}],"
+ + "PARAMETER[\"scale_factor\",0.9996],"
+ + "PARAMETER[\"false_easting\",500000],"
+ + "PARAMETER[\"false_northing\",0],"
+ + "UNIT[\"metre\",1,AUTHORITY[\"EPSG\",\"9001\"]],"
+ + "AXIS[\"Easting\",EAST],"
+ + "AXIS[\"Northing\",NORTH],"
+ + $"AUTHORITY[\"EPSG\",\"267{zone}\"]]";
+ }
+ }
+}
diff --git a/MapProjections/Shared/Nad83UtmProjection.cs b/MapProjections/Shared/Nad83UtmProjection.cs
new file mode 100644
index 00000000..47265657
--- /dev/null
+++ b/MapProjections/Shared/Nad83UtmProjection.cs
@@ -0,0 +1,50 @@
+// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
+// © 2022 Clemens Fischer
+// Licensed under the Microsoft Public License (Ms-PL)
+
+using System;
+
+namespace MapControl.Projections
+{
+ ///
+ /// NAD83 UTM Projection with zone number.
+ ///
+ public class Nad83UtmProjection : GeoApiProjection
+ {
+ public const int FirstZone = 1;
+ public const int LastZone = 23;
+ public const int FirstZoneEpsgCode = 26900 + FirstZone;
+ public const int LastZoneEpsgCode = 26900 + LastZone;
+
+ public int Zone { get; }
+
+ public Nad83UtmProjection(int zone)
+ {
+ if (zone < FirstZone || zone > LastZone)
+ {
+ throw new ArgumentException($"Invalid NAD83 UTM zone {zone}.", nameof(zone));
+ }
+
+ Zone = zone;
+ CoordinateSystemWkt
+ = $"PROJCS[\"NAD83 / UTM zone {zone}N\","
+ + "GEOGCS[\"NAD83\","
+ + "DATUM[\"North_American_Datum_1983\","
+ + "SPHEROID[\"GRS 1980\",6378137,298.257222101],"
+ + "TOWGS84[0,0,0,0,0,0,0]],"
+ + "PRIMEM[\"Greenwich\",0,AUTHORITY[\"EPSG\",\"8901\"]],"
+ + "UNIT[\"degree\",0.0174532925199433,AUTHORITY[\"EPSG\",\"9122\"]],"
+ + "AUTHORITY[\"EPSG\",\"4269\"]],"
+ + "PROJECTION[\"Transverse_Mercator\"],"
+ + "PARAMETER[\"latitude_of_origin\",0],"
+ + $"PARAMETER[\"central_meridian\",{6 * zone - 183}],"
+ + "PARAMETER[\"scale_factor\",0.9996],"
+ + "PARAMETER[\"false_easting\",500000],"
+ + "PARAMETER[\"false_northing\",0],"
+ + "UNIT[\"metre\",1,AUTHORITY[\"EPSG\",\"9001\"]],"
+ + "AXIS[\"Easting\",EAST],"
+ + "AXIS[\"Northing\",NORTH],"
+ + $"AUTHORITY[\"EPSG\",\"269{zone}\"]]";
+ }
+ }
+}
diff --git a/MapProjections/Shared/WebMercatorProjection.cs b/MapProjections/Shared/WebMercatorProjection.cs
index 19b4f559..ffaed777 100644
--- a/MapProjections/Shared/WebMercatorProjection.cs
+++ b/MapProjections/Shared/WebMercatorProjection.cs
@@ -13,6 +13,8 @@ namespace MapControl.Projections
///
public class WebMercatorProjection : GeoApiProjection
{
+ public const int DefaultEpsgCode = 3857;
+
public WebMercatorProjection()
{
CoordinateSystem = ProjectedCoordinateSystem.WebMercator;
diff --git a/MapProjections/Shared/Wgs84AutoUtmProjection.cs b/MapProjections/Shared/Wgs84AutoUtmProjection.cs
deleted file mode 100644
index 3b7c00cf..00000000
--- a/MapProjections/Shared/Wgs84AutoUtmProjection.cs
+++ /dev/null
@@ -1,56 +0,0 @@
-// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
-// © 2022 Clemens Fischer
-// Licensed under the Microsoft Public License (Ms-PL)
-
-using ProjNet.CoordinateSystems;
-using System;
-
-namespace MapControl.Projections
-{
- public class Wgs84AutoUtmProjection : GeoApiProjection
- {
- public const string DefaultCrsId = "AUTO2:42001";
-
- public Wgs84AutoUtmProjection(bool useZoneCrsId = false)
- {
- UseZoneCrsId = useZoneCrsId;
- UpdateZone();
- }
-
- public int Zone { get; private set; }
- public bool IsNorth { get; private set; }
- public bool UseZoneCrsId { get; }
-
- public override Location Center
- {
- get => base.Center;
- 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;
-
- if (Zone != zone || IsNorth != north)
- {
- Zone = zone;
- IsNorth = north;
- CoordinateSystem = ProjectedCoordinateSystem.WGS84_UTM(Zone, IsNorth);
-
- if (!UseZoneCrsId)
- {
- CrsId = DefaultCrsId;
- }
- }
- }
- }
-}
diff --git a/MapProjections/Shared/Wgs84UtmProjection.cs b/MapProjections/Shared/Wgs84UtmProjection.cs
index 1072853e..1ea655f0 100644
--- a/MapProjections/Shared/Wgs84UtmProjection.cs
+++ b/MapProjections/Shared/Wgs84UtmProjection.cs
@@ -7,16 +7,86 @@ using System;
namespace MapControl.Projections
{
+ ///
+ /// WGS84 UTM Projection with zone number and north/south flag.
+ ///
public class Wgs84UtmProjection : GeoApiProjection
{
+ public const int FirstZone = 1;
+ public const int LastZone = 60;
+ public const int FirstZoneNorthEpsgCode = 32600 + FirstZone;
+ public const int LastZoneNorthEpsgCode = 32600 + LastZone;
+ public const int FirstZoneSouthEpsgCode = 32700 + FirstZone;
+ public const int LastZoneSouthEpsgCode = 32700 + LastZone;
+
+ public int Zone { get; private set; }
+ public bool IsNorth { get; private set; }
+
+ protected Wgs84UtmProjection()
+ {
+ }
+
public Wgs84UtmProjection(int zone, bool north)
{
- if (zone < 1 || zone > 60)
+ SetZone(zone, north);
+ }
+
+ protected void SetZone(int zone, bool north)
+ {
+ if (zone < FirstZone || zone > LastZone)
{
- throw new ArgumentException($"Invalid UTM zone {zone}.", nameof(zone));
+ throw new ArgumentException($"Invalid WGS84 UTM zone {zone}.", nameof(zone));
}
- CoordinateSystem = ProjectedCoordinateSystem.WGS84_UTM(zone, north);
+ Zone = zone;
+ IsNorth = north;
+ CoordinateSystem = ProjectedCoordinateSystem.WGS84_UTM(Zone, IsNorth);
+ }
+ }
+
+ ///
+ /// WGS84 UTM Projection with automatic zone selection from projection center.
+ ///
+ public class Wgs84AutoUtmProjection : Wgs84UtmProjection
+ {
+ public const string DefaultCrsId = "AUTO2:42001";
+
+ public Wgs84AutoUtmProjection(bool useZoneCrsId = false)
+ {
+ UseZoneCrsId = useZoneCrsId;
+ UpdateZone();
+ }
+
+ public bool UseZoneCrsId { get; }
+
+ public override Location Center
+ {
+ get => base.Center;
+ 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;
+
+ if (Zone != zone || IsNorth != north || string.IsNullOrEmpty(CrsId))
+ {
+ SetZone(zone, north);
+
+ if (!UseZoneCrsId)
+ {
+ CrsId = DefaultCrsId;
+ }
+ }
}
}
}
diff --git a/MapProjections/Shared/WorldMercatorProjection.cs b/MapProjections/Shared/WorldMercatorProjection.cs
index 185f081e..b7a73060 100644
--- a/MapProjections/Shared/WorldMercatorProjection.cs
+++ b/MapProjections/Shared/WorldMercatorProjection.cs
@@ -12,6 +12,8 @@ namespace MapControl.Projections
///
public class WorldMercatorProjection : GeoApiProjection
{
+ public const int DefaultEpsgCode = 3395;
+
public WorldMercatorProjection()
{
CoordinateSystemWkt
diff --git a/MapProjections/UWP/MapProjections.UWP.csproj b/MapProjections/UWP/MapProjections.UWP.csproj
index 4ae24b5b..6ce0adee 100644
--- a/MapProjections/UWP/MapProjections.UWP.csproj
+++ b/MapProjections/UWP/MapProjections.UWP.csproj
@@ -55,9 +55,6 @@
WebMercatorProjection.cs
-
- Wgs84AutoUtmProjection.cs
-
Wgs84UtmProjection.cs
diff --git a/SampleApps/Shared/UTM2GTIF.tiff b/SampleApps/Shared/UTM2GTIF.tiff
new file mode 100644
index 00000000..a0fde79e
Binary files /dev/null and b/SampleApps/Shared/UTM2GTIF.tiff differ
diff --git a/SampleApps/UniversalApp/MainPage.xaml b/SampleApps/UniversalApp/MainPage.xaml
index 96c756d9..d4b58aab 100644
--- a/SampleApps/UniversalApp/MainPage.xaml
+++ b/SampleApps/UniversalApp/MainPage.xaml
@@ -210,6 +210,19 @@
ServiceUri="http://ows.terrestris.de/osm/service"/>
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -220,18 +233,8 @@
-
-
-
-
-
-
-
-
-
-
-
-
+
+
@@ -242,6 +245,8 @@
Map="{Binding ElementName=map}">
+
+
10_535_330.jpg
+
+ UTM2GTIF.tiff
+
diff --git a/SampleApps/WinUiApp/MainWindow.xaml b/SampleApps/WinUiApp/MainWindow.xaml
index 6e23ad9d..2971ba62 100644
--- a/SampleApps/WinUiApp/MainWindow.xaml
+++ b/SampleApps/WinUiApp/MainWindow.xaml
@@ -218,6 +218,19 @@
ServiceUri="http://ows.terrestris.de/osm/service"/>
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -228,18 +241,8 @@
-
-
-
-
-
-
-
-
-
-
-
-
+
+
@@ -249,6 +252,8 @@
Map="{Binding ElementName=map}">
+
+
+
diff --git a/SampleApps/WpfApplication/MainWindow.xaml b/SampleApps/WpfApplication/MainWindow.xaml
index dfbfe390..e04bfa68 100644
--- a/SampleApps/WpfApplication/MainWindow.xaml
+++ b/SampleApps/WpfApplication/MainWindow.xaml
@@ -184,6 +184,13 @@
+
+
+
+
+
+
+
@@ -191,12 +198,8 @@
-
-
-
-
-
-
+
+
@@ -206,6 +209,8 @@
Map="{Binding ElementName=map}">
+
+
Always
+
+ Always
+
+
+
+
+ Never
+
+
\ No newline at end of file