code cleaned using CodeMaid

This commit is contained in:
Ieuan Walker
2019-07-12 19:49:45 +01:00
parent 8bdb910dfd
commit aa0f376e55
29 changed files with 816 additions and 855 deletions

View File

@@ -16,4 +16,4 @@ namespace GeoUK.OSTN.Tests
return (Math.Abs(initialValue - value) < maximumDifferenceAllowed);
}
}
}
}

View File

@@ -1,10 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace GeoUK.OSTN.Tests.Models
namespace GeoUK.OSTN.Tests.Models
{
public class DataPoint
{
@@ -13,4 +7,4 @@ namespace GeoUK.OSTN.Tests.Models
public double Y { get; set; }
public double Height { get; set; }
}
}
}

View File

@@ -1,8 +1,7 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("GeoUK.OSTN.Tests")]
@@ -14,8 +13,8 @@ using System.Runtime.InteropServices;
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
@@ -25,12 +24,12 @@ using System.Runtime.InteropServices;
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

View File

@@ -1,11 +1,8 @@
using System;
using GeoUK.Coordinates;
using GeoUK.OSTN.Tests.Models;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using GeoUK.Coordinates;
using GeoUK.OSTN.Tests.Models;
using Xunit;
namespace GeoUK.OSTN.Tests
@@ -87,7 +84,7 @@ namespace GeoUK.OSTN.Tests
var inputData = new List<DataPoint>();
var outputData = new Dictionary<string, DataPoint>();
using (var inputFile = new StreamReader(inputFileName))
{
string line;
@@ -153,4 +150,4 @@ namespace GeoUK.OSTN.Tests
}
}
}
}
}

View File

@@ -1,10 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace GeoUK.OSTN
namespace GeoUK.OSTN
{
public class OstnDataRecord
{
@@ -16,4 +10,4 @@ namespace GeoUK.OSTN
public double ETRS89_ODN_HeightShift { get; set; }
public double Height_Datum_Flag { get; set; }
}
}
}

View File

@@ -5,4 +5,4 @@
OSTN02 = 1,
OSTN15 = 2
}
}
}

View File

@@ -1,15 +1,15 @@
using System;
using System.IO;
using System.Collections.Generic;
using System.Text;
using System.Reflection;
using System.IO;
using System.Linq;
using System.Reflection;
namespace GeoUK.OSTN
{
internal static class ResourceManager
{
private static Dictionary<int, OstnDataRecord> _ostn02Data;
public static Dictionary<int, OstnDataRecord> Ostn02Data
{
get
@@ -21,6 +21,7 @@ namespace GeoUK.OSTN
}
private static Dictionary<int, OstnDataRecord> _ostn15Data;
public static Dictionary<int, OstnDataRecord> Ostn15Data
{
get
@@ -37,7 +38,7 @@ namespace GeoUK.OSTN
/// <param name="ostnVersion">If not provided, it will load both OSTN02 and OSTN15 data.</param>
public static void LoadResources(OstnVersionEnum? ostnVersion = null)
{
if(!ostnVersion.HasValue || ostnVersion.Value == OstnVersionEnum.OSTN02)
if (!ostnVersion.HasValue || ostnVersion.Value == OstnVersionEnum.OSTN02)
_ostn02Data = RetrieveEmbeddedOSTN(OstnVersionEnum.OSTN02);
if (!ostnVersion.HasValue || ostnVersion.Value == OstnVersionEnum.OSTN15)
@@ -57,9 +58,11 @@ namespace GeoUK.OSTN
case OstnVersionEnum.OSTN02:
stream = ResourceManager.GetEmbeddedResourceStream(typeof(Transform).GetTypeInfo().Assembly, "OSTN02_OSGM02_GB.txt");
break;
case OstnVersionEnum.OSTN15:
stream = ResourceManager.GetEmbeddedResourceStream(typeof(Transform).GetTypeInfo().Assembly, "OSTN15_OSGM15_DataFile.txt");
break;
default:
throw new NotImplementedException();
}
@@ -100,23 +103,25 @@ namespace GeoUK.OSTN
/// <returns>The embedded resource stream.</returns>
/// <param name="assembly">Assembly.</param>
/// <param name="resourceFileName">Resource file name.</param>
private static Stream GetEmbeddedResourceStream (Assembly assembly, string resourceFileName)
{
var resourceNames = assembly.GetManifestResourceNames ();
private static Stream GetEmbeddedResourceStream(Assembly assembly, string resourceFileName)
{
var resourceNames = assembly.GetManifestResourceNames();
var resourcePaths = resourceNames
.Where (x => x.EndsWith (resourceFileName, StringComparison.CurrentCultureIgnoreCase))
.ToArray ();
var resourcePaths = resourceNames
.Where(x => x.EndsWith(resourceFileName, StringComparison.CurrentCultureIgnoreCase))
.ToArray();
if (!resourcePaths.Any ()) {
throw new Exception (String.Format ("Resource ending with {0} not found.", resourceFileName));
}
if (!resourcePaths.Any())
{
throw new Exception(String.Format("Resource ending with {0} not found.", resourceFileName));
}
if (resourcePaths.Count () > 1) {
throw new Exception (String.Format ("Multiple resources ending with {0} found: {1}{2}", resourceFileName, Environment.NewLine, String.Join (Environment.NewLine, resourcePaths)));
}
if (resourcePaths.Count() > 1)
{
throw new Exception(String.Format("Multiple resources ending with {0} found: {1}{2}", resourceFileName, Environment.NewLine, String.Join(Environment.NewLine, resourcePaths)));
}
return assembly.GetManifestResourceStream (resourcePaths.Single ());
}
return assembly.GetManifestResourceStream(resourcePaths.Single());
}
}
}
}

View File

@@ -1,16 +1,13 @@
using System;
using GeoUK.Coordinates;
using GeoUK.Coordinates;
namespace GeoUK.OSTN
{
public class Shifts
{
public double Se { get; set; }
public double Sn { get; set; }
public double Sg { get; set; }
public Osgb36GeoidDatum GeoidDatum { get; set; }
}
}
public class Shifts
{
public double Se { get; set; }
public double Sn { get; set; }
public double Sg { get; set; }
public Osgb36GeoidDatum GeoidDatum { get; set; }
}
}

View File

@@ -1,149 +1,143 @@
using System;
using GeoUK.Coordinates;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using GeoUK.Coordinates;
using GeoUK.Ellipsoids;
using GeoUK.Projections;
using System;
using System.Collections.Generic;
namespace GeoUK.OSTN
{
public static class Transform
{
/// <summary>
/// Loads the OSTN data into memory.
/// </summary>
/// <param name="ostnVersion">If not provided, it will load both OSTN02 and OSTN15 data.</param>
public static void PreloadResources(OstnVersionEnum? ostnVersion = null)
{
public static class Transform
{
/// <summary>
/// Loads the OSTN data into memory.
/// </summary>
/// <param name="ostnVersion">If not provided, it will load both OSTN02 and OSTN15 data.</param>
public static void PreloadResources(OstnVersionEnum? ostnVersion = null)
{
ResourceManager.LoadResources(ostnVersion);
}
}
/// <summary>
/// Performs an ETRS89 to OSGB36/ODN datum transformation. Accuracy is approximately 10 centimeters.
/// <summary>
/// Performs an ETRS89 to OSGB36/ODN datum transformation. Accuracy is approximately 10 centimeters.
/// Whilst very accurate this method is much slower than the Helmert transformation.
/// </summary>
public static Osgb36 Etrs89ToOsgb(LatitudeLongitude coordinates, OstnVersionEnum ostnVersion = OstnVersionEnum.OSTN15)
{
var enCoordinates = Convert.ToEastingNorthing (new Grs80 (), new BritishNationalGrid (), coordinates);
return Etrs89ToOsgb (enCoordinates, coordinates.ElipsoidalHeight);
}
{
var enCoordinates = Convert.ToEastingNorthing(new Grs80(), new BritishNationalGrid(), coordinates);
return Etrs89ToOsgb(enCoordinates, coordinates.ElipsoidalHeight);
}
private static Osgb36 Etrs89ToOsgb(EastingNorthing coordinates, double ellipsoidHeight, OstnVersionEnum ostnVersion = OstnVersionEnum.OSTN15)
{
var shifts = GetShifts (coordinates, ellipsoidHeight, ostnVersion);
private static Osgb36 Etrs89ToOsgb(EastingNorthing coordinates, double ellipsoidHeight, OstnVersionEnum ostnVersion = OstnVersionEnum.OSTN15)
{
var shifts = GetShifts(coordinates, ellipsoidHeight, ostnVersion);
var easting = coordinates.Easting + shifts.Se;
var northing = coordinates.Northing + shifts.Sn;
var height = ellipsoidHeight - shifts.Sg;
var easting = coordinates.Easting + shifts.Se;
var northing = coordinates.Northing + shifts.Sn;
var height = ellipsoidHeight - shifts.Sg;
return new Osgb36(easting, northing, height, shifts.GeoidDatum);
return new Osgb36(easting, northing, height, shifts.GeoidDatum);
}
}
/// <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;
/// <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;
var shiftsA = GetShifts(coordinates, coordinates.Height, ostnVersion);
var shiftsA = GetShifts (coordinates, coordinates.Height, 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);
var shiftsB = GetShifts(enCoordinates, coordinates.Height, ostnVersion);
//0.0001 error meters
int iter = 0;
while ((errorN > 0.0001 || errorE > 0.0001) && iter <10) {
errorE = Math.Abs(shiftsA.Se - shiftsB.Se);
errorN = Math.Abs(shiftsA.Sn - shiftsB.Sn);
enCoordinates = new EastingNorthing (coordinates.Easting - shiftsA.Se, coordinates.Northing - shiftsA.Sn);
var shiftsB = GetShifts (enCoordinates, coordinates.Height, ostnVersion);
shiftsA = shiftsB;
iter++;
}
errorE = Math.Abs (shiftsA.Se - shiftsB.Se);
errorN = Math.Abs (shiftsA.Sn - shiftsB.Sn);
return Convert.ToLatitudeLongitude(new Wgs84(), new BritishNationalGrid(), enCoordinates);
}
shiftsA = shiftsB;
iter++;
private static Shifts GetShifts(EastingNorthing coordinates, double ellipsoidHeight, OstnVersionEnum ostnVersion)
{
//See OS Document: Transformations and OSGM02/OSGM15 user guide chapter 3
var ostnData = GetOstnData(ostnVersion);
}
List<int> recordNumbers = new List<int>();
var records = new OstnDataRecord[4];
return Convert.ToLatitudeLongitude(new Wgs84(), new BritishNationalGrid(), enCoordinates);
//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;
private static Shifts GetShifts (EastingNorthing coordinates, double ellipsoidHeight, OstnVersionEnum ostnVersion)
{
//See OS Document: Transformations and OSGM02/OSGM15 user guide chapter 3
var ostnData = GetOstnData(ostnVersion);
List<int> recordNumbers = new List<int> ();
var 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));
//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 reccords from the data dictionary
for (int index = 0; index < 4; index++)
{
records[index] = ostnData[recordNumbers[index]];
}
for (int index = 0; index < 4; index++)
{
records[index] = ostnData[recordNumbers[index]];
}
//populate the properties
var se0 = System.Convert.ToDouble (records[0].ETRS89_OSGB36_EShift);
var se1 = System.Convert.ToDouble (records[1].ETRS89_OSGB36_EShift);
var se2 = System.Convert.ToDouble (records[2].ETRS89_OSGB36_EShift);
var se3 = System.Convert.ToDouble (records[3].ETRS89_OSGB36_EShift);
var se0 = System.Convert.ToDouble(records[0].ETRS89_OSGB36_EShift);
var se1 = System.Convert.ToDouble(records[1].ETRS89_OSGB36_EShift);
var se2 = System.Convert.ToDouble(records[2].ETRS89_OSGB36_EShift);
var se3 = System.Convert.ToDouble(records[3].ETRS89_OSGB36_EShift);
var sn0 = System.Convert.ToDouble (records[0].ETRS89_OSGB36_NShift);
var sn1 = System.Convert.ToDouble (records[1].ETRS89_OSGB36_NShift);
var sn2 = System.Convert.ToDouble (records[2].ETRS89_OSGB36_NShift);
var sn3 = System.Convert.ToDouble (records[3].ETRS89_OSGB36_NShift);
var sn0 = System.Convert.ToDouble(records[0].ETRS89_OSGB36_NShift);
var sn1 = System.Convert.ToDouble(records[1].ETRS89_OSGB36_NShift);
var sn2 = System.Convert.ToDouble(records[2].ETRS89_OSGB36_NShift);
var sn3 = System.Convert.ToDouble(records[3].ETRS89_OSGB36_NShift);
var sg0 = System.Convert.ToDouble (records[0].ETRS89_ODN_HeightShift);
var sg1 = System.Convert.ToDouble (records[1].ETRS89_ODN_HeightShift);
var sg2 = System.Convert.ToDouble (records[2].ETRS89_ODN_HeightShift);
var sg3 = System.Convert.ToDouble (records[3].ETRS89_ODN_HeightShift);
var sg0 = System.Convert.ToDouble(records[0].ETRS89_ODN_HeightShift);
var sg1 = System.Convert.ToDouble(records[1].ETRS89_ODN_HeightShift);
var sg2 = System.Convert.ToDouble(records[2].ETRS89_ODN_HeightShift);
var sg3 = System.Convert.ToDouble(records[3].ETRS89_ODN_HeightShift);
var dx = coordinates.Easting - x0;
var dy = coordinates.Northing - y0;
var dx = coordinates.Easting - x0;
var dy = coordinates.Northing - y0;
var t = dx / 1000.0;
var u = dy / 1000.0;
var t = dx / 1000.0;
var u = dy / 1000.0;
var shifts = new Shifts ();
var shifts = new Shifts();
shifts.Se = (1 - t) * (1 - u) * se0 + t * (1 - u) * se1 + t * u * se2 + (1 - t) * u * se3;
shifts.Sn = (1 - t) * (1 - u) * sn0 + t * (1 - u) * sn1 + t * u * sn2 + (1 - t) * u * sn3;
shifts.Sg = (1 - t) * (1 - u) * sg0 + t * (1 - u) * sg1 + t * u * sg2 + (1 - t) * u * sg3;
shifts.Se = (1 - t) * (1 - u) * se0 + t * (1 - u) * se1 + t * u * se2 + (1 - t) * u * se3;
shifts.Sn = (1 - t) * (1 - u) * sn0 + t * (1 - u) * sn1 + t * u * sn2 + (1 - t) * u * sn3;
shifts.Sg = (1 - t) * (1 - u) * sg0 + t * (1 - u) * sg1 + t * u * sg2 + (1 - t) * u * sg3;
shifts.GeoidDatum = (Osgb36GeoidDatum)System.Convert.ToInt32 (records[0].Height_Datum_Flag);
shifts.GeoidDatum = (Osgb36GeoidDatum)System.Convert.ToInt32(records[0].Height_Datum_Flag);
return shifts;
}
return shifts;
}
/// <summary>
/// Calculates a data file record number.
/// </summary>
/// <param name="eastIndex"></param>
/// <param name="northIndex"></param>
/// <returns></returns>
private static int CalculateRecordNumber(int eastIndex, int northIndex)
{
return eastIndex + (northIndex * 701) + 1;
}
/// <summary>
/// Calculates a data file record number.
/// </summary>
/// <param name="eastIndex"></param>
/// <param name="northIndex"></param>
/// <returns></returns>
private static int CalculateRecordNumber(int eastIndex, int northIndex)
{
return eastIndex + (northIndex * 701) + 1;
}
/// <summary>
/// Retrieves the parsed OSTN data from the embedded resource file.
@@ -151,17 +145,18 @@ namespace GeoUK.OSTN
/// <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();
}
}
}
}
}
}

