aboutsummaryrefslogtreecommitdiff
path: root/PositionCalculator.cs
diff options
context:
space:
mode:
authorJake Mannens <jake@asger.xyz>2024-09-20 16:13:30 +1000
committerJake Mannens <jake@asger.xyz>2024-10-28 14:53:04 +1100
commit7c6009abd22d8461039be15d0fd069a460340585 (patch)
tree580890eacc1ae2d86ee3f95927e3aed47bb12c96 /PositionCalculator.cs
v0.1v0.1
Diffstat (limited to 'PositionCalculator.cs')
-rw-r--r--PositionCalculator.cs100
1 files changed, 100 insertions, 0 deletions
diff --git a/PositionCalculator.cs b/PositionCalculator.cs
new file mode 100644
index 0000000..8d8a94f
--- /dev/null
+++ b/PositionCalculator.cs
@@ -0,0 +1,100 @@
+using CoordinateSharp;
+using PagerParser;
+using System;
+using System.ComponentModel.DataAnnotations.Schema;
+using System.Text.RegularExpressions;
+
+namespace PagerParser;
+
+public class GpsPosition {
+ [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
+ public int GpsPositionId { get; set; }
+ public double Latitude { get; set; }
+ public double Longitude { get; set; }
+}
+
+public record MelwaysPage {
+ public int PageNo { get; set; }
+ public double Latitude { get; set; }
+ public double Longitude { get; set; }
+}
+
+// Derive roughly-accurate GPS coordinates from a Melways page number
+// and grid number (e.g: 131 D7) by looking up the origin coordinates
+// of the Melways page from a pre-defined table, then interpolating
+// the grid number across the page to get a (very) rough position.
+public class PositionCalculator {
+ private const float PageWidth = 0.0583403752108005f;
+ private const float PageHeight = 0.0444074086328539f;
+
+ private const int ColCount = 10;
+ private const int RowCount = 12;
+
+ private const float ColWidth = PageWidth / ColCount;
+ private const float RowHeight = PageHeight / RowCount;
+
+ private static readonly MelwaysPage[] MelwaysPages = {
+ new MelwaysPage { PageNo = 94, Latitude = -38.0062431030181, Longitude = 145.153465677450 },
+ new MelwaysPage { PageNo = 95, Latitude = -38.0061349929752, Longitude = 145.197873798763 },
+ new MelwaysPage { PageNo = 96, Latitude = -38.0060458242193, Longitude = 145.242282747795 },
+ new MelwaysPage { PageNo = 98, Latitude = -38.0501502394990, Longitude = 145.153538108815 },
+ new MelwaysPage { PageNo = 110, Latitude = -38.0059397267576, Longitude = 145.286740799198 },
+ new MelwaysPage { PageNo = 111, Latitude = -38.0058646642328, Longitude = 145.331164408607 },
+ new MelwaysPage { PageNo = 128, Latitude = -38.0500712736303, Longitude = 145.197997939698 },
+ new MelwaysPage { PageNo = 129, Latitude = -38.0499811306888, Longitude = 145.242424322651 },
+ new MelwaysPage { PageNo = 130, Latitude = -38.0498760059982, Longitude = 145.286857218675 },
+ new MelwaysPage { PageNo = 131, Latitude = -38.0497905233513, Longitude = 145.331303121527 },
+ new MelwaysPage { PageNo = 212, Latitude = -38.0056782419614, Longitude = 145.375580424547 },
+ new MelwaysPage { PageNo = 213, Latitude = -38.0055063939227, Longitude = 145.419999796841 },
+ new MelwaysPage { PageNo = 214, Latitude = -38.0496145139129, Longitude = 145.375744441368 },
+ new MelwaysPage { PageNo = 215, Latitude = -38.0494726543543, Longitude = 145.420190429893 },
+ new MelwaysPage { PageNo = 315, Latitude = -38.0053618479218, Longitude = 145.464319398407 },
+ new MelwaysPage { PageNo = 317, Latitude = -38.0493097638301, Longitude = 145.464666307851 }
+ };
+
+ public static GpsPosition? GetGpsPosition(ParsedPagerMessage message) {
+ if(message.MelwaysMapNo is null || message.MelwaysGrid is null)
+ return null;
+ var page = MelwaysPages.FirstOrDefault(p => p.PageNo == message.MelwaysMapNo);
+ if(page is null)
+ return null;
+
+ var match = Regex.Match(message.MelwaysGrid.ToUpper(), "^([A-HJ-K])([0-9]+)$");
+ if(!match.Success)
+ return null;
+
+ var row = int.Parse(match.Groups[2].Value) - 1;
+ var col = match.Groups[1].Value[0] - 'A';
+ if(col > 7)
+ col -= 1; // Compensate for Melways grids skipping 'I'
+
+ var position = new GpsPosition {
+ Latitude = page.Latitude - (row * RowHeight) - (RowHeight / 2),
+ Longitude = page.Longitude + (col * ColWidth) + (ColWidth / 2)
+ };
+
+ if(message.GridReference is null)
+ return position;
+
+ // If we have a 6-digit grid reference, try to refine the location further
+ // using the UTM coordinate system. Since zone information isn't included
+ // in a 6-digit grid reference, we use the coordinates calculated from the
+ // Melways as a starting point to find the zone.
+
+ double gridRef = (double) message.GridReference;
+
+ var origUTM = new Coordinate(position.Latitude, position.Longitude).UTM;
+ var newUTM = new UniversalTransverseMercator(
+ origUTM.LatZone,
+ origUTM.LongZone,
+ (Math.Floor(origUTM.Easting / 100000) * 100000) + (Math.Floor(gridRef / 1000) * 100),
+ (Math.Floor(origUTM.Northing / 100000) * 100000) + ((gridRef % 1000) * 100));
+
+ var coord = UniversalTransverseMercator.ConvertUTMtoLatLong(newUTM);
+
+ position.Latitude = coord.Latitude.ToDouble();
+ position.Longitude = coord.Longitude.ToDouble();
+
+ return position;
+ }
+} \ No newline at end of file