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; } }