View File

@@ -1,44 +1,42 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Globalization;
using GeoUK.Coordinates;
using GeoUK.Ellipsoids;
using GeoUK.Projections;
using System;
using System.Globalization;
namespace GeoUK
{
/// <summary>
/// This class performs various generic conversions between coordinate systems and units of measure.
/// This class does not perform transformations.
/// </summary>
public static class Convert
{
/// <summary>
/// Method to convert from Easting Northing coordinates to Latitude Longitude coordinates.
/// </summary>
/// <returns>The latitude longitude.</returns>
/// <param name = "ellipsoid"></param>
/// <param name="projection">Projection.</param>
/// <param name="coordinates">Coordinates.</param>
public static LatitudeLongitude ToLatitudeLongitude (Ellipsoid ellipsoid, Projections.Projection projection, EastingNorthing coordinates)
{
double M;
var N = coordinates.Northing;
var E = coordinates.Easting;
/// <summary>
/// This class performs various generic conversions between coordinate systems and units of measure.
/// This class does not perform transformations.
/// </summary>
public static class Convert
{
/// <summary>
/// Method to convert from Easting Northing coordinates to Latitude Longitude coordinates.
/// </summary>
/// <returns>The latitude longitude.</returns>
/// <param name = "ellipsoid"></param>
/// <param name="projection">Projection.</param>
/// <param name="coordinates">Coordinates.</param>
public static LatitudeLongitude ToLatitudeLongitude(Ellipsoid ellipsoid, Projections.Projection projection, EastingNorthing coordinates)
{
double M;
var N = coordinates.Northing;
var E = coordinates.Easting;
//from OS Guide
//constants needed are a Semi-Major Axis , b , e2 , N0 , E0 , F0 ,φ0 , and λ0
double a = ellipsoid.SemiMajorAxis;
double b = ellipsoid.SemiMinorAxis;
double e2 = ellipsoid.EccentricitySquared;
double F0 = projection.ScaleFactor;
double lat0 = ToRadians (projection.TrueOriginLatitude);
double lon0 = ToRadians (projection.TrueOriginLongitude);
double E0 = projection.TrueOriginEasting;
double N0 = projection.TrueOriginNorthing;
//from OS Guide
//constants needed are a Semi-Major Axis , b , e2 , N0 , E0 , F0 ,φ0 , and λ0
double a = ellipsoid.SemiMajorAxis;
double b = ellipsoid.SemiMinorAxis;
double e2 = ellipsoid.EccentricitySquared;
double F0 = projection.ScaleFactor;
double lat0 = ToRadians(projection.TrueOriginLatitude);
double lon0 = ToRadians(projection.TrueOriginLongitude);
double E0 = projection.TrueOriginEasting;
double N0 = projection.TrueOriginNorthing;
/*
/*
Console.WriteLine ("a: {0}", a);
Console.WriteLine ("b: {0}", b);
Console.WriteLine ("e2: {0}", e2);
@@ -53,58 +51,58 @@ namespace GeoUK
Console.WriteLine ("E: {0}", E);
*/
var lat = ((N - N0) / (a * F0)) + lat0;
var lat = ((N - N0) / (a * F0)) + lat0;
//double n = (a - b) / (a + b);
//check for error and reiterate as required
int loopCount = 0;
do {
M = CalculateM (lat, lat0, a, b, F0);
//double n = (a - b) / (a + b);
//check for error and reiterate as required
int loopCount = 0;
do
{
M = CalculateM(lat, lat0, a, b, F0);
lat += ((N - N0 - M) / (a * F0));
lat += ((N - N0 - M) / (a * F0));
/*
/*
Console.WriteLine ("\nlat #{0}: {1}", loopCount + 1, lat);
Console.WriteLine ("M #{0}: {1}", loopCount + 1, M);
Console.WriteLine ("N - N0 - M #{0}: {1}\n", loopCount + 1, N - N0 - M);
*/
loopCount++;
} while (!IsNearlyZero (N - N0 - M, 1e-16) & loopCount < 10);
loopCount++;
} while (!IsNearlyZero(N - N0 - M, 1e-16) & loopCount < 10);
double v = a * F0 * Math.Pow ((1 - e2 * Math.Pow (Math.Sin (lat), 2)), -0.5);
double p = a * F0 * (1 - e2) * Math.Pow ((1 - e2 * Math.Pow (Math.Sin (lat), 2)), -1.5);
double n2 = (v / p) - 1;
double v = a * F0 * Math.Pow((1 - e2 * Math.Pow(Math.Sin(lat), 2)), -0.5);
double p = a * F0 * (1 - e2) * Math.Pow((1 - e2 * Math.Pow(Math.Sin(lat), 2)), -1.5);
double n2 = (v / p) - 1;
var VII = Math.Tan (lat) / (2 * p * v);
var VII = Math.Tan(lat) / (2 * p * v);
var VIIIa = Math.Tan (lat) / (24 * p * Math.Pow (v, 3));
var VIIIb = 5 + (3 * Math.Pow (Math.Tan (lat), 2)) + n2 - 9 * (Math.Pow (Math.Tan (lat), 2)) * n2;
var VIII = VIIIa * VIIIb;
var VIIIa = Math.Tan(lat) / (24 * p * Math.Pow(v, 3));
var VIIIb = 5 + (3 * Math.Pow(Math.Tan(lat), 2)) + n2 - 9 * (Math.Pow(Math.Tan(lat), 2)) * n2;
var VIII = VIIIa * VIIIb;
var IXa = Math.Tan (lat) / (720 * p * Math.Pow (v, 5));
var IXb = 61 + (90 * Math.Pow (Math.Tan (lat), 2)) + (45 * Math.Pow (Math.Tan (lat), 4));
var IX = IXa * IXb;
var IXa = Math.Tan(lat) / (720 * p * Math.Pow(v, 5));
var IXb = 61 + (90 * Math.Pow(Math.Tan(lat), 2)) + (45 * Math.Pow(Math.Tan(lat), 4));
var IX = IXa * IXb;
var X = MathEx.Secant (lat) / v;
var X = MathEx.Secant(lat) / v;
var XIa = MathEx.Secant (lat) / (6 * Math.Pow (v, 3));
var XIb = v / p + (2 * Math.Pow (Math.Tan (lat), 2));
var XI = XIa * XIb;
var XIa = MathEx.Secant(lat) / (6 * Math.Pow(v, 3));
var XIb = v / p + (2 * Math.Pow(Math.Tan(lat), 2));
var XI = XIa * XIb;
var XIIa = MathEx.Secant (lat) / (120 * Math.Pow (v, 5));
var XIIb = 5 + (28 * Math.Pow (Math.Tan (lat), 2)) + (24 * Math.Pow (Math.Tan (lat), 4));
var XII = XIIa * XIIb;
var XIIa = MathEx.Secant(lat) / (120 * Math.Pow(v, 5));
var XIIb = 5 + (28 * Math.Pow(Math.Tan(lat), 2)) + (24 * Math.Pow(Math.Tan(lat), 4));
var XII = XIIa * XIIb;
var XIIAa = MathEx.Secant (lat) / (5040 * Math.Pow (v, 7));
var XIIAb = 61 + (662 * Math.Pow (Math.Tan (lat), 2)) + (1320 * Math.Pow (Math.Tan (lat), 4)) + (720 * Math.Pow (Math.Tan (lat), 6));
var XIIA = XIIAa * XIIAb;
var XIIAa = MathEx.Secant(lat) / (5040 * Math.Pow(v, 7));
var XIIAb = 61 + (662 * Math.Pow(Math.Tan(lat), 2)) + (1320 * Math.Pow(Math.Tan(lat), 4)) + (720 * Math.Pow(Math.Tan(lat), 6));
var XIIA = XIIAa * XIIAb;
lat = lat - VII * Math.Pow (E - E0, 2) + VIII * Math.Pow (E - E0, 4) - IX * Math.Pow (E - E0, 6);
var lon = lon0 + X * (E - E0) - XI * Math.Pow (E - E0, 3) + XII * Math.Pow (E - E0, 5) - XIIA * Math.Pow (E - E0, 7);
lat = lat - VII * Math.Pow(E - E0, 2) + VIII * Math.Pow(E - E0, 4) - IX * Math.Pow(E - E0, 6);
var lon = lon0 + X * (E - E0) - XI * Math.Pow(E - E0, 3) + XII * Math.Pow(E - E0, 5) - XIIA * Math.Pow(E - E0, 7);
/*
/*
Console.WriteLine ("v: {0}", v);
Console.WriteLine ("p: {0}", p);
Console.WriteLine ("n2: {0}", n2);
@@ -119,267 +117,267 @@ namespace GeoUK
Console.WriteLine ("lon: {0}", lon);
*/
return new LatitudeLongitude (ToDegrees (lat), ToDegrees (lon));
return new LatitudeLongitude(ToDegrees(lat), ToDegrees(lon));
}
private static bool IsNearlyZero(double x, double tolerance)
{
if (x < 0)
{
x = x * -1;
}
}
return (x < 0 && x > tolerance * -1) || (x >= 0 && x < tolerance);
}
private static bool IsNearlyZero (double x, double tolerance)
{
if (x < 0) {
x = x * -1;
}
private static double CalculateM(double latitude, double latitudeOrigin, double semiMajorAxis, double semiMinorAxis, double scaleFactor)
{
double n = (semiMajorAxis - semiMinorAxis) / (semiMajorAxis + semiMinorAxis);
return (x < 0 && x > tolerance * -1) || (x >= 0 && x < tolerance);
double Ma = (1 + n + ((5.0 / 4.0) * Math.Pow(n, 2)) + ((5.0 / 4.0) * Math.Pow(n, 3))) * (latitude - latitudeOrigin);
double Mb = ((3 * n) + (3 * Math.Pow(n, 2)) + ((21.0 / 8.0) * Math.Pow(n, 3))) * Math.Sin(latitude - latitudeOrigin) * Math.Cos(latitude + latitudeOrigin);
double Mc = (((15.0 / 8.0) * Math.Pow(n, 2)) + (15.0 / 8.0) * Math.Pow(n, 3)) * Math.Sin(2 * (latitude - latitudeOrigin)) * Math.Cos(2 * (latitude + latitudeOrigin));
double Md = (35.0 / 24.0 * Math.Pow(n, 3)) * Math.Sin(3 * (latitude - latitudeOrigin)) * Math.Cos(3 * (latitude + latitudeOrigin));
double M = semiMinorAxis * scaleFactor * (Ma - Mb + Mc - Md);
}
return M;
}
private static double CalculateM (double latitude, double latitudeOrigin, double semiMajorAxis, double semiMinorAxis, double scaleFactor)
{
double n = (semiMajorAxis - semiMinorAxis) / (semiMajorAxis + semiMinorAxis);
/// <summary>
/// Converts decimal degrees to radians.
/// </summary>
/// <param name="degrees"></param>
/// <returns></returns>
public static double ToRadians(double degrees)
{
return degrees * (Math.PI / 180);
}
double Ma = (1 + n + ((5.0 / 4.0) * Math.Pow (n, 2)) + ((5.0 / 4.0) * Math.Pow (n, 3))) * (latitude - latitudeOrigin);
double Mb = ((3 * n) + (3 * Math.Pow (n, 2)) + ((21.0 / 8.0) * Math.Pow (n, 3))) * Math.Sin (latitude - latitudeOrigin) * Math.Cos (latitude + latitudeOrigin);
double Mc = (((15.0 / 8.0) * Math.Pow (n, 2)) + (15.0 / 8.0) * Math.Pow (n, 3)) * Math.Sin (2 * (latitude - latitudeOrigin)) * Math.Cos (2 * (latitude + latitudeOrigin));
double Md = (35.0 / 24.0 * Math.Pow (n, 3)) * Math.Sin (3 * (latitude - latitudeOrigin)) * Math.Cos (3 * (latitude + latitudeOrigin));
double M = semiMinorAxis * scaleFactor * (Ma - Mb + Mc - Md);
/// <summary>
/// Converts radians to decimal degrees.
/// </summary>
/// <param name="radians"></param>
/// <returns></returns>
public static double ToDegrees(double radians)
{
return radians * (180 / Math.PI);
}
return M;
}
/// <summary>
/// Converts cartesian coordinates to grid eastings and northings for any Transverse Mercator map projection, including the Ordnance Survey National Grid.
/// Ellipsoid height is ignored.
/// </summary>
/// <remarks>
/// When converting OSGB36 coordinates between (easting, northing) and (latitude, longitude),
/// use the Airy 1830 ellipsoid. When converting ETRS89 coordinates between (easting, northing) and
/// (latitude, longitude), use the GRS80 ellipsoid. Use the same National Grid projection
/// constants for both ETRS89 and OSGB36 coordinates.
/// </remarks>
public static EastingNorthing ToEastingNorthing(Ellipsoid ellipsoid, Projections.Projection projection, Cartesian coordinates)
{
LatitudeLongitude coords = ToLatitudeLongitude(ellipsoid, coordinates);
return ToEastingNorthing(ellipsoid, projection, coords);
}
/// <summary>
/// Converts latitude and longitude to grid eastings and northings for any Transverse Mercator map projection, including the Ordnance Survey National Grid.
/// Ellipsoid height is ignored.
/// </summary>
/// <remarks>
/// When converting OSGB36 coordinates between (easting, northing) and (latitude, longitude),
/// use the Airy 1830 ellipsoid. When converting ETRS89 coordinates between (easting, northing) and
/// (latitude, longitude), use the GRS80 ellipsoid. Use the same National Grid projection
/// constants for both ETRS89 and OSGB36 coordinates.
/// </remarks>
/// <param name="ellipsoid"></param>
/// <param name="projection"></param>
/// <param name="coordinates"></param>
/// <returns></returns>
public static EastingNorthing ToEastingNorthing(Ellipsoid ellipsoid, Projections.Projection projection, LatitudeLongitude coordinates)
{
double lat = ToRadians(coordinates.Latitude);
double lon = ToRadians(coordinates.Longitude);
/// <summary>
/// Converts decimal degrees to radians.
/// </summary>
/// <param name="degrees"></param>
/// <returns></returns>
public static double ToRadians (double degrees)
{
return degrees * (Math.PI / 180);
}
//OS Document Transformation and OSGM02 User Guide, Appendix B.
//B1
double a = ellipsoid.SemiMajorAxis;
double b = ellipsoid.SemiMinorAxis;
double e2 = ellipsoid.EccentricitySquared;
double F0 = projection.ScaleFactor;
double lat0 = ToRadians(projection.TrueOriginLatitude);
double lon0 = ToRadians(projection.TrueOriginLongitude);
double E0 = projection.TrueOriginEasting;
double N0 = projection.TrueOriginNorthing;
/// <summary>
/// Converts radians to decimal degrees.
/// </summary>
/// <param name="radians"></param>
/// <returns></returns>
public static double ToDegrees (double radians)
{
return radians * (180 / Math.PI);
}
//B2
//double n = (a - b) / (a + b);
/// <summary>
/// Converts cartesian coordinates to grid eastings and northings for any Transverse Mercator map projection, including the Ordnance Survey National Grid.
/// Ellipsoid height is ignored.
/// </summary>
/// <remarks>
/// When converting OSGB36 coordinates between (easting, northing) and (latitude, longitude),
/// use the Airy 1830 ellipsoid. When converting ETRS89 coordinates between (easting, northing) and
/// (latitude, longitude), use the GRS80 ellipsoid. Use the same National Grid projection
/// constants for both ETRS89 and OSGB36 coordinates.
/// </remarks>
public static EastingNorthing ToEastingNorthing (Ellipsoid ellipsoid, Projections.Projection projection, Cartesian coordinates)
{
LatitudeLongitude coords = ToLatitudeLongitude (ellipsoid, coordinates);
return ToEastingNorthing (ellipsoid, projection, coords);
}
//B3
double v = a * F0 * Math.Pow((1 - e2 * Math.Pow(Math.Sin(lat), 2)), -0.5);
/// <summary>
/// Converts latitude and longitude to grid eastings and northings for any Transverse Mercator map projection, including the Ordnance Survey National Grid.
/// Ellipsoid height is ignored.
/// </summary>
/// <remarks>
/// When converting OSGB36 coordinates between (easting, northing) and (latitude, longitude),
/// use the Airy 1830 ellipsoid. When converting ETRS89 coordinates between (easting, northing) and
/// (latitude, longitude), use the GRS80 ellipsoid. Use the same National Grid projection
/// constants for both ETRS89 and OSGB36 coordinates.
/// </remarks>
/// <param name="ellipsoid"></param>
/// <param name="projection"></param>
/// <param name="coordinates"></param>
/// <returns></returns>
public static EastingNorthing ToEastingNorthing (Ellipsoid ellipsoid, Projections.Projection projection, LatitudeLongitude coordinates)
{
double lat = ToRadians (coordinates.Latitude);
double lon = ToRadians (coordinates.Longitude);
//B4
double p = a * F0 * (1 - e2) * Math.Pow((1 - e2 * Math.Pow(Math.Sin(lat), 2)), -1.5);
//OS Document Transformation and OSGM02 User Guide, Appendix B.
//B1
double a = ellipsoid.SemiMajorAxis;
double b = ellipsoid.SemiMinorAxis;
double e2 = ellipsoid.EccentricitySquared;
double F0 = projection.ScaleFactor;
double lat0 = ToRadians (projection.TrueOriginLatitude);
double lon0 = ToRadians (projection.TrueOriginLongitude);
double E0 = projection.TrueOriginEasting;
double N0 = projection.TrueOriginNorthing;
//B2
//double n = (a - b) / (a + b);
//B5
double n2 = v / p - 1;
//B3
double v = a * F0 * Math.Pow ((1 - e2 * Math.Pow (Math.Sin (lat), 2)), -0.5);
//B6
var M = CalculateM(lat, lat0, a, b, F0);
//B4
double p = a * F0 * (1 - e2) * Math.Pow ((1 - e2 * Math.Pow (Math.Sin (lat), 2)), -1.5);
// double Ma = (1 + n + ((5.0 / 4.0) * Math.Pow (n, 2)) + ((5.0 / 4.0) * Math.Pow (n, 3))) * (lat - lat0);
// double Mb = ((3 * n) + (3 * Math.Pow (n, 2)) + ((21.0 / 8.0) * Math.Pow (n, 3))) * Math.Sin (lat - lat0) * Math.Cos (lat + lat0);
// double Mc = (((15.0 / 8.0) * Math.Pow (n, 2)) + (15.0 / 8.0) * Math.Pow (n, 3)) * Math.Sin (2 * (lat - lat0)) * Math.Cos (2 * (lat + lat0));
// double Md = (35.0 / 24.0 * Math.Pow (n, 3)) * Math.Sin (3 * (lat - lat0)) * Math.Cos (3 * (lat + lat0));
// double M = b * F0 * (Ma - Mb + Mc - Md);
//B5
double n2 = v / p - 1;
double I = M + N0;
double II = (v / 2) * Math.Sin(lat) * Math.Cos(lat);
double III = (v / 24) * Math.Sin(lat) * Math.Pow(Math.Cos(lat), 3) * (5 - Math.Pow(Math.Tan(lat), 2) + 9 * n2);
double IIIA = (v / 720) * Math.Sin(lat) * Math.Pow(Math.Cos(lat), 5) * (61 - 58 * Math.Pow(Math.Tan(lat), 2) + Math.Pow(Math.Tan(lat), 4));
double IV = v * Math.Cos(lat);
double V = (v / 6) * Math.Pow(Math.Cos(lat), 3) * ((v / p) - Math.Pow(Math.Tan(lat), 2));
double VI = (v / 120) * Math.Pow(Math.Cos(lat), 5) * (5 - 18 * Math.Pow(Math.Tan(lat), 2) + Math.Pow(Math.Tan(lat), 4) + 14 * n2 - 58 * Math.Pow(Math.Tan(lat), 2) * n2);
//B6
var M = CalculateM (lat, lat0, a, b, F0);
//B7
double N = I + (II * Math.Pow((lon - lon0), 2)) + (III * Math.Pow((lon - lon0), 4)) + (IIIA * Math.Pow((lon - lon0), 6));
// double Ma = (1 + n + ((5.0 / 4.0) * Math.Pow (n, 2)) + ((5.0 / 4.0) * Math.Pow (n, 3))) * (lat - lat0);
// double Mb = ((3 * n) + (3 * Math.Pow (n, 2)) + ((21.0 / 8.0) * Math.Pow (n, 3))) * Math.Sin (lat - lat0) * Math.Cos (lat + lat0);
// double Mc = (((15.0 / 8.0) * Math.Pow (n, 2)) + (15.0 / 8.0) * Math.Pow (n, 3)) * Math.Sin (2 * (lat - lat0)) * Math.Cos (2 * (lat + lat0));
// double Md = (35.0 / 24.0 * Math.Pow (n, 3)) * Math.Sin (3 * (lat - lat0)) * Math.Cos (3 * (lat + lat0));
// double M = b * F0 * (Ma - Mb + Mc - Md);
//B8
double E = E0 + (IV * (lon - lon0)) + (V * Math.Pow((lon - lon0), 3)) + (VI * Math.Pow((lon - lon0), 5));
double I = M + N0;
double II = (v / 2) * Math.Sin (lat) * Math.Cos (lat);
double III = (v / 24) * Math.Sin (lat) * Math.Pow (Math.Cos (lat), 3) * (5 - Math.Pow (Math.Tan (lat), 2) + 9 * n2);
double IIIA = (v / 720) * Math.Sin (lat) * Math.Pow (Math.Cos (lat), 5) * (61 - 58 * Math.Pow (Math.Tan (lat), 2) + Math.Pow (Math.Tan (lat), 4));
double IV = v * Math.Cos (lat);
double V = (v / 6) * Math.Pow (Math.Cos (lat), 3) * ((v / p) - Math.Pow (Math.Tan (lat), 2));
double VI = (v / 120) * Math.Pow (Math.Cos (lat), 5) * (5 - 18 * Math.Pow (Math.Tan (lat), 2) + Math.Pow (Math.Tan (lat), 4) + 14 * n2 - 58 * Math.Pow (Math.Tan (lat), 2) * n2);
return new EastingNorthing(E, N, coordinates.ElipsoidalHeight); //height is still with respect to the ellipsoid
}
//B7
double N = I + (II * Math.Pow ((lon - lon0), 2)) + (III * Math.Pow ((lon - lon0), 4)) + (IIIA * Math.Pow ((lon - lon0), 6));
public static Cartesian ToCartesian(Ellipsoid ellipsoid, Projection projection, EastingNorthing coordinates)
{
var latLongCoordinates = ToLatitudeLongitude(
ellipsoid,
projection,
coordinates);
//B8
double E = E0 + (IV * (lon - lon0)) + (V * Math.Pow ((lon - lon0), 3)) + (VI * Math.Pow ((lon - lon0), 5));
return ToCartesian(ellipsoid, latLongCoordinates);
}
return new EastingNorthing (E, N, coordinates.ElipsoidalHeight); //height is still with respect to the ellipsoid
}
/// <summary>
/// Converts latitude, longitude and elipsoidal height coordinates to cartesian coordinates using the same ellipsoid.
/// Please note this is not a transformation between ellipsoids.
/// </summary>
/// <param name="ellipsoid"></param>
/// <param name="coordinates"></param>
/// <returns></returns>
public static Cartesian ToCartesian(Ellipsoid ellipsoid, LatitudeLongitude coordinates)
{
double lat = ToRadians(coordinates.Latitude);
double lon = ToRadians(coordinates.Longitude);
double height = coordinates.ElipsoidalHeight;
public static Cartesian ToCartesian (Ellipsoid ellipsoid, Projection projection, EastingNorthing coordinates)
{
var latLongCoordinates = ToLatitudeLongitude (
ellipsoid,
projection,
coordinates);
return ToCartesian (ellipsoid, latLongCoordinates);
}
double e2 = ellipsoid.EccentricitySquared;
double a = ellipsoid.SemiMajorAxis;
/// <summary>
/// Converts latitude, longitude and elipsoidal height coordinates to cartesian coordinates using the same ellipsoid.
/// Please note this is not a transformation between ellipsoids.
/// </summary>
/// <param name="ellipsoid"></param>
/// <param name="coordinates"></param>
/// <returns></returns>
public static Cartesian ToCartesian (Ellipsoid ellipsoid, LatitudeLongitude coordinates)
{
double v = a / Math.Sqrt(1 - (e2 * Math.Pow(Math.Sin(lat), 2)));
double lat = ToRadians (coordinates.Latitude);
double lon = ToRadians (coordinates.Longitude);
double height = coordinates.ElipsoidalHeight;
double x = (v + height) * Math.Cos(lat) * Math.Cos(lon);
double y = (v + height) * Math.Cos(lat) * Math.Sin(lon);
double z = ((1 - e2) * v + height) * Math.Sin(lat);
double e2 = ellipsoid.EccentricitySquared;
double a = ellipsoid.SemiMajorAxis;
return new Cartesian(x, y, z);
}
double v = a / Math.Sqrt (1 - (e2 * Math.Pow (Math.Sin (lat), 2)));
/// <summary>
/// Converts cartesian coordinates to latitude, longitude and elipsoidal height using the same ellipsoid.
/// Please note this is not a transformation between ellipsoids.
/// </summary>
/// <param name="ellipsoid"></param>
/// <param name="coordinates"></param>
/// <returns></returns>
public static LatitudeLongitude ToLatitudeLongitude(Ellipsoid ellipsoid, Cartesian coordinates)
{
double e2 = ellipsoid.EccentricitySquared;
double a = ellipsoid.SemiMajorAxis;
double p = Math.Sqrt(Math.Pow(coordinates.X, 2) + Math.Pow(coordinates.Y, 2));
double lon = Math.Atan(coordinates.Y / coordinates.X);
double x = (v + height) * Math.Cos (lat) * Math.Cos (lon);
double y = (v + height) * Math.Cos (lat) * Math.Sin (lon);
double z = ((1 - e2) * v + height) * Math.Sin (lat);
//have a first stab
double v = 0.0;
double lat = Math.Atan(coordinates.Z / (p * (1 - e2)));
return new Cartesian (x, y, z);
}
//iterate a few times 3 is enough but 10 to be safe
for (int iterations = 0; iterations < 10; iterations++)
{
v = a / Math.Sqrt(1 - (e2 * Math.Pow(Math.Sin(lat), 2)));
lat = Math.Atan((coordinates.Z + e2 * v * Math.Sin(lat)) / p);
}
double height = (p / Math.Cos(lat)) - v;
/// <summary>
/// Converts cartesian coordinates to latitude, longitude and elipsoidal height using the same ellipsoid.
/// Please note this is not a transformation between ellipsoids.
/// </summary>
/// <param name="ellipsoid"></param>
/// <param name="coordinates"></param>
/// <returns></returns>
public static LatitudeLongitude ToLatitudeLongitude (Ellipsoid ellipsoid, Cartesian coordinates)
{
double e2 = ellipsoid.EccentricitySquared;
double a = ellipsoid.SemiMajorAxis;
double p = Math.Sqrt (Math.Pow (coordinates.X, 2) + Math.Pow (coordinates.Y, 2));
double lon = Math.Atan (coordinates.Y / coordinates.X);
return new LatitudeLongitude(ToDegrees(lat), ToDegrees(lon), height);
}
//have a first stab
double v = 0.0;
double lat = Math.Atan (coordinates.Z / (p * (1 - e2)));
//iterate a few times 3 is enough but 10 to be safe
for (int iterations = 0; iterations < 10; iterations++) {
v = a / Math.Sqrt (1 - (e2 * Math.Pow (Math.Sin (lat), 2)));
lat = Math.Atan ((coordinates.Z + e2 * v * Math.Sin (lat)) / p);
}
double height = (p / Math.Cos (lat)) - v;
/// <summary>
/// Converts degrees minutes and seconds to decimal degrees.
/// </summary>
/// <param name="degrees"></param>
/// <param name="minutes"></param>
/// <param name="seconds"></param>
/// <returns></returns>
public static double ToDecimelDegrees(int degrees, int minutes, double seconds)
{
//determine seconds as minutes
double m = minutes + (seconds / 60.0);
return ToDecimelDegrees(degrees, m);
}
return new LatitudeLongitude (ToDegrees (lat), ToDegrees (lon), height);
}
/// <summary>
/// Converts degrees and decimel minutes to decimal degrees.
/// </summary>
/// <param name="degrees"></param>
/// <param name="minutes"></param>
/// <returns></returns>
public static double ToDecimelDegrees(int degrees, double minutes)
{
//determine minutes as derees
return degrees + (minutes / 60.0);
}
/// <summary>
/// Converts degrees minutes and seconds to decimal degrees.
/// </summary>
/// <param name="degrees"></param>
/// <param name="minutes"></param>
/// <param name="seconds"></param>
/// <returns></returns>
public static double ToDecimelDegrees (int degrees, int minutes, double seconds)
{
//determine seconds as minutes
double m = minutes + (seconds / 60.0);
return ToDecimelDegrees (degrees, m);
}
private static double Div(double value, double divisor)
{
double dblResult = 0;
bool blnNegative = false;
/// <summary>
/// Converts degrees and decimel minutes to decimal degrees.
/// </summary>
/// <param name="degrees"></param>
/// <param name="minutes"></param>
/// <returns></returns>
public static double ToDecimelDegrees (int degrees, double minutes)
{
//determine minutes as derees
return degrees + (minutes / 60.0);
}
//make the division
dblResult = value / divisor;
private static double Div (double value, double divisor)
{
double dblResult = 0;
bool blnNegative = false;
//do all calculations on positive numbers
if (dblResult < 0)
{
blnNegative = true;
dblResult = dblResult * -1;
}
//make the division
dblResult = value / divisor;
//see if there is any remainder
if (dblResult % 1 > 0)
{
dblResult = Math.Ceiling(dblResult) - 1;
}
else
{
dblResult = System.Convert.ToInt32(dblResult, CultureInfo.InvariantCulture);
}
//do all calculations on positive numbers
if (dblResult < 0) {
blnNegative = true;
dblResult = dblResult * -1;
}
if (blnNegative)
{
dblResult = Negate(dblResult);
}
//see if there is any remainder
if (dblResult % 1 > 0) {
dblResult = Math.Ceiling (dblResult) - 1;
} else {
dblResult = System.Convert.ToInt32 (dblResult, CultureInfo.InvariantCulture);
}
return dblResult;
}
if (blnNegative) {
dblResult = Negate (dblResult);
}
return dblResult;
}
/// <summary>
/// Helper funtion to reverse the sign of a value. Helps code to be more readable.
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
private static double Negate (double value)
{
return value * -1.0;
}
}
/// <summary>
/// Helper funtion to reverse the sign of a value. Helps code to be more readable.
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
private static double Negate(double value)
{
return value * -1.0;
}
}
}

