/// <summary> /// Get the latitude/longitude coordinates from the euclidian coordinates /// </summary> /// <param name="xy">The euclidien coordinates</param> /// <returns>The latitude/longitude coordinates of that point</returns> public override GlobalCoordinates FromEuclidian(EuclidianCoordinate xy) { double scaleFactor; double meridianConvergence; return(FromEuclidian(xy, out scaleFactor, out meridianConvergence)); }
/// <summary> /// Check whether another euclidian point belongs to the same projection /// </summary> /// <param name="other">The other point</param> /// <returns>True if they belong to the same projection, false otherwise</returns> public override bool IsSameProjection(EuclidianCoordinate other) { var utmOther = other as UtmCoordinate; if (null != utmOther) { return(utmOther.Grid.Equals(Grid)); } return(false); }
/// <summary> /// Compute the euclidian distance to another point /// </summary> /// <param name="other">The other point</param> /// <returns>The distance</returns> /// <exception cref="ArgumentException">Raised if the two points don't belong to the same projection</exception> public override double DistanceTo(EuclidianCoordinate other) { var obj = other as UtmCoordinate; if (obj == null || !Grid.Equals(obj.Grid)) { throw new ArgumentException(); } return(base.DistanceTo(other)); }
/// <summary> /// Compute the euclidian distance between two points given by rectangular coordinates /// Please note, that due to scaling effects this might be quite different from the true /// geodetic distance. To get a good approximation, you must divide this value by a /// scale factor. /// </summary> /// <param name="point1">The first point</param> /// <param name="point2">The second point</param> /// <returns>The distance between the points</returns> /// <exception cref="ArgumentException">Raised if the two points don't belong to the same projection</exception> /// <exception cref="ArgumentNullException">Raised if one of the points is null</exception> public double EuclidianDistance(EuclidianCoordinate point1, EuclidianCoordinate point2) { if (point1 == null || point2 == null) { throw new ArgumentNullException(); } if (!(point1.Projection.Equals(this) && point2.Projection.Equals(this))) { throw new ArgumentException(Properties.Resource.POINT_NOT_OWNED); } return(point1.DistanceTo(point2)); }
/// <summary> /// Convert a XY position on a Mercator map into global coordinates /// </summary> /// <param name="xy">The xy position on the Mercator map</param> /// <returns>The global coordinates</returns> public GlobalCoordinates XyToGlobalCoordinates(double[] xy) { var e = new EuclidianCoordinate(this, xy); return(FromEuclidian(e)); }
/// <summary> /// Get the latitude/longitude coordinates from the euclidian coordinates /// </summary> /// <param name="xy">The euclidien coordinates</param> /// <returns>The latitude/longitude coordinates of that point</returns> public override GlobalCoordinates FromEuclidian(EuclidianCoordinate xy) { return(new GlobalCoordinates(YToLatitude(xy.Y), XToLongitude(xy.X))); }
/// <summary> /// Compute a loxodromic path from start to end witha given number of points /// </summary> /// <param name="start">starting coordinates</param> /// <param name="end">ending coordinates</param> /// <param name="mercatorRhumbDistance">The distance of the two points on a Rhumb line on the Mercator projection</param> /// <param name="bearing">The constant course for the path</param> /// <param name="numberOfPoints">Number of points on the path (including start and end)</param> /// <exception cref="ArgumentOutOfRangeException">Thrown if the number of points is less than 2</exception> /// <returns>An array of points describing the loxodromic path from start to end</returns> public GlobalCoordinates[] CalculatePath( GlobalCoordinates start, GlobalCoordinates end, out double mercatorRhumbDistance, out Angle bearing, int numberOfPoints = 10) { mercatorRhumbDistance = 0; bearing = 0; if (numberOfPoints < 2) { throw new ArgumentOutOfRangeException(Properties.Resource.GEODETIC_PATH_MIN_2); } if (start == end || numberOfPoints == 2) { return new[] { start, end } } ; var cStart = ToEuclidian(start); var cEnd = ToEuclidian(end); var dist = EuclidianDistance(cStart, cEnd); var step = dist / (numberOfPoints - 1); var dx = (cEnd.X - cStart.X) / dist; var dy = (cEnd.Y - cStart.Y) / dist; bearing = 0; bearing.Radians = Math.Atan2(dx, dy); if (bearing < 0) { bearing += 360; } if (bearing == 90 || bearing == 270) { mercatorRhumbDistance = dist * ScaleFactor(start.Latitude.Degrees); } else { /* * This is based on a paper published by Miljenko Petrović * See: http://hrcak.srce.hr/file/24998 * */ var e2 = ReferenceGlobe.Eccentricity * ReferenceGlobe.Eccentricity; mercatorRhumbDistance = ReferenceGlobe.SemiMajorAxis / Math.Cos(bearing.Radians) * (((1 - e2 / 4.0) * (end.Latitude - start.Latitude).Radians) - e2 * (Math.Sin(2 * end.Latitude.Radians) - Math.Sin(2 * start.Latitude.Radians)) * 3.0 / 8.0); } var result = new GlobalCoordinates[numberOfPoints]; result[0] = start; result[numberOfPoints - 1] = end; for (var i = 1; i < numberOfPoints - 1; i++) { var point = new EuclidianCoordinate(this, cStart.X + i * dx * step, cStart.Y + i * dy * step); result[i] = FromEuclidian(point); } return(result); } }
/// <summary> /// Get the latitude/longitude coordinates from the euclidian coordinates /// </summary> /// <param name="xy">The euclidien coordinates</param> /// <returns>The latitude/longitude coordinates of that point</returns> public override GlobalCoordinates FromEuclidian(EuclidianCoordinate xy) { return(FromEuclidian(xy, out _, out _)); }
internal GlobalCoordinates FromEuclidian( EuclidianCoordinate xy, out double scaleFactor, out double meridianConvergence) { if (!(xy is UtmCoordinate point)) { throw new ArgumentException(Properties.Resource.NO_UTM_COORDINATE); } var hemi = point.Grid.IsNorthern ? 1 : -1; var northingOffset = point.Grid.IsNorthern ? 0.0 : Southern_Northing_Offset; var chi = (point.Y - northingOffset) / (MathConsts.K0 * _m.A); var eta = (point.X - MathConsts.E0) / (MathConsts.K0 * _m.A); var sum = 0.0; for (var j = 1; j <= 3; j++) { sum += (_m.Beta[j - 1] * Math.Sin(2.0 * j * chi) * Math.Cosh(2.0 * j * eta)); } var chitick = chi - sum; sum = 0.0; for (var j = 1; j <= 3; j++) { sum += (_m.Beta[j - 1] * Math.Cos(2.0 * j * chi) * Math.Sinh(2.0 * j * eta)); } var etatick = eta - sum; sum = 0.0; for (var j = 1; j <= 3; j++) { sum += (2.0 * j * _m.Beta[j - 1] * Math.Cos(2.0 * j * chi) * Math.Cosh(2.0 * j * eta)); } var sigmatick = 1.0 - sum; var tautick = 0.0; for (var j = 1; j <= 3; j++) { tautick += (2.0 * j * _m.Beta[j - 1] * Math.Sin(2.0 * j * chi) * Math.Sinh(2.0 * j * eta)); } var xi = Math.Asin(Math.Sin(chitick) / Math.Cosh(etatick)); var phi = xi; for (var j = 1; j <= 3; j++) { phi += (_m.Delta[j - 1] * Math.Sin(2.0 * j * xi)); } var lambda0 = point.Grid.CenterMeridian.Radians; var lambda = lambda0 + Math.Atan(Math.Sinh(etatick) / Math.Cos(chitick)); var k = ((MathConsts.K0 * _m.A) / ReferenceGlobe.SemiMajorAxis) * Math.Sqrt(((Math.Pow(Math.Cos(chitick), 2.0) + Math.Pow(Math.Sinh(etatick), 2.0)) / (sigmatick * sigmatick + tautick * tautick)) * (1.0 + Math.Pow(((1.0 - _m.N) / (1.0 + _m.N)) * Math.Tan(phi), 2.0))); var gamma = Math.Atan((tautick + sigmatick * Math.Tan(chitick) * Math.Tanh(etatick)) / (sigmatick - tautick * Math.Tan(chitick) * Math.Tanh(etatick))) * hemi; scaleFactor = k; meridianConvergence = gamma; return(new GlobalCoordinates(Angle.RadToDeg(phi), Angle.RadToDeg(lambda))); }
/// <summary> /// Get the latitude/longitude coordinates from the euclidian coordinates /// </summary> /// <param name="xy">The euclidien coordinates</param> /// <returns>The latitude/longitude coordinates of that point</returns> public abstract GlobalCoordinates FromEuclidian(EuclidianCoordinate xy);