/// <summary> /// Create a new earth-centered, earth-fixed (ECEF) reference from the given parameters and /// the given reference ellipsoid. /// </summary> /// <param name="x"> The x co-ordinate. </param> /// <param name="y"> The y co-ordinate. </param> /// <param name="z"> The z co-ordinate. </param> /// <param name="datum"> The datum. </param> public ECEFRef(double x, double y, double z, Datum.Datum datum) : base(datum) { X = x; Y = y; Z = z; }
/// <summary> /// Create a new UTM reference object. Checks are made to make sure that the /// given parameters are roughly valid, but the checks are not exhaustive with /// regards to the easting value. Catching a NotDefinedOnUTMGridException does /// not necessarily mean that the UTM reference is well-formed. This is because /// that valid values for the easting vary depending on the latitude. /// </summary> /// <param name="lngZone">The longitude zone number.</param> /// <param name="latZone">The latitude zone character.</param> /// <param name="easting">The easting in metres.</param> /// <param name="northing">The northing in metres.</param> /// <param name="datum">The datum of the UTM reference</param> /// <exception cref="NotDefinedOnUtmGridException"> /// If any of the parameters are invalid. Be careful that a valid /// value for the easting does not necessarily mean that the UTM /// reference is well-formed. The current checks do not take into /// account the varying range of valid values for the easting for /// different latitudes.</exception> public UTMRef(int lngZone, char latZone, double easting, double northing, Datum.Datum datum) : base(datum) { if (lngZone < 1 || lngZone > 60) { throw new NotDefinedOnUtmGridException("Longitude zone (" + lngZone + ") is not defined on the UTM grid."); } if (latZone < 'C' || latZone > 'X') { throw new NotDefinedOnUtmGridException("Latitude zone (" + latZone + ") is not defined on the UTM grid."); } if (easting < 0.0 || easting > 1000000.0) { throw new NotDefinedOnUtmGridException("Easting (" + easting + ") is not defined on the UTM grid."); } if (northing < 0.0 || northing > 10000000.0) { throw new NotDefinedOnUtmGridException("Northing (" + northing + ") is not defined on the UTM grid."); } Easting = easting; Northing = northing; LatZone = latZone; LngZone = lngZone; }
/// <summary> /// Create a new LatLng object to represent a latitude/longitude pair using the /// specified datum. /// </summary> /// <param name="latitudeDegrees">The degrees part of the latitude. Must be 0 <= latitudeDegrees <= /// 90.0.</param> /// <param name="latitudeMinutes">The minutes part of the latitude. Must be 0 <= latitudeMinutes < /// 60.0.</param> /// <param name="latitudeSeconds">The seconds part of the latitude. Must be 0 <= latitudeSeconds < /// 60.0.</param> /// <param name="northSouth">Whether the latitude is north or south of the equator.</param> /// <param name="longitudeDegrees">The degrees part of the longitude. Must be 0 <= longitudeDegrees <= /// 180.0.</param> /// <param name="longitudeMinutes">The minutes part of the longitude. Must be 0 <= longitudeMinutes < /// 60.0.</param> /// <param name="longitudeSeconds">The seconds part of the longitude. Must be 0 <= longitudeSeconds < /// 60.0.</param> /// <param name="eastWest">Whether the longitude is east or west of the prime meridian.</param> /// <param name="height">The perpendicular height above the reference ellipsoid.</param> /// <param name="datum">The datum that this reference is based on.</param> /// <exception cref="ArgumentException">if any of the parameters are invalid.</exception> public LatLng(int latitudeDegrees, int latitudeMinutes, double latitudeSeconds, NorthSouth northSouth, int longitudeDegrees, int longitudeMinutes, double longitudeSeconds, EastWest eastWest, double height, Datum.Datum datum) { if (latitudeDegrees < 0.0 || latitudeDegrees > 90.0 || latitudeMinutes < 0.0 || latitudeMinutes >= 60.0 || latitudeSeconds < 0.0 || latitudeSeconds >= 60.0) { throw new ArgumentException("Invalid latitude"); } if (longitudeDegrees < 0.0 || longitudeDegrees > 180.0 || longitudeMinutes < 0.0 || longitudeMinutes >= 60.0 || longitudeSeconds < 0.0 || longitudeSeconds >= 60.0) { throw new ArgumentException("Invalid longitude"); } Latitude = (int)northSouth * (latitudeDegrees + (latitudeMinutes / 60.0) + (latitudeSeconds / 3600.0)); Longitude = (int)eastWest * (longitudeDegrees + (longitudeMinutes / 60.0) + (longitudeSeconds / 3600.0)); Height = height; Datum = datum; }
private void InternalToDatum(Datum.Datum d, bool toWgs) { double a = Datum.ReferenceEllipsoid.SemiMajorAxis; double eSquared = Datum.ReferenceEllipsoid.EccentricitySquared; double phi = Util.ToRadians(Latitude); double lambda = Util.ToRadians(Longitude); double v = a / (Math.Sqrt(1 - eSquared * Util.SinSquared(phi))); double h = Height; // height double x = (v + h) * Math.Cos(phi) * Math.Cos(lambda); double y = (v + h) * Math.Cos(phi) * Math.Sin(lambda); double z = ((1 - eSquared) * v + h) * Math.Sin(phi); double invert = -1; Datum.Datum referenceDatum = d; if (toWgs) { invert = 1; referenceDatum = Datum; } double dx = invert * referenceDatum.DX; double dy = invert * referenceDatum.DY; double dz = invert * referenceDatum.DZ; double ds = invert * referenceDatum.DS / 1000000.0; double rx = invert * Util.ToRadians(referenceDatum.RX / 3600.0); double ry = invert * Util.ToRadians(referenceDatum.RY / 3600.0); double rz = invert * Util.ToRadians(referenceDatum.RZ / 3600.0); double sc = 1 + ds; double xB = dx + (x * sc) + ((-rx * y) * sc) + ((ry * z) * sc); double yB = dy + ((rz * x) * sc) + (y * sc) + ((-rx * z) * sc); double zB = dz + ((-ry * x) * sc) + ((rx * y) * sc) + (z * sc); a = d.ReferenceEllipsoid.SemiMajorAxis; eSquared = d.ReferenceEllipsoid.EccentricitySquared; double lambdaB = Util.ToDegrees(Math.Atan(yB / xB)); double p = Math.Sqrt((xB * xB) + (yB * yB)); double phiN = Math.Atan(zB / (p * (1 - eSquared))); for (int i = 1; i < 10; i++) { v = a / (Math.Sqrt(1 - eSquared * Util.SinSquared(phiN))); double phiN1 = Math.Atan((zB + (eSquared * v * Math.Sin(phiN))) / p); phiN = phiN1; } double phiB = Util.ToDegrees(phiN); Latitude = phiB; Longitude = lambdaB; Datum = d; }
private void InternalToDatum(Datum.Datum d, bool toWgs) { var a = _datum.ReferenceEllipsoid.SemiMajorAxis; var eSquared = _datum.ReferenceEllipsoid.EccentricitySquared; var phi = Util.ToRadians(Latitude); var lambda = Util.ToRadians(Longitude); var v = a / Math.Sqrt(1 - eSquared * Util.sinSquared(phi)); var H = Height; // height var x = (v + H) * Math.Cos(phi) * Math.Cos(lambda); var y = (v + H) * Math.Cos(phi) * Math.Sin(lambda); var z = ((1 - eSquared) * v + H) * Math.Sin(phi); double invert = -1; var referenceDatum = d; if (toWgs) { invert = 1; referenceDatum = _datum; } var dx = invert * referenceDatum.DX; var dy = invert * referenceDatum.DY; var dz = invert * referenceDatum.DZ; var ds = invert * referenceDatum.DS / 1000000.0; var rx = invert * Util.ToRadians(referenceDatum.RX / 3600.0); var ry = invert * Util.ToRadians(referenceDatum.RY / 3600.0); var rz = invert * Util.ToRadians(referenceDatum.RZ / 3600.0); var sc = 1 + ds; var xB = dx + x * sc + -rx * y * sc + ry * z * sc; var yB = dy + rz * x * sc + y * sc + -rx * z * sc; var zB = dz + -ry * x * sc + rx * y * sc + z * sc; a = d.ReferenceEllipsoid.SemiMajorAxis; eSquared = d.ReferenceEllipsoid.EccentricitySquared; var lambdaB = Util.ToDegrees(Math.Atan(yB / xB)); var p = Math.Sqrt(xB * xB + yB * yB); var phiN = Math.Atan(zB / (p * (1 - eSquared))); for (var i = 1; i < 10; i++) { v = a / Math.Sqrt(1 - eSquared * Util.sinSquared(phiN)); var phiN1 = Math.Atan((zB + eSquared * v * Math.Sin(phiN)) / p); phiN = phiN1; } var phiB = Util.ToDegrees(phiN); Latitude = phiB; Longitude = lambdaB; _datum = d; }
/// <summary> /// Converts this LatLng to another datum. /// </summary> /// <param name="d">The datum.</param> public void ToDatum(Datum.Datum d) { // first convert to WGS84 if needed if (!(Datum is WGS84Datum)) { InternalToDatum(WGS84Datum.Instance, true); } if (d is WGS84Datum) { // Don't do anything if datum and d are both WGS84. return; } InternalToDatum(d, false); }
/// <summary> /// Create a new LatLng object to represent a latitude/longitude pair using the /// specified datum. /// </summary> /// <param name="latitude">The latitude in degrees. Must be between -90.0 and 90.0 inclusive. /// -90.0 and 90.0 are effectively equivalent.</param> /// <param name="longitude">The longitude in degrees. Must be between -180.0 and 180.0 /// inclusive. -180.0 and 180.0 are effectively equivalent.</param> /// <param name="height">The perpendicular height above the reference ellipsoid.</param> /// <param name="datum">The datum that this reference is based on.</param> /// <exception cref="ArgumentException">If either the given latitude or the given longitude are invalid.</exception> public LatLng(double latitude, double longitude, double height, Datum.Datum datum) { if (!IsValidLatitude(latitude)) { throw new ArgumentException("Latitude (" + latitude + ") is invalid. Must be between -90.0 and 90.0 inclusive."); } if (!IsValidLongitude(longitude)) { throw new ArgumentException("Longitude (" + longitude + ") is invalid. Must be between -180.0 and 180.0 inclusive."); } Latitude = latitude; Longitude = longitude; Height = height; Datum = datum; }
/// <summary> /// Convert this LatLng from the OSGB36 datum to the WGS84 datum using an /// approximate Helmert transformation. /// </summary> public void ToWGS84() { double a = Airy1830Ellipsoid.Instance.SemiMajorAxis; double eSquared = Airy1830Ellipsoid.Instance.EccentricitySquared; double phi = Util.ToRadians(latitude); double lambda = Util.ToRadians(longitude); double v = a / (Math.Sqrt(1 - eSquared * Util.sinSquared(phi))); double H = 0; // height double x = (v + H) * Math.Cos(phi) * Math.Cos(lambda); double y = (v + H) * Math.Cos(phi) * Math.Sin(lambda); double z = ((1 - eSquared) * v + H) * Math.Sin(phi); double tx = 446.448; // ty : Incorrect value in v1.0 (-124.157). Corrected in v1.1. double ty = -125.157; double tz = 542.060; double s = -0.0000204894; double rx = Util.ToRadians(0.00004172222); double ry = Util.ToRadians(0.00006861111); double rz = Util.ToRadians(0.00023391666); double xB = tx + (x * (1 + s)) + (-rx * y) + (ry * z); double yB = ty + (rz * x) + (y * (1 + s)) + (-rx * z); double zB = tz + (-ry * x) + (rx * y) + (z * (1 + s)); a = WGS84Ellipsoid.Instance.SemiMajorAxis; eSquared = WGS84Ellipsoid.Instance.EccentricitySquared; double lambdaB = Util.ToDegrees(Math.Atan(yB / xB)); double p = Math.Sqrt((xB * xB) + (yB * yB)); double phiN = Math.Atan(zB / (p * (1 - eSquared))); for (int i = 1; i < 10; i++) { v = a / (Math.Sqrt(1 - eSquared * Util.sinSquared(phiN))); double phiN1 = Math.Atan((zB + (eSquared * v * Math.Sin(phiN))) / p); phiN = phiN1; } double phiB = Util.ToDegrees(phiN); latitude = phiB; longitude = lambdaB; datum = WGS84Datum.Instance; }
/// <summary> /// Create a new LatLng object to represent a latitude/longitude pair using the /// specified datum. /// </summary> /// <param name="latitude">The latitude in degrees. Must be between -90.0 and 90.0 inclusive. /// -90.0 and 90.0 are effectively equivalent.</param> /// <param name="longitude">The longitude in degrees. Must be between -180.0 and 180.0 /// inclusive. -180.0 and 180.0 are effectively equivalent.</param> /// <param name="height">The perpendicular height above the reference ellipsoid.</param> /// <param name="datum">The datum that this reference is based on.</param> /// <exception cref="ArgumentException">If either the given latitude or the given longitude are invalid.</exception> public LatLng(double latitude, double longitude, double height, DotNetCoords.Datum.Datum datum) { if (!IsValidLatitude(latitude)) { throw new ArgumentException("Latitude (" + latitude + ") is invalid. Must be between -90.0 and 90.0 inclusive."); } if (!IsValidLongitude(longitude)) { throw new ArgumentException("Longitude (" + longitude + ") is invalid. Must be between -180.0 and 180.0 inclusive."); } this.latitude = latitude; this.longitude = longitude; this.height = height; this.datum = datum; }
/// <summary> /// Create a new LatLng object to represent a latitude/longitude pair using the /// specified datum. /// </summary> /// <param name="latitudeDegrees">The degrees part of the latitude. Must be 0 <= latitudeDegrees <= /// 90.0.</param> /// <param name="latitudeMinutes">The minutes part of the latitude. Must be 0 <= latitudeMinutes < /// 60.0.</param> /// <param name="latitudeSeconds">The seconds part of the latitude. Must be 0 <= latitudeSeconds < /// 60.0.</param> /// <param name="northSouth">Whether the latitude is north or south of the equator.</param> /// <param name="longitudeDegrees">The degrees part of the longitude. Must be 0 <= longitudeDegrees <= /// 180.0.</param> /// <param name="longitudeMinutes">The minutes part of the longitude. Must be 0 <= longitudeMinutes < /// 60.0.</param> /// <param name="longitudeSeconds">The seconds part of the longitude. Must be 0 <= longitudeSeconds < /// 60.0.</param> /// <param name="eastWest">Whether the longitude is east or west of the prime meridian.</param> /// <param name="height">The perpendicular height above the reference ellipsoid.</param> /// <param name="datum">The datum that this reference is based on.</param> /// <exception cref="ArgumentException">if any of the parameters are invalid.</exception> public LatLng(int latitudeDegrees, int latitudeMinutes, double latitudeSeconds, NorthSouth northSouth, int longitudeDegrees, int longitudeMinutes, double longitudeSeconds, EastWest eastWest, double height, DotNetCoords.Datum.Datum datum) { if (latitudeDegrees < 0.0 || latitudeDegrees > 90.0 || latitudeMinutes < 0.0 || latitudeMinutes >= 60.0 || latitudeSeconds < 0.0 || latitudeSeconds >= 60.0) { throw new ArgumentException("Invalid latitude"); } if (longitudeDegrees < 0.0 || longitudeDegrees > 180.0 || longitudeMinutes < 0.0 || longitudeMinutes >= 60.0 || longitudeSeconds < 0.0 || longitudeSeconds >= 60.0) { throw new ArgumentException("Invalid longitude"); } this.latitude = (int)northSouth * (latitudeDegrees + (latitudeMinutes / 60.0) + (latitudeSeconds / 3600.0)); this.longitude = (int)eastWest * (longitudeDegrees + (longitudeMinutes / 60.0) + (longitudeSeconds / 3600.0)); this.height = height; this.datum = datum; }
/// <summary> /// Create a new UTM reference object. Checks are made to make sure that the given /// parameters are roughly valid, but the checks are not exhaustive with regards to the /// easting value. Catching a NotDefinedOnUTMGridException does not necessarily mean that /// the UTM reference is well-formed. This is because that valid values for the easting vary /// depending on the latitude. /// </summary> /// <param name="lngZone"> The longitude zone number. </param> /// <param name="latZone"> The latitude zone character. </param> /// <param name="easting"> The easting in meters. </param> /// <param name="northing"> The northing in meters. </param> /// <param name="datum"> The datum of the UTM reference </param> /// <exception cref="NotDefinedOnUtmGridException"> /// If any of the parameters are invalid. Be careful that a valid value for the easting does /// not necessarily mean that the UTM reference is well-formed. The current checks do not /// take into account the varying range of valid values for the easting for different latitudes. /// </exception> public UtmRef(int lngZone, char latZone, double easting, double northing, Datum.Datum datum) : base(datum) { latZone = char.ToUpper(latZone); if (lngZone < 1 || lngZone > 60) { throw new NotDefinedOnUtmGridException("Longitude zone (" + lngZone + ") is not defined on the UTM grid."); } if (latZone < 'C' || latZone > 'X') { throw new NotDefinedOnUtmGridException("Latitude zone (" + latZone + ") is not defined on the UTM grid."); } if (easting < 0.0 || easting > 1000000.0) { throw new NotDefinedOnUtmGridException("Easting (" + easting + ") is not defined on the UTM grid."); } if (northing < 0.0 || northing > 10000000.0) { throw new NotDefinedOnUtmGridException("Northing (" + northing + ") is not defined on the UTM grid."); } Easting = easting; Northing = northing; LatZone = latZone; LngZone = lngZone; }
/// <summary> /// Take a string and make it a LatLng /// </summary> /// <param name="toConvert"></param> /// <exception cref="ArgumentException"></exception> public LatLng(string toConvert) { if (RxLatLngDecimal.IsMatch(toConvert)) { double lat, lng; var latLngMatch = RxLatLngDecimal.Match(toConvert); var strLat = latLngMatch.Groups["lat"].Value; var strLng = latLngMatch.Groups["lng"].Value; if (double.TryParse(strLat, out lat) && double.TryParse(strLng, out lng)) { Latitude = lat; Longitude = lng; Height = 0; } } if (RxLatLngDms.IsMatch(toConvert)) { var latLngDMSMatch = RxLatLngDms.Match(toConvert); int latDeg, latMin, lngDeg, lngMin; double latSec, lngSec; char latDir, lngDir; var strLatDeg = latLngDMSMatch.Groups["latDeg"].Value; var strLngDeg = latLngDMSMatch.Groups["lngDeg"].Value; var strLatMin = latLngDMSMatch.Groups["latMin"].Value; var strLngMin = latLngDMSMatch.Groups["lngMin"].Value; var strLatSec = latLngDMSMatch.Groups["latSec"].Value; var strLngSec = latLngDMSMatch.Groups["lngSec"].Value; var strLatDir = latLngDMSMatch.Groups["latDir"].Value; var strLngDir = latLngDMSMatch.Groups["lngDir"].Value; if (int.TryParse(strLatDeg, out latDeg) && int.TryParse(strLngDeg, out lngDeg) && int.TryParse(strLatMin, out latMin) && int.TryParse(strLngMin, out lngMin) && double.TryParse(strLatSec, out latSec) && double.TryParse(strLngSec, out lngSec) ) { char.TryParse(strLatDir, out latDir); char.TryParse(strLngDir, out lngDir); latDir = char.ToUpper(latDir); lngDir = char.ToUpper(lngDir); var northSouth = NorthSouth.North; var eastWest = EastWest.East; // deal with the negative numbers if (latDir == 'S') { northSouth = NorthSouth.South; } if (lngDir == 'W') { eastWest = EastWest.West; } if (lngDeg < 0) { lngDeg = Math.Abs(lngDeg); eastWest = EastWest.West; } if (latDeg < 0) { latDeg = Math.Abs(latDeg); northSouth = NorthSouth.South; } var lat = latDeg + latMin / 60.0 + latSec / 3600.0; var lng = lngDeg + lngMin / 60.0 + lngSec / 3600.0; Latitude = (int)northSouth * lat; Longitude = (int)eastWest * lng; Height = 0; _datum = WGS84Datum.Instance; } } }
/// <summary> /// Initializes a new instance of the <see cref="CoordinateSystem"/> class. /// </summary> /// <param name="datum">The datum.</param> protected CoordinateSystem(DotNetCoords.Datum.Datum datum) { this.datum = datum; }