View File

@@ -1,7 +1,3 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace GeoUK.Coordinates
{
/// <summary>
@@ -25,6 +21,7 @@ namespace GeoUK.Coordinates
_y = y;
_z = z;
}
/// <summary>
/// Returns the X axis parameter.
/// </summary>
@@ -32,6 +29,7 @@ namespace GeoUK.Coordinates
{
get { return _x; }
}
/// <summary>
/// Returns the Y axis parameter.
/// </summary>
@@ -39,6 +37,7 @@ namespace GeoUK.Coordinates
{
get { return _y; }
}
/// <summary>
/// Returns the Z axis parameter.
/// </summary>
@@ -46,6 +45,5 @@ namespace GeoUK.Coordinates
{
get { return _z; }
}
}
}
}

View File

@@ -1,7 +1,3 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace GeoUK.Coordinates
{
/// <summary>
@@ -10,9 +6,10 @@ namespace GeoUK.Coordinates
/// </summary>
public class EastingNorthing
{
double _easting;
double _northing;
double _height;
private double _easting;
private double _northing;
private double _height;
/// <summary>
/// Constructor.
/// </summary>
@@ -24,6 +21,7 @@ namespace GeoUK.Coordinates
_northing = northing;
_height = 0;
}
/// <summary>
/// Constructor.
/// </summary>
@@ -36,6 +34,7 @@ namespace GeoUK.Coordinates
_northing = northing;
_height = height;
}
/// <summary>
/// Retruns the easting parameter.
/// </summary>
@@ -43,6 +42,7 @@ namespace GeoUK.Coordinates
{
get { return _easting; }
}
/// <summary>
/// returns the northing parameter.
/// </summary>
@@ -50,6 +50,7 @@ namespace GeoUK.Coordinates
{
get { return _northing; }
}
/// <summary>
/// Returns the height parameter.
/// </summary>
@@ -58,4 +59,4 @@ namespace GeoUK.Coordinates
get { return _height; }
}
}
}
}

