Esempio n. 1
0
        /// <summary>
        /// Converts a grid coordinate to a geodetic coordinate.
        /// </summary>
        /// <param name="coordinate">The grid coordinate to convert.</param>
        /// <returns>The geodetic representation of the initial coordinate.</returns>
        public static GeodeticCoordinate GridToGeodetic(GridCoordinate coordinate)
        {
            var geoCoord = new GeodeticCoordinate();

            var    projection = coordinate.Projection;
            double flattening = projection.Ellipsoid.Flattening;
            double axis       = projection.Ellipsoid.SemiMajorAxis;

            double eSquare = flattening * (2d - flattening);
            double n       = flattening / (2d - flattening);
            double a       = axis / (1d + n) * (1 + n * n / 4 + n * n * n * n / 64d);

            // ReSharper disable InconsistentNaming
            double A = eSquare + eSquare * eSquare + eSquare * eSquare * eSquare + eSquare * eSquare * eSquare * eSquare;
            double B = -(7d * eSquare * eSquare + 17d * eSquare * eSquare * eSquare + 30d * eSquare * eSquare * eSquare * eSquare) / 6d;
            double C = (224d * eSquare * eSquare * eSquare + 889d * eSquare * eSquare * eSquare * eSquare) / 120d;
            double D = -(4279d * eSquare * eSquare * eSquare * eSquare) / 1260d;
            // ReSharper restore InconsistentNaming

            double delta1 = n / 2d - (2d * n * n) / 3d + (37d * n * n * n) / 96d - (n * n * n * n) / 360d;
            double delta2 = (n * n) / 48d + (n * n * n) / 15d - (437d * n * n * n * n) / 1440d;
            double delta3 = (17d * n * n * n) / 480d - (37d * n * n * n * n) / 840d;
            double delta4 = (4397d * n * n * n * n) / 161280d;

            double radMeridian = projection.CentralMeridianLon.ToRadians();
            double xi          = (coordinate.X - projection.FalseNorthing) / (projection.CentralMeridianScale * a);
            double eta         = (coordinate.Y - projection.FalseEasting) / (projection.CentralMeridianScale * a);

            double xiPrime = xi -
                             delta1 * Math.Sin(2d * xi) * Math.Cosh(2d * eta) -
                             delta2 * Math.Sin(4d * xi) * Math.Cosh(4d * eta) -
                             delta3 * Math.Sin(6d * xi) * Math.Cosh(6d * eta) -
                             delta4 * Math.Sin(8d * xi) * Math.Cosh(8d * eta);
            double etaPrime = eta -
                              delta1 * Math.Cos(2d * xi) * Math.Sinh(2d * eta) -
                              delta2 * Math.Cos(4d * xi) * Math.Sinh(4d * eta) -
                              delta3 * Math.Cos(6d * xi) * Math.Sinh(6d * eta) -
                              delta4 * Math.Cos(8d * xi) * Math.Sinh(8d * eta);

            double conformalLatitude = Math.Asin(Math.Sin(xiPrime) / Math.Cosh(etaPrime));
            double radLonDelta       = Math.Atan(Math.Sinh(etaPrime) / Math.Cos(xiPrime));

            double radLon = radMeridian + radLonDelta;
            double radLat = conformalLatitude + Math.Sin(conformalLatitude) * Math.Cos(conformalLatitude) *
                            (A +
                             B * Math.Pow(Math.Sin(conformalLatitude), 2d) +
                             C * Math.Pow(Math.Sin(conformalLatitude), 4d) +
                             D * Math.Pow(Math.Sin(conformalLatitude), 6d));

            geoCoord.Longitude = radLon.ToDegrees();
            geoCoord.Latitude  = radLat.ToDegrees();

            return(geoCoord);
        }
        /// <summary>
        /// Calculates the distance between two geodetic coordinates using the Haversine formula.
        /// </summary>
        /// <param name="coordinate1">The first coordinate.</param>
        /// <param name="coordinate2">The second coordinate.</param>
        /// <returns>The distance between the coordinates in kilometers.</returns>
        public static double Haversine(GeodeticCoordinate coordinate1, GeodeticCoordinate coordinate2)
        {
            double latDelta = (coordinate1.Latitude - coordinate2.Latitude) * (Math.PI / 180d);
            double lonDelta = (coordinate1.Longitude - coordinate2.Longitude) * (Math.PI / 180d);

            double a = Math.Sin(latDelta / 2) * Math.Sin(latDelta / 2) +
                       Math.Cos(coordinate1.Latitude * (Math.PI / 180d)) * Math.Cos(coordinate2.Latitude * (Math.PI / 180d)) *
                       Math.Sin(lonDelta / 2) * Math.Sin(lonDelta / 2);
            double c = 2 * Math.Atan2(Math.Sqrt(a), Math.Sqrt(1 - a));

            return(ApproxEarthRadius * c);
        }
