diff options
Diffstat (limited to 'PositionCalculator.cs')
| -rw-r--r-- | PositionCalculator.cs | 100 |
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 |