View File

@@ -1,7 +1,3 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace GeoUK.Coordinates
{
/// <summary>
@@ -13,61 +9,75 @@ namespace GeoUK.Coordinates
/// Outside Model Boundary
/// </summary>
OutsideModelBoundary = 0,
/// <summary>
/// Newlyn, Uk Mainland
/// </summary>
NewlynUkMainland = 1,
/// <summary>
/// StMarys, Scilly Isles
/// </summary>
StMarysScillyIsles = 2,
/// <summary>
/// Douglas02, Isle of Man
/// </summary>
Douglas02IsleofMan = 3,
/// <summary>
/// Stornoway, Outer Hebrides
/// </summary>
StornowayOuterHebrides = 4,
/// <summary>
/// St. Kilda, St. Kilda
/// </summary>
StKildaStKilda = 5,
/// <summary>
/// Lerwick, Shetland Isles
/// </summary>
LerwickShetlandIsles = 6,
/// <summary>
/// Newlyn, Orkney Isles
/// </summary>
NewlynOrkneyIsles = 7,
/// <summary>
/// Fair Isle, Fair Isle
/// </summary>
FairIsleFairIsle = 8,
/// <summary>
/// Flannan Isles, Flannan Isles
/// </summary>
FlannanIslesFlannanIsles = 9,
/// <summary>
/// North Rona, North Rona
/// </summary>
NorthRonaNorthRona = 10,
/// <summary>
/// Sule Skerry, Sule Skerry
/// </summary>
SuleSkerrySuleSkerry = 11,
/// <summary>
/// Foula, Foula.
/// </summary>
FoulaFoula = 12,
/// <summary>
/// Malin Head, Republic of Ireland
/// </summary>
MalinHeadRepublicofIreland = 13,
/// <summary>
/// Belfast, Northern Ireland
/// </summary>
BelfastNorthernIreland = 14
}
}
}

