From 3ee308caeebd10a200e0eab80775e3e8129c2ec8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A1ssio=20Morales?= Date: Mon, 25 May 2026 13:50:59 -0300 Subject: [PATCH] Fix UTM discontinuity across zones and hemispheres (#41) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Cássio Morales --- Visualizer/ShapeExtensions.cs | 19 +++++++++++++++++-- Visualizer/SpatialRecordProcessor.cs | 8 +++++++- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/Visualizer/ShapeExtensions.cs b/Visualizer/ShapeExtensions.cs index a565bea..a3381f4 100644 --- a/Visualizer/ShapeExtensions.cs +++ b/Visualizer/ShapeExtensions.cs @@ -23,11 +23,26 @@ public static class ShapeExtensions private const double EccPrimeSquared = (EccSquared) / (1 - EccSquared); public static ApplicationDataModel.Shapes.Point ToUtm(this ApplicationDataModel.Shapes.Point point) + { + return ProjectToUtm(point, GetLongOrigin(point.X), point.Y < 0); + } + + public static ApplicationDataModel.Shapes.Point ToUtmRelativeToSpatialRecordFirstPoint( + this ApplicationDataModel.Shapes.Point point, + ApplicationDataModel.Shapes.Point firstPoint) + { + return ProjectToUtm(point, GetLongOrigin(firstPoint.X), firstPoint.Y < 0); + } + + private static ApplicationDataModel.Shapes.Point ProjectToUtm( + ApplicationDataModel.Shapes.Point point, + double longitudeOriginDegrees, + bool applySouthernHemisphereOffset) { var latitudeInRadians = point.Y * ConstDeg2Rad; var longitudeInRadians = point.X * ConstDeg2Rad; - var longitudeOriginInRadians = GetLongOrigin(point.X) * ConstDeg2Rad; + var longitudeOriginInRadians = longitudeOriginDegrees * ConstDeg2Rad; var n = A / Math.Sqrt(1 - EccSquared * Math.Sin(latitudeInRadians) * Math.Sin(latitudeInRadians)); var t = Math.Tan(latitudeInRadians) * Math.Tan(latitudeInRadians); @@ -48,7 +63,7 @@ public static ApplicationDataModel.Shapes.Point ToUtm(this ApplicationDataModel. (61 - 58 * t + t * t + 600 * c - 330 * EccPrimeSquared) * a1 * a1 * a1 * a1 * a1 * a1 / 720)); - if (point.Y < 0) + if (applySouthernHemisphereOffset) { utmNorthing += 10000000.0; } diff --git a/Visualizer/SpatialRecordProcessor.cs b/Visualizer/SpatialRecordProcessor.cs index 713cc04..c6e5fcc 100644 --- a/Visualizer/SpatialRecordProcessor.cs +++ b/Visualizer/SpatialRecordProcessor.cs @@ -58,6 +58,7 @@ public void ThemeMap(string workingDataKey) List projectedPoints = new List(); List doubleValues = null; + Point? firstPoint = null; foreach (SpatialRecord record in _spatialRecords) { Point? point = record.Geometry.FirstPoint(); @@ -66,7 +67,12 @@ public void ThemeMap(string workingDataKey) continue; } - projectedPoints.Add(point.ToUtm()); + if (firstPoint == null) + { + firstPoint = point; + } + + projectedPoints.Add(point.ToUtmRelativeToSpatialRecordFirstPoint(firstPoint)); if (_workingDataDictionary.ContainsKey(workingDataKey)) {