Esempio n. 3
0
        /// <summary>
        /// Converts a geodetic coordinate to a grid coordinate.
        /// </summary>
        /// <param name="coordinate">The geodetic coordinate to convert.</param>
        /// <param name="projection">The projection to use in the conversion.</param>
        /// <returns>The grid representation of the initial coordinate.</returns>
        public static GridCoordinate GeodeticToGrid(GeodeticCoordinate coordinate, Projection projection)
        {
            var gridCoordinate = new GridCoordinate {
                Projection = projection
            };

            double flattening = projection.Ellipsoid.Flattening;
            double axis       = projection.Ellipsoid.SemiMajorAxis;

            double eSquare = flattening * (2d - flattening);
            double n       = flattening / (2d - flattening);
            double a       = axis / (1d + n) * (1 + n * n / 4 + n * n * n * n / 64d);

            // ReSharper disable InconsistentNaming
            double A = eSquare;
            double B = (5d * eSquare * eSquare - eSquare * eSquare * eSquare) / 6d;
            double C = (104d * eSquare * eSquare * eSquare - 45d * eSquare * eSquare * eSquare * eSquare) / 120d;
            double D = (1237d * eSquare * eSquare * eSquare * eSquare) / 1260d;
            // ReSharper restore InconsistentNaming

            double beta1 = n / 2d - (2d * n * n) / 3d + (5d * n * n * n) / 16d + (41d * n * n * n * n) / 180d;
            double beta2 = (13d * n * n) / 48d - (3d * n * n * n) / 5d + (557d * n * n * n * n) / 1440d;
            double beta3 = (61d * n * n * n) / 240d - (103d * n * n * n * n) / 140d;
            double beta4 = (49561d * n * n * n * n) / 161280d;

            double radLat      = coordinate.Latitude.ToRadians();
            double radLon      = coordinate.Longitude.ToRadians();
            double radMeridian = projection.CentralMeridianLon.ToRadians();
            double radLonDelta = radLon - radMeridian;

            double conformalLatitude = radLat - Math.Sin(radLat) * Math.Cos(radLat) * (A + B * Math.Pow(Math.Sin(radLat), 2d) + C * Math.Pow(Math.Sin(radLat), 4d) + D * Math.Pow(Math.Sin(radLat), 6d));

            double xiPrime  = Math.Atan(Math.Tan(conformalLatitude) / Math.Cos(radLonDelta)); // Bad naming but there is no name defined for this in the specs
            double etaPrime = Atanh(Math.Cos(conformalLatitude) * Math.Sin(radLonDelta));     // Bad naming but there is no name defined for this in the specs

            gridCoordinate.X = projection.CentralMeridianScale * a * (xiPrime +
                                                                      beta1 * Math.Sin(2d * xiPrime) * Math.Cosh(2d * etaPrime) +
                                                                      beta2 * Math.Sin(4d * xiPrime) * Math.Cosh(4d * etaPrime) +
                                                                      beta3 * Math.Sin(6d * xiPrime) * Math.Cosh(6d * etaPrime) +
                                                                      beta4 * Math.Sin(8d * xiPrime) * Math.Cosh(8d * etaPrime)) + projection.FalseNorthing;

            gridCoordinate.Y = projection.CentralMeridianScale * a * (etaPrime +
                                                                      beta1 * Math.Cos(2d * xiPrime) * Math.Sinh(2d * etaPrime) +
                                                                      beta2 * Math.Cos(4d * xiPrime) * Math.Sinh(4d * etaPrime) +
                                                                      beta3 * Math.Cos(6d * xiPrime) * Math.Sinh(6d * etaPrime) +
                                                                      beta4 * Math.Cos(8d * xiPrime) * Math.Sinh(8d * etaPrime)) + projection.FalseEasting;

            return(gridCoordinate);
        }
        /// <summary>
        /// Calculates a new coordinate from a bearing and distance from a specified coordinate.
        /// </summary>
        /// <param name="start">The initial coordinate.</param>
        /// <param name="bearing">The bearing from the initial coordinate in degrees.</param>
        /// <param name="distance">The distance from the initial coordinate in kilometers.</param>
        /// <returns>A new geodetic coordinate representing the new point.</returns>
        public static GeodeticCoordinate CoordFromDistance(GeodeticCoordinate start, double bearing, double distance)
        {
            distance = distance / ApproxEarthRadius;
            bearing *= Math.PI / 180d;

            double latStart = start.Latitude.ToRadians();
            double lonStart = start.Longitude.ToRadians();

            var latEnd = Math.Asin(Math.Sin(latStart) * Math.Cos(distance) +
                                   Math.Cos(latStart) * Math.Sin(distance) * Math.Cos(bearing));
            var lonEnd = lonStart + Math.Atan2(Math.Sin(bearing) * Math.Sin(distance) * Math.Cos(latStart),
                                               Math.Cos(distance) - Math.Sin(latStart) * Math.Sin(latEnd));

            lonEnd = (lonEnd + 3 * Math.PI) % (2 * Math.PI) - Math.PI;  // normalise to -180...+180

            return(new GeodeticCoordinate()
            {
                Latitude = latEnd.ToDegrees(), Longitude = lonEnd.ToDegrees()
            });
        }