View File

@@ -1,16 +1,15 @@
using System;
namespace GeoUK.Coordinates
{
/// <summary>
/// <summary>
/// This immutable class represents a set of latitude/longitude/ellipsoidal height coordinates.
/// </summary>
public class LatitudeLongitude
public class LatitudeLongitude
{
{
private double _degreesLatitude = 0.0;
private double _degreesLongitude = 0.0;
private double _elipsoidalHeight = 0.0;
/// <summary>
/// Constructor.
/// </summary>
@@ -22,38 +21,42 @@ namespace GeoUK.Coordinates
_degreesLongitude = degreesLongitude;
_elipsoidalHeight = 0.0;
}
/// <summary>
/// <summary>
/// Constructor.
/// </summary>
/// <param name="degreesLatitude"></param>
/// <param name="degreesLongitude"></param>
/// <param name="elipsoidalHeight"></param>
public LatitudeLongitude(double degreesLatitude, double degreesLongitude, double elipsoidalHeight)
{
{
_degreesLatitude = degreesLatitude;
_degreesLongitude = degreesLongitude;
_elipsoidalHeight = elipsoidalHeight;
}
/// <summary>
/// Returns latitude in degrees.
/// </summary>
public double Latitude
{
get
{
{
get
{
return _degreesLatitude;
}
}
}
}
/// <summary>
/// Returns longitude in degrees.
/// </summary>
public double Longitude
{
get
{
{
get
{
return _degreesLongitude;
}
}
}
}
/// <summary>
/// returns elipsoidal height in meters.
/// </summary>
@@ -65,4 +68,4 @@ namespace GeoUK.Coordinates
}
}
}
}
}

View File

@@ -1,11 +1,9 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace GeoUK.Coordinates
{
/// <summary>
/// This immutable class, derived from EastingNorthingCoordinates, provides a convenient means
/// This immutable class, derived from EastingNorthingCoordinates, provides a convenient means
/// to represent OSGB36 eastings and northings.
/// </summary>
/// <remarks>
@@ -14,47 +12,47 @@ namespace GeoUK.Coordinates
/// </remarks>
public class Osgb36 : EastingNorthing
{
Osgb36GeoidDatum _datum = Osgb36GeoidDatum.OutsideModelBoundary;
private Osgb36GeoidDatum _datum = Osgb36GeoidDatum.OutsideModelBoundary;
/// <summary>
/// Initializes a new instance of the <see cref="GeoUK.Coordinates.Osgb36Cordinates"/> class.
/// </summary>
/// <param name="easting">Easting.</param>
/// <param name="northing">Northing.</param>
public Osgb36(double easting, double northing)
: base(easting, northing, 0)
{
_datum = Osgb36GeoidDatum.NewlynUkMainland;
}
/// <summary>
/// Initializes a new instance of the <see cref="GeoUK.Coordinates.Osgb36Cordinates"/> class.
/// </summary>
/// <param name="easting">Easting.</param>
/// <param name="northing">Northing.</param>
public Osgb36(double easting, double northing)
: base(easting, northing, 0)
{
_datum = Osgb36GeoidDatum.NewlynUkMainland;
}
/// <summary>
/// Initializes a new instance of the <see cref="GeoUK.Coordinates.Osgb36Cordinates"/> class.
/// </summary>
/// <param name="eastingNorthingCoordinates">Easting northing coordinates.</param>
public Osgb36(EastingNorthing eastingNorthingCoordinates)
: base(eastingNorthingCoordinates.Easting, eastingNorthingCoordinates.Northing, eastingNorthingCoordinates.Height)
{
_datum = Osgb36GeoidDatum.NewlynUkMainland;
}
/// <summary>
/// Initializes a new instance of the <see cref="GeoUK.Coordinates.Osgb36Cordinates"/> class.
/// </summary>
/// <param name="eastingNorthingCoordinates">Easting northing coordinates.</param>
public Osgb36(EastingNorthing eastingNorthingCoordinates)
: base(eastingNorthingCoordinates.Easting, eastingNorthingCoordinates.Northing, eastingNorthingCoordinates.Height)
{
_datum = Osgb36GeoidDatum.NewlynUkMainland;
}
/// <summary>
/// Initializes a new instance of the <see cref="GeoUK.Coordinates.Osgb36Cordinates"/> class.
/// </summary>
/// <param name="eastingNorthingCoordinates">Easting northing coordinates.</param>
/// <param name="datum">Datum.</param>
public Osgb36(EastingNorthing eastingNorthingCoordinates, Osgb36GeoidDatum datum)
: base(eastingNorthingCoordinates.Easting, eastingNorthingCoordinates.Northing, eastingNorthingCoordinates.Height)
{
_datum = datum;
}
/// <summary>
/// Initializes a new instance of the <see cref="GeoUK.Coordinates.Osgb36Cordinates"/> class.
/// </summary>
/// <param name="eastingNorthingCoordinates">Easting northing coordinates.</param>
/// <param name="datum">Datum.</param>
public Osgb36(EastingNorthing eastingNorthingCoordinates, Osgb36GeoidDatum datum)
: base(eastingNorthingCoordinates.Easting, eastingNorthingCoordinates.Northing, eastingNorthingCoordinates.Height)
{
_datum = datum;
}
/// <summary>
/// Initializes a new instance of the <see cref="GeoUK.Coordinates.Osgb36Cordinates"/> class.
/// </summary>
/// <param name="easting">Easting.</param>
/// <param name="northing">Northing.</param>
/// <param name="height">Height.</param>
/// <param name="datum">Datum.</param>
/// <summary>
/// Initializes a new instance of the <see cref="GeoUK.Coordinates.Osgb36Cordinates"/> class.
/// </summary>
/// <param name="easting">Easting.</param>
/// <param name="northing">Northing.</param>
/// <param name="height">Height.</param>
/// <param name="datum">Datum.</param>
public Osgb36(double easting, double northing, double height, Osgb36GeoidDatum datum)
: base(easting, northing, height)
{
@@ -62,7 +60,7 @@ namespace GeoUK.Coordinates
}
/// <summary>
/// Returns the Local Geoid datum in use. other property values should be
/// Returns the Local Geoid datum in use. other property values should be
/// considered invalid if this property is set to OutsideModelBoundary.
/// </summary>
public Osgb36GeoidDatum RegionGeoidDatum
@@ -70,76 +68,74 @@ namespace GeoUK.Coordinates
get { return _datum; }
}
public string MapReference {
get {
/*
public string MapReference
{
get
{
/*
10km (2-figure) Grid Reference: SO84 = 380000 Easting 240000 Northing
1km (4-figure) Grid Reference: NS2468 = 224000 Easting 668000 Northing
100m (6-figure) Grid Reference: TL123456 = 512300 Easting 245600 Northing
*/
var easting = this.Easting;
var northing = this.Northing;
var easting = this.Easting;
var northing = this.Northing;
var bngSquare = GetBngSquare (easting, northing);
var bngSquare = GetBngSquare(easting, northing);
//get the number of complete 500k squares
var indexNorthing = (int)Math.Floor (northing / 500000);
var indexEasting = (int)Math.Floor (easting / 500000);
//get the number of complete 500k squares
var indexNorthing = (int)Math.Floor(northing / 500000);
var indexEasting = (int)Math.Floor(easting / 500000);
//reduce E and N by the number of 500k squares
northing = northing - indexNorthing * 500000;
easting = easting - indexEasting * 500000;
//reduce E and N by the number of 500k squares
northing = northing - indexNorthing * 500000;
easting = easting - indexEasting * 500000;
//reduce by the number of 100k squares within the 500k square.
indexNorthing = (int)Math.Floor (northing) / 100000;
indexEasting = (int)Math.Floor (easting) / 100000;
//reduce by the number of 100k squares within the 500k square.
indexNorthing = (int)Math.Floor(northing) / 100000;
indexEasting = (int)Math.Floor(easting) / 100000;
northing = northing - indexNorthing * 100000;
easting = easting - indexEasting * 100000;
northing = northing - indexNorthing * 100000;
easting = easting - indexEasting * 100000;
northing = Math.Round (northing / 100);
easting = Math.Round (easting / 100);
return string.Format ("{0}{1}{2}", bngSquare, Math.Round (easting).ToString("000"), Math.Round (northing).ToString ("000"));
}
}
northing = Math.Round(northing / 100);
easting = Math.Round(easting / 100);
return string.Format("{0}{1}{2}", bngSquare, Math.Round(easting).ToString("000"), Math.Round(northing).ToString("000"));
}
}
/// <summary>
/// Returns the two letter OS code based on easting and northing in metres.
/// </summary>
/// <returns>The square with northing.</returns>
/// <param name="northing">Northing.</param>
/// <param name="easting">Easting.</param>
public static string GetBngSquare(double easting, double northing)
{
var result = string.Empty;
/// <summary>
/// Returns the two letter OS code based on easting and northing in metres.
/// </summary>
/// <returns>The square with northing.</returns>
/// <param name="northing">Northing.</param>
/// <param name="easting">Easting.</param>
public static string GetBngSquare(double easting, double northing)
{
var result = string.Empty;
//test for our upper and lower limits
if (easting >=0 && easting < 700000 && northing >=0 && northing < 1300000)
{
//test for our upper and lower limits
if (easting >= 0 && easting < 700000 && northing >= 0 && northing < 1300000)
{
var firstChar = new char[6] { 'S', 'N', 'H', 'T', 'O', 'J' };
var secondChar = new char[25] { 'V', 'Q', 'L', 'F', 'A', 'W', 'R', 'M', 'G', 'B', 'X', 'S', 'N', 'H', 'C', 'Y', 'T', 'O', 'J', 'D', 'Z', 'U', 'P', 'K', 'E' };
var firstChar = new char[6] { 'S', 'N', 'H', 'T', 'O', 'J' };
var secondChar = new char[25] {'V', 'Q', 'L', 'F', 'A', 'W', 'R', 'M', 'G', 'B', 'X', 'S', 'N', 'H', 'C', 'Y', 'T', 'O', 'J', 'D', 'Z', 'U', 'P', 'K', 'E'};
//calculate the first letter
var indexNorthing = (int)Math.Floor(northing / 500000);
var indexEasting = (int)Math.Floor(easting / 500000);
//calculate the first letter
var indexNorthing = (int)Math.Floor(northing / 500000);
var indexEasting = (int)Math.Floor(easting / 500000);
//get the first char
var chr1 = firstChar[(indexEasting * 3) + indexNorthing];
//get the first char
var chr1 = firstChar[(indexEasting * 3) + indexNorthing];
//to get the second letter we subtract the number of 500km sectors calculated above
indexNorthing = (int)Math.Floor((northing - (indexNorthing * 500000)) / 100000);
indexEasting = (int)Math.Floor((easting - (indexEasting * 500000))/ 100000);
//get the second char
var chr2 = secondChar[(indexEasting * 5) + indexNorthing];
result = string.Format("{0}{1}", chr1, chr2);
}
return result;
}
//to get the second letter we subtract the number of 500km sectors calculated above
indexNorthing = (int)Math.Floor((northing - (indexNorthing * 500000)) / 100000);
indexEasting = (int)Math.Floor((easting - (indexEasting * 500000)) / 100000);
//get the second char
var chr2 = secondChar[(indexEasting * 5) + indexNorthing];
result = string.Format("{0}{1}", chr1, chr2);
}
return result;
}
}
}
}

