/// <summary> /// Performs an OSGB36/ODN to ETRS89 datum transformation. Accuracy is approximately 10 centimeters. /// Whilst very accurate this method is much slower than the Helmert transformation. /// </summary> public static LatitudeLongitude OsgbToEtrs89(Osgb36 coordinates, OstnVersionEnum ostnVersion = OstnVersionEnum.OSTN15) { //calculate shifts from OSGB36 point double errorN = double.MaxValue; double errorE = double.MaxValue; EastingNorthing enCoordinates = null; Shifts shiftsA = GetShifts(coordinates, ostnVersion); //0.0001 error meters int iter = 0; while ((errorN > 0.0001 || errorE > 0.0001) && iter < 10) { enCoordinates = new EastingNorthing(coordinates.Easting - shiftsA.Se, coordinates.Northing - shiftsA.Sn); Shifts shiftsB = GetShifts(enCoordinates, ostnVersion); errorE = Math.Abs(shiftsA.Se - shiftsB.Se); errorN = Math.Abs(shiftsA.Sn - shiftsB.Sn); shiftsA = shiftsB; iter++; } return(Convert.ToLatitudeLongitude(new Wgs84(), new BritishNationalGrid(), enCoordinates)); }
/// <summary> /// Retrieves the parsed OSTN data from the embedded resource file. /// </summary> /// <param name="ostnVersion"></param> /// <returns></returns> private static Dictionary <int, OstnDataRecord> GetOstnData(OstnVersionEnum ostnVersion) { switch (ostnVersion) { case OstnVersionEnum.OSTN02: return(ResourceManager.Ostn02Data); case OstnVersionEnum.OSTN15: return(ResourceManager.Ostn15Data); default: throw new NotImplementedException(); } }
/// <summary> /// Gets the embedded OSTN data /// </summary> /// <param name="ostnVersion"></param> /// <returns></returns> private static Dictionary <int, OstnDataRecord> RetrieveEmbeddedOSTN(OstnVersionEnum ostnVersion) { Stream stream; switch (ostnVersion) { case OstnVersionEnum.OSTN02: stream = GetEmbeddedResourceStream(typeof(Transform).GetTypeInfo().Assembly, "OSTN02_OSGM02_GB.txt"); break; case OstnVersionEnum.OSTN15: stream = GetEmbeddedResourceStream(typeof(Transform).GetTypeInfo().Assembly, "OSTN15_OSGM15_DataFile.txt"); break; default: throw new NotImplementedException(); } Dictionary <int, OstnDataRecord> data = new Dictionary <int, OstnDataRecord>(); using (StreamReader reader = new StreamReader(stream)) { // Skipping the header row reader.ReadLine(); string line; while ((line = reader.ReadLine()) != null) { if (string.IsNullOrWhiteSpace(line)) { continue; } string[] values = line.Split(','); OstnDataRecord record = new OstnDataRecord { Point_ID = int.Parse(values[0]), ETRS89_Easting = double.Parse(values[1]), ETRS89_Northing = double.Parse(values[2]), ETRS89_OSGB36_EShift = double.Parse(values[3]), ETRS89_OSGB36_NShift = double.Parse(values[4]), ETRS89_ODN_HeightShift = double.Parse(values[5]), Height_Datum_Flag = double.Parse(values[6]), }; data[record.Point_ID] = record; } } return(data); }
private static Shifts GetShifts(EastingNorthing coordinates, OstnVersionEnum ostnVersion) { //See OS Document: Transformations and OSGM02/OSGM15 user guide chapter 3 Dictionary <int, OstnDataRecord> ostnData = GetOstnData(ostnVersion); List <int> recordNumbers = new List <int>(); OstnDataRecord[] records = new OstnDataRecord[4]; //determine record numbers int eastIndex = (int)(coordinates.Easting / 1000.0); int northIndex = (int)(coordinates.Northing / 1000.0); double x0 = eastIndex * 1000; double y0 = northIndex * 1000; //work out the four records recordNumbers.Add(CalculateRecordNumber(eastIndex, northIndex)); recordNumbers.Add(CalculateRecordNumber(eastIndex + 1, northIndex)); recordNumbers.Add(CalculateRecordNumber(eastIndex + 1, northIndex + 1)); recordNumbers.Add(CalculateRecordNumber(eastIndex, northIndex + 1)); // Get the corresponding records from the data dictionary for (int index = 0; index < 4; index++) { records[index] = ostnData[recordNumbers[index]]; } //populate the properties double se0 = System.Convert.ToDouble(records[0].ETRS89_OSGB36_EShift); double se1 = System.Convert.ToDouble(records[1].ETRS89_OSGB36_EShift); double se2 = System.Convert.ToDouble(records[2].ETRS89_OSGB36_EShift); double se3 = System.Convert.ToDouble(records[3].ETRS89_OSGB36_EShift); double sn0 = System.Convert.ToDouble(records[0].ETRS89_OSGB36_NShift); double sn1 = System.Convert.ToDouble(records[1].ETRS89_OSGB36_NShift); double sn2 = System.Convert.ToDouble(records[2].ETRS89_OSGB36_NShift); double sn3 = System.Convert.ToDouble(records[3].ETRS89_OSGB36_NShift); double sg0 = System.Convert.ToDouble(records[0].ETRS89_ODN_HeightShift); double sg1 = System.Convert.ToDouble(records[1].ETRS89_ODN_HeightShift); double sg2 = System.Convert.ToDouble(records[2].ETRS89_ODN_HeightShift); double sg3 = System.Convert.ToDouble(records[3].ETRS89_ODN_HeightShift); double dx = coordinates.Easting - x0; double dy = coordinates.Northing - y0; double t = dx / 1000.0; double u = dy / 1000.0; Shifts shifts = new Shifts { Se = (1 - t) * (1 - u) * se0 + t * (1 - u) * se1 + t * u * se2 + (1 - t) * u * se3, Sn = (1 - t) * (1 - u) * sn0 + t * (1 - u) * sn1 + t * u * sn2 + (1 - t) * u * sn3, Sg = (1 - t) * (1 - u) * sg0 + t * (1 - u) * sg1 + t * u * sg2 + (1 - t) * u * sg3, GeoidDatum = (Osgb36GeoidDatum)System.Convert.ToInt32(records[0].Height_Datum_Flag) }; return(shifts); }
private static Osgb36 Etrs89ToOsgb(EastingNorthing coordinates, double ellipsoidHeight, OstnVersionEnum ostnVersion = OstnVersionEnum.OSTN15) { Shifts shifts = GetShifts(coordinates, ostnVersion); double easting = coordinates.Easting + shifts.Se; double northing = coordinates.Northing + shifts.Sn; double height = ellipsoidHeight - shifts.Sg; return(new Osgb36(easting, northing, height, shifts.GeoidDatum)); }