View File

@@ -1,16 +1,12 @@
using System;
namespace GeoUK.Ellipsoids
{
/// <summary>
/// This immutable class, derived from Ellipsoid, represents an Airy1930 ellipsoid and is provided for convienience.
/// </summary>
public class Airy1830 : Ellipsoid
{
private const double C_SEMI_MAJOR_AXIS = 6377563.396; //a
private const double C_SEMI_MINOR_AXIS = 6356256.909; //b
{
private const double C_SEMI_MAJOR_AXIS = 6377563.396; //a
private const double C_SEMI_MINOR_AXIS = 6356256.909; //b
/// <summary>
/// Constructor.
@@ -19,7 +15,5 @@ namespace GeoUK.Ellipsoids
: base(C_SEMI_MAJOR_AXIS, C_SEMI_MINOR_AXIS)
{
}
}
}
}
}

View File

@@ -1,16 +1,12 @@
using System;
namespace GeoUK.Ellipsoids
{
/// <summary>
/// This immutable class, derived from Ellipsoid, represents an Airy1930 ellipsoid and is provided for convienience.
/// </summary>
public class Airy1830Modified : Ellipsoid
{
private const double C_SEMI_MAJOR_AXIS = 6377340.189; //a
private const double C_SEMI_MINOR_AXIS = 6356034.447; //b
{
private const double C_SEMI_MAJOR_AXIS = 6377340.189; //a
private const double C_SEMI_MINOR_AXIS = 6356034.447; //b
/// <summary>
/// Constructor.
@@ -19,7 +15,5 @@ namespace GeoUK.Ellipsoids
: base(C_SEMI_MAJOR_AXIS, C_SEMI_MINOR_AXIS)
{
}
}
}
}
}

View File

@@ -1,6 +1,4 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace GeoUK.Ellipsoids
{
@@ -9,12 +7,11 @@ namespace GeoUK.Ellipsoids
/// </summary>
public class Ellipsoid
{
private double _semiMajorAxis = 0.0;
private double _semiMinorAxis = 0.0;
private double _eccentricity = 0.0;
private double _eccentricitySquared = 0.0;
/// <summary>
/// Constructor.
/// </summary>
@@ -27,6 +24,7 @@ namespace GeoUK.Ellipsoids
_eccentricitySquared = (Math.Pow(semiMajorAxis, 2) - Math.Pow(semiMinorAxis, 2)) / Math.Pow(semiMajorAxis, 2);
_eccentricity = Math.Sqrt(_eccentricitySquared);
}
/// <summary>
/// Calculates the Radius of curvature for a given latitude.
/// </summary>
@@ -43,6 +41,7 @@ namespace GeoUK.Ellipsoids
//return (C_SEMI_MAJOR_AXIS / Math.Pow((1 - m_EccentricitySquared * Math.Pow(Math.Sin(dblRadians),2)), 0.5));
return _semiMajorAxis / Math.Pow((1 - _eccentricitySquared * Math.Pow(Math.Sin(dblRadians), 2)), 0.5);
}
/// <summary>
/// Returns the semi-major axis of the ellipsoid.
/// </summary>
@@ -53,6 +52,7 @@ namespace GeoUK.Ellipsoids
return _semiMajorAxis;
}
}
/// <summary>
/// Returns the semi-major axis of the ellipsoid.
/// </summary>
@@ -63,6 +63,7 @@ namespace GeoUK.Ellipsoids
return _semiMinorAxis;
}
}
/// <summary>
/// returns the eccentricity of the ellipsoid.
/// </summary>
@@ -73,6 +74,7 @@ namespace GeoUK.Ellipsoids
return _eccentricity;
}
}
/// <summary>
/// returns the eccentricity squared of the ellipsoid.
/// </summary>
@@ -83,6 +85,7 @@ namespace GeoUK.Ellipsoids
return _eccentricitySquared;
}
}
/// <summary>
/// returns the second eccentricity squared of the ellipsoid.
/// </summary>
@@ -93,6 +96,7 @@ namespace GeoUK.Ellipsoids
return (Math.Pow(_semiMajorAxis, 2) - Math.Pow(_semiMinorAxis, 2)) / Math.Pow(_semiMinorAxis, 2);
}
}
/// <summary>
/// Returns radians for a given value of degrees.
/// </summary>
@@ -102,6 +106,7 @@ namespace GeoUK.Ellipsoids
{
return degrees * (Math.PI / 180);
}
/// <summary>
/// Returns degrees for a given value of radians.
/// </summary>
@@ -112,4 +117,4 @@ namespace GeoUK.Ellipsoids
return radians * (180 / Math.PI);
}
}
}
}

View File

@@ -1,5 +1,3 @@
using System;
namespace GeoUK.Ellipsoids
{
/// <summary>
@@ -9,6 +7,7 @@ namespace GeoUK.Ellipsoids
{
//WGS constants
private const double C_SEMI_MAJOR_AXIS = 6378137; //a
private const double C_SEMI_MINOR_AXIS = 6356752.314; //b
/// <summary>
@@ -18,7 +17,5 @@ namespace GeoUK.Ellipsoids
: base(C_SEMI_MAJOR_AXIS, C_SEMI_MINOR_AXIS)
{
}
}
}
}

View File

@@ -1,21 +1,18 @@
using System;
namespace GeoUK.Ellipsoids
namespace GeoUK.Ellipsoids
{
public class Hayford1909 : Ellipsoid
{
//WGS constants
private const double C_SEMI_MAJOR_AXIS = 6378388; //a
private const double C_SEMI_MINOR_AXIS = 6356911.946; //b
public class Hayford1909 : Ellipsoid
{
//WGS constants
private const double C_SEMI_MAJOR_AXIS = 6378388; //a
/// <summary>
/// Constructor.
/// </summary>
public Hayford1909()
: base(C_SEMI_MAJOR_AXIS, C_SEMI_MINOR_AXIS)
{
}
}
}
private const double C_SEMI_MINOR_AXIS = 6356911.946; //b
/// <summary>
/// Constructor.
/// </summary>
public Hayford1909()
: base(C_SEMI_MAJOR_AXIS, C_SEMI_MINOR_AXIS)
{
}
}
}

View File

@@ -1,5 +1,3 @@
using System;
namespace GeoUK.Ellipsoids
{
/// <summary>
@@ -9,7 +7,9 @@ namespace GeoUK.Ellipsoids
{
//WGS constants
private const double C_SEMI_MAJOR_AXIS = 6378137; //a
private const double C_SEMI_MINOR_AXIS = 6356752.3141; //b
/// <summary>
/// Constructor.
/// </summary>
@@ -18,5 +18,4 @@ namespace GeoUK.Ellipsoids
{
}
}
}
}

View File

@@ -2,33 +2,32 @@
namespace GeoUK
{
public static class MathEx
{
public static double Secant(double x){
return 1 / Math.Cos(x);
}
// Cosecant Cosec(X) = 1 / Sin(X)
// Cotangent Cotan(X) = 1 / Tan(X)
// Inverse Sine Arcsin(X) = Atn(X / Sqr(-X * X + 1))
// Inverse Cosine Arccos(X) = Atn(-X / Sqr(-X * X + 1)) + 2 * Atn(1)
// Inverse Secant Arcsec(X) = 2 * Atn(1) - Atn(Sgn(X) / Sqr(X * X - 1))
// Inverse Cosecant Arccosec(X) = Atn(Sgn(X) / Sqr(X * X - 1))
// Inverse Cotangent Arccotan(X) = 2 * Atn(1) - Atn(X)
// Hyperbolic Sine HSin(X) = (Exp(X) - Exp(-X)) / 2
// Hyperbolic Cosine HCos(X) = (Exp(X) + Exp(-X)) / 2
// Hyperbolic Tangent HTan(X) = (Exp(X) - Exp(-X)) / (Exp(X) + Exp(-X))
// Hyperbolic Secant HSec(X) = 2 / (Exp(X) + Exp(-X))
// Hyperbolic Cosecant HCosec(X) = 2 / (Exp(X) - Exp(-X))
// Hyperbolic Cotangent HCotan(X) = (Exp(X) + Exp(-X)) / (Exp(X) - Exp(-X))
// Inverse Hyperbolic Sine HArcsin(X) = Log(X + Sqr(X * X + 1))
// Inverse Hyperbolic Cosine HArccos(X) = Log(X + Sqr(X * X - 1))
// Inverse Hyperbolic Tangent HArctan(X) = Log((1 + X) / (1 - X)) / 2
// Inverse Hyperbolic Secant HArcsec(X) = Log((Sqr(-X * X + 1) + 1) / X)
// Inverse Hyperbolic Cosecant HArccosec(X) = Log((Sgn(X) * Sqr(X * X + 1) + 1) / X)
// Inverse Hyperbolic Cotangent HArccotan(X) = Log((X + 1) / (X - 1)) / 2
// Logarithm to base N LogN(X) = Log(X) / Log(N)
}
}
public static class MathEx
{
public static double Secant(double x)
{
return 1 / Math.Cos(x);
}
// Cosecant Cosec(X) = 1 / Sin(X)
// Cotangent Cotan(X) = 1 / Tan(X)
// Inverse Sine Arcsin(X) = Atn(X / Sqr(-X * X + 1))
// Inverse Cosine Arccos(X) = Atn(-X / Sqr(-X * X + 1)) + 2 * Atn(1)
// Inverse Secant Arcsec(X) = 2 * Atn(1) - Atn(Sgn(X) / Sqr(X * X - 1))
// Inverse Cosecant Arccosec(X) = Atn(Sgn(X) / Sqr(X * X - 1))
// Inverse Cotangent Arccotan(X) = 2 * Atn(1) - Atn(X)
// Hyperbolic Sine HSin(X) = (Exp(X) - Exp(-X)) / 2
// Hyperbolic Cosine HCos(X) = (Exp(X) + Exp(-X)) / 2
// Hyperbolic Tangent HTan(X) = (Exp(X) - Exp(-X)) / (Exp(X) + Exp(-X))
// Hyperbolic Secant HSec(X) = 2 / (Exp(X) + Exp(-X))
// Hyperbolic Cosecant HCosec(X) = 2 / (Exp(X) - Exp(-X))
// Hyperbolic Cotangent HCotan(X) = (Exp(X) + Exp(-X)) / (Exp(X) - Exp(-X))
// Inverse Hyperbolic Sine HArcsin(X) = Log(X + Sqr(X * X + 1))
// Inverse Hyperbolic Cosine HArccos(X) = Log(X + Sqr(X * X - 1))
// Inverse Hyperbolic Tangent HArctan(X) = Log((1 + X) / (1 - X)) / 2
// Inverse Hyperbolic Secant HArcsec(X) = Log((Sqr(-X * X + 1) + 1) / X)
// Inverse Hyperbolic Cosecant HArccosec(X) = Log((Sgn(X) * Sqr(X * X + 1) + 1) / X)
// Inverse Hyperbolic Cotangent HArccotan(X) = Log((X + 1) / (X - 1)) / 2
// Logarithm to base N LogN(X) = Log(X) / Log(N)
}
}

View File

@@ -1,116 +1,116 @@
using System;
using GeoUK.Coordinates;
using System.IO;
using System.Collections.Generic;
using System.Reflection;
using GeoUK.Coordinates;
using GeoUK.Ellipsoids;
using GeoUK.Projections;
using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
namespace GeoUK
{
public static class OSTN02Transform
{
/// <summary>
/// Performs an ETRS89 to OSGB36/ODN datum transformation. Accuracy is approximately 10 centimeters.
/// Whilst very accurate this method is much slower than the Helmert transformation.
/// </summary>
public static Osgb36 Etrs89ToOsgb(LatitudeLongitude coordinates)
{
var enCoordinates = Convert.ToEastingNorthing (new Grs80 (), new BritishNationalGrid (), coordinates);
return Etrs89ToOsgb (enCoordinates, coordinates.ElipsoidalHeight);
}
public static class OSTN02Transform
{
/// <summary>
/// Performs an ETRS89 to OSGB36/ODN datum transformation. Accuracy is approximately 10 centimeters.
/// Whilst very accurate this method is much slower than the Helmert transformation.
/// </summary>
public static Osgb36 Etrs89ToOsgb(LatitudeLongitude coordinates)
{
var enCoordinates = Convert.ToEastingNorthing(new Grs80(), new BritishNationalGrid(), coordinates);
return Etrs89ToOsgb(enCoordinates, coordinates.ElipsoidalHeight);
}
private static Osgb36 Etrs89ToOsgb(EastingNorthing coordinates, double ellipsoidHeight)
{
var dataStream = GetEmbeddedOSTN02 ();
private static Osgb36 Etrs89ToOsgb(EastingNorthing coordinates, double ellipsoidHeight)
{
var dataStream = GetEmbeddedOSTN02();
TextReader tr = new StreamReader(dataStream);
List<int> recordNumbers = new List<int>();
string[] records = new string[4];
TextReader tr = new StreamReader(dataStream);
List<int> recordNumbers = new List<int>();
string[] records = new string[4];
//determine record numbers
int eastIndex = (int)(coordinates.Easting / 1000.0);
int northIndex = (int)(coordinates.Northing / 1000.0);
//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;
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));
//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 records from the data file
int recordsFound = 0;
while (recordsFound < 4)
{
string csvRecord = tr.ReadLine();
for (int index = 0; index < 4; index++)
{
if (csvRecord.StartsWith (recordNumbers [index].ToString ().Trim () + ",", StringComparison.Ordinal)) {
//dont use add as we need to keep these in same order as record numbers
records [index] = csvRecord;
recordsFound++;
}
}
}
//get records from the data file
int recordsFound = 0;
while (recordsFound < 4)
{
string csvRecord = tr.ReadLine();
for (int index = 0; index < 4; index++)
{
if (csvRecord.StartsWith(recordNumbers[index].ToString().Trim() + ",", StringComparison.Ordinal))
{
//dont use add as we need to keep these in same order as record numbers
records[index] = csvRecord;
recordsFound++;
}
}
}
//populate the properties
string[] fields0 = records[0].Split(",".ToCharArray());
string[] fields1 = records[1].Split(",".ToCharArray());
string[] fields2 = records[2].Split(",".ToCharArray());
string[] fields3 = records[3].Split(",".ToCharArray());
//populate the properties
string[] fields0 = records[0].Split(",".ToCharArray());
string[] fields1 = records[1].Split(",".ToCharArray());
string[] fields2 = records[2].Split(",".ToCharArray());
string[] fields3 = records[3].Split(",".ToCharArray());
var se0 = System.Convert.ToDouble(fields0[3]);
var se1 = System.Convert.ToDouble(fields1[3]);
var se2 = System.Convert.ToDouble(fields2[3]);
var se3 = System.Convert.ToDouble(fields3[3]);
var se0 = System.Convert.ToDouble(fields0[3]);
var se1 = System.Convert.ToDouble(fields1[3]);
var se2 = System.Convert.ToDouble(fields2[3]);
var se3 = System.Convert.ToDouble(fields3[3]);
var sn0 = System.Convert.ToDouble(fields0[4]);
var sn1 = System.Convert.ToDouble(fields1[4]);
var sn2 = System.Convert.ToDouble(fields2[4]);
var sn3 = System.Convert.ToDouble(fields3[4]);
var sn0 = System.Convert.ToDouble(fields0[4]);
var sn1 = System.Convert.ToDouble(fields1[4]);
var sn2 = System.Convert.ToDouble(fields2[4]);
var sn3 = System.Convert.ToDouble(fields3[4]);
var sg0 = System.Convert.ToDouble(fields0[5]);
var sg1 = System.Convert.ToDouble(fields1[5]);
var sg2 = System.Convert.ToDouble(fields2[5]);
var sg3 = System.Convert.ToDouble(fields3[5]);
var sg0 = System.Convert.ToDouble(fields0[5]);
var sg1 = System.Convert.ToDouble(fields1[5]);
var sg2 = System.Convert.ToDouble(fields2[5]);
var sg3 = System.Convert.ToDouble(fields3[5]);
var dx = coordinates.Easting - x0;
var dy = coordinates.Northing - y0;
var dx = coordinates.Easting - x0;
var dy = coordinates.Northing - y0;
var t = dx / 1000.0;
var u = dy / 1000.0;
var t = dx / 1000.0;
var u = dy / 1000.0;
var se = (1 - t) * (1 - u) * se0 + t * (1 - u) * se1 + t * u * se2 + (1 - t) * u * se3;
var sn = (1 - t) * (1 - u) * sn0 + t * (1 - u) * sn1 + t * u * sn2 + (1 - t) * u * sn3;
var sg = (1 - t) * (1 - u) * sg0 + t * (1 - u) * sg1 + t * u * sg2 + (1 - t) * u * sg3;
var se = (1 - t) * (1 - u) * se0 + t * (1 - u) * se1 + t * u * se2 + (1 - t) * u * se3;
var sn = (1 - t) * (1 - u) * sn0 + t * (1 - u) * sn1 + t * u * sn2 + (1 - t) * u * sn3;
var sg = (1 - t) * (1 - u) * sg0 + t * (1 - u) * sg1 + t * u * sg2 + (1 - t) * u * sg3;
var geoidDatum = (Osgb36GeoidDatum)System.Convert.ToInt32(fields0[6]);
var geoidDatum = (Osgb36GeoidDatum)System.Convert.ToInt32(fields0[6]);
var easting = coordinates.Easting + se;
var northing = coordinates.Northing + sn;
var height = ellipsoidHeight - sg;
var easting = coordinates.Easting + se;
var northing = coordinates.Northing + sn;
var height = ellipsoidHeight - sg;
return new Osgb36(easting, northing, height, geoidDatum);
return new Osgb36(easting, northing, height, geoidDatum);
}
}
/// <summary>
/// Calculates a data file record number.
/// </summary>
/// <param name="eastIndex"></param>
/// <param name="northIndex"></param>
/// <returns></returns>
private static int CalculateRecordNumber(int eastIndex, int northIndex)
{
return eastIndex + (northIndex * 701) + 1;
}
private static Stream GetEmbeddedOSTN02()
{
return ResourceManager.GetEmbeddedResourceStream (typeof(OSTN02Transform).GetTypeInfo ().Assembly, "OSTN02_OSGM02_GB.txt");
}
}
}
/// <summary>
/// Calculates a data file record number.
/// </summary>
/// <param name="eastIndex"></param>
/// <param name="northIndex"></param>
/// <returns></returns>
private static int CalculateRecordNumber(int eastIndex, int northIndex)
{
return eastIndex + (northIndex * 701) + 1;
}
private static Stream GetEmbeddedOSTN02()
{
return ResourceManager.GetEmbeddedResourceStream(typeof(OSTN02Transform).GetTypeInfo().Assembly, "OSTN02_OSGM02_GB.txt");
}
}
}

View File

@@ -1,7 +1,3 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace GeoUK.Projections
{
/// <summary>
@@ -23,4 +19,4 @@ namespace GeoUK.Projections
{
}
}
}
}

View File

@@ -1,7 +1,3 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace GeoUK.Projections
{
/// <summary>
@@ -9,11 +5,11 @@ namespace GeoUK.Projections
/// </summary>
public class IrishNationalGrid : Projection
{
private const double SCALE_FACTOR = 1.000035;
private const double E = 200000;
private const double TO_LAT = 53.5;
private const double SCALE_FACTOR = 1.000035;
private const double E = 200000;
private const double TO_LAT = 53.5;
private const double TO_LONG = -8;
private const double N_NH = 250000;
private const double N_NH = 250000;
/// <summary>
/// Constructor.
@@ -23,4 +19,4 @@ namespace GeoUK.Projections
{
}
}
}
}

View File

@@ -1,6 +1,4 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Globalization;
namespace GeoUK.Projections
@@ -16,7 +14,6 @@ namespace GeoUK.Projections
private double _trueOriginEasting = 0.0;
private double _trueOriginNorthing = 0.0;
/// <summary>
/// Constructor.
/// </summary>
@@ -36,6 +33,7 @@ namespace GeoUK.Projections
{
get { return _scaleFactor; }
}
/// <summary>
/// Returns the Easting coordinate of the true origin.
/// </summary>
@@ -43,6 +41,7 @@ namespace GeoUK.Projections
{
get { return _trueOriginEasting; }
}
/// <summary>
/// Returns the Northing coordinate of the true origin.
/// </summary>
@@ -50,13 +49,15 @@ namespace GeoUK.Projections
{
get { return _trueOriginNorthing; }
}
/// <summary>
/// Returns the Latitude coordinate of the true origin for the southern hemisphere.
/// </summary>
public double TrueOriginLatitude
{
get{ return _trueOriginLatitude; }
get { return _trueOriginLatitude; }
}
/// <summary>
/// Returns the Longitude coordinate of the true origin for the southern hemisphere.
/// </summary>
@@ -64,6 +65,7 @@ namespace GeoUK.Projections
{
get { return _trueOriginLongitude; }
}
//public static double DegreesToRadians(double degrees)
//{
// return degrees * (Math.PI / 180);
@@ -109,8 +111,6 @@ namespace GeoUK.Projections
}
return dblResult;
}
}
}
}

View File

@@ -1,12 +1,9 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Globalization;
namespace GeoUK.Projections
{
/// <summary>
/// This immutable class, derived from Projection, represents the Universal Transverse Mercator projection.
/// This immutable class, derived from Projection, represents the Universal Transverse Mercator projection.
/// The class handles all medidian calculations internally.
/// </summary>
public class UniversalTransverseMercator : Projection
@@ -16,6 +13,7 @@ namespace GeoUK.Projections
private const double TO_LAT = 0; //is this for britain? These will need to be calculated based on the lat and long being transfformed.
private const double N_NH = 0;
private const double N_SH = 10000000;
/// <summary>
/// Constructor
/// </summary>
@@ -24,8 +22,8 @@ namespace GeoUK.Projections
public UniversalTransverseMercator(double degreesLatitude, double degreesLongitude)
: base(SCALE_FACTOR, E, CalculateOriginNorthing(degreesLatitude, degreesLongitude), TO_LAT, CalculateLongitudeOrigin(degreesLatitude, degreesLongitude))
{
}
private static double CalculateOriginNorthing(double degreesLatitude, double degreesLongitude)
{
double falseNorthing = 0.0;
@@ -40,9 +38,9 @@ namespace GeoUK.Projections
}
return falseNorthing;
}
private static double CalculateLongitudeOrigin(double degreesLatitude, double degreesLongitude)
{
double longOrigin = 0.0;
if (degreesLongitude < 0)
@@ -68,9 +66,8 @@ namespace GeoUK.Projections
longOrigin = Div(degreesLongitude, 6);
longOrigin = (System.Convert.ToInt32(longOrigin, CultureInfo.InvariantCulture)) * 6 + 3;
}
}
}
return longOrigin;
}
}
}
}

View File

@@ -1,39 +1,37 @@
using System;
using System.IO;
using System.Collections.Generic;
using System.Text;
using System.Reflection;
using System.Linq;
using System.Reflection;
namespace GeoUK
{
internal static class ResourceManager
{
/// <summary>
/// Attempts to find and return the given resource from within the specified assembly.
/// </summary>
/// <returns>The embedded resource stream.</returns>
/// <param name="assembly">Assembly.</param>
/// <param name="resourceFileName">Resource file name.</param>
public static Stream GetEmbeddedResourceStream(Assembly assembly, string resourceFileName)
{
var resourceNames = assembly.GetManifestResourceNames();
var resourcePaths = resourceNames
.Where(x => x.EndsWith(resourceFileName, StringComparison.CurrentCultureIgnoreCase))
.ToArray();
/// <summary>
/// Attempts to find and return the given resource from within the specified assembly.
/// </summary>
/// <returns>The embedded resource stream.</returns>
/// <param name="assembly">Assembly.</param>
/// <param name="resourceFileName">Resource file name.</param>
public static Stream GetEmbeddedResourceStream (Assembly assembly, string resourceFileName)
{
var resourceNames = assembly.GetManifestResourceNames ();
if (!resourcePaths.Any())
{
throw new Exception(string.Format("Resource ending with {0} not found.", resourceFileName));
}
var resourcePaths = resourceNames
.Where (x => x.EndsWith (resourceFileName, StringComparison.CurrentCultureIgnoreCase))
.ToArray ();
if (resourcePaths.Count() > 1)
{
throw new Exception(string.Format("Multiple resources ending with {0} found: {1}{2}", resourceFileName, Environment.NewLine, string.Join(Environment.NewLine, resourcePaths)));
}
if (!resourcePaths.Any ()) {
throw new Exception (string.Format ("Resource ending with {0} not found.", resourceFileName));
}
if (resourcePaths.Count () > 1) {
throw new Exception (string.Format ("Multiple resources ending with {0} found: {1}{2}", resourceFileName, Environment.NewLine, string.Join (Environment.NewLine, resourcePaths)));
}
return assembly.GetManifestResourceStream (resourcePaths.Single ());
}
return assembly.GetManifestResourceStream(resourcePaths.Single());
}
}
}
}

View File

@@ -1,8 +1,5 @@
using System;
using System.Globalization;
using GeoUK.Coordinates;
using GeoUK.Ellipsoids;
using GeoUK.Projections;
using System;
namespace GeoUK
{
@@ -11,14 +8,13 @@ namespace GeoUK
/// </summary>
public static class Transform
{
/// <summary>
/// Performs an ETRS89 to OSGB36 datum transformation. Accuracy is approximately 5 meters in all directions.
/// For this method, ERTS89, ITRS2000 and WGS84 datums can be considered the same.
/// </summary>
/// <param name="coordinates">Cartesian Coordinates to be transformed.</param>
/// <remarks>
/// This method uses a Helmert transformation to determine the OSGB36 coordinates.
/// This method uses a Helmert transformation to determine the OSGB36 coordinates.
/// Whilst only accurate to 5 meters in all directions, it is extremely fast.
/// </remarks>
public static Cartesian Etrs89ToOsgb36(Cartesian coordinates)
@@ -37,9 +33,9 @@ namespace GeoUK
Cartesian result = HelmertTransformation(coordinates, tx, ty, tz, rx, ry, rz, s);
return result;
return result;
}
/// <summary>
/// Performs an OSGB36 to ETRS89 datum transformation. Accuracy is approximately 5 meters in all directions.
/// For this method, ERTS89, ITRS2000 and WGS84 datums can be considered the same.
@@ -56,22 +52,21 @@ namespace GeoUK
double ty = -125.157;
double tz = 542.060;
double s = -20.4894;
double rx = ToRadians(ToDecimelDegrees(0, 0, 0.1502));
double rx = ToRadians(ToDecimelDegrees(0, 0, 0.1502));
double ry = ToRadians(ToDecimelDegrees(0, 0, 0.247));
double rz = ToRadians(ToDecimelDegrees(0, 0, 0.8421));
return HelmertTransformation(coordinates, tx, ty, tz, rx, ry, rz, s);
}
}
/*
/*
* //(BUT CHANGE SIGNS OF EACH PARAMETER FOR REVERSE)
tX (m) tY (m) tZ (m) s (ppm) rX (sec) rY (sec) rZ (sec)
-446.448 +125.157 -542.060 +20.4894 -0.1502 -0.2470 -0.8421
*/
/// <summary>
/// <summary>
/// Performs an ETRS89 to ITRS2000 datum transformation.
/// </summary>
/// <param name="coordinates">Cartesian Coordinates to be transformed.</param>
@@ -95,21 +90,21 @@ namespace GeoUK
double rz = Negate(ToRadians(ToDecimelDegrees(0, 0, -0.000792) * dt));
return HelmertTransformation(coordinates, tx, ty, tz, rx, ry, rz, s);
}
/// <summary>
/// Performs an ITRS2000 to ETRS89 datum transformation.
/// </summary>
/// <param name="coordinates">Cartesian Coordinates to be transformed.</param>
/// <param name="epochYear">Refers to the year the data specified in coordinates was gathered.</param>
/// <returns></returns>
public static Cartesian Itrs2000ToEtrs89(Cartesian coordinates, int epochYear )
public static Cartesian Itrs2000ToEtrs89(Cartesian coordinates, int epochYear)
{
//tX (m) tY (m) tZ (m) s (ppm) rX (sec) rY (sec) rZ (sec)
//0.054 0.051 - 0.048 0 0.000081 dt 0.00049 dt - 0.000792 dt
//dt represents shift in years since time of survey to when ETRS89 was determined
//dt represents shift in years since time of survey to when ETRS89 was determined
int dt = epochYear - 1989;
//set up the parameters
double tx = 0.054;
@@ -121,8 +116,8 @@ namespace GeoUK
double rz = ToRadians(ToDecimelDegrees(0, 0, -0.000792) * dt);
return HelmertTransformation(coordinates, tx, ty, tz, rx, ry, rz, s);
}
/// <summary>
/// Performs an ITRS94/96/97 to ETRS89 datum transformation.
/// </summary>
@@ -149,6 +144,7 @@ namespace GeoUK
return HelmertTransformation(coordinates, tx, ty, tz, rx, ry, rz, s);
}
/// <summary>
/// Performs an ETRS89 to ITRS94/96/97 datum transformation.
/// </summary>
@@ -175,25 +171,30 @@ namespace GeoUK
return HelmertTransformation(coordinates, tx, ty, tz, rx, ry, rz, s);
}
private static double ToDecimelDegrees(int degrees, int minutes, double seconds)
private static double ToDecimelDegrees(int degrees, int minutes, double seconds)
{
//determine seconds as minutes
double m = minutes + (seconds / 60.0);
return ToDecimelDegrees(degrees, m);
}
private static double ToDecimelDegrees(int degrees, double minutes)
private static double ToDecimelDegrees(int degrees, double minutes)
{
//determine minutes as derees
return degrees + (minutes / 60.0);
}
private static double ToRadians(double degrees)
private static double ToRadians(double degrees)
{
return degrees * (Math.PI / 180.0);
}
private static double ToDegrees(double radians)
private static double ToDegrees(double radians)
{
return radians * (180.0 / Math.PI);
}
/// <summary>
/// This seven parameter method can be used to transform coordinates between datums.
/// </summary>
@@ -262,6 +263,7 @@ namespace GeoUK
//adding to T whilst creating the cartesian coordinates
return new Cartesian(T[0] + temp[0], T[1] + temp[1], T[2] + temp[2]);
}
/// <summary>
/// Helper funtion to reverse the sign of a value. Helps code to be more readable.
/// </summary>
@@ -272,4 +274,4 @@ namespace GeoUK
return value * -1.0;
}
}
}
}