예제 #1
0
        public void InitializationWithRadians()
        {
            var target = Longitude.FromRadians(Math.PI / 4);

            Assert.AreEqual(45.0, target.Degrees);
            Assert.AreEqual(Math.PI / 4, target.Radians);
        }
예제 #2
0
        /// <summary>
        /// transform the geodetic datum
        /// </summary>
        /// <param name="point">geodetic point</param>
        /// <param name="ellipsoid">source ellipsoid</param>
        /// <param name="da">semi-major difference of ellipsoids</param>
        /// <param name="df">flattening difference of ellipsoids</param>
        /// <param name="dX">translation along the X-axis</param>
        /// <param name="dY">translation along the Y-axis</param>
        /// <param name="dZ">translation along the Z-axis</param>
        /// <returns>geodetic point in new datum</returns>
        public static GeodeticCoord Transform(GeodeticCoord point, Ellipsoid ellipsoid, double da, double df, double dX, double dY, double dZ)
        {
            double B = point.Latitude.Radians;
            double L = point.Longitude.Radians;
            double H = point.Height;

            double sinB = Math.Sin(B);
            double cosB = Math.Cos(B);
            double sinL = Math.Sin(L);
            double cosL = Math.Cos(L);

            double a   = ellipsoid.SemiMajorAxis;
            double b_a = 1 - ellipsoid.Flattening;

            double ee = ellipsoid.ee;
            double w  = 1.0 - ee * sinB * sinB;
            double Rm = a * (1.0 - ee) / Math.Pow(w, 1.5);
            double Rn = a / Math.Sqrt(w);

            // formula is from http://earth-info.nga.mil/GandG/coordsys/datums/standardmolodensky.html
            double dB = (-dX * sinB * cosL - dY * sinB * sinL + dZ * cosB
                         + da * (Rn * ee * sinB * cosB) / a
                         + df * (Rm / b_a + Rn * b_a) * sinB * cosB) / (Rm + H);
            double dL = (-dX * sinL + dY * cosL) / ((Rn + H) * cosB);
            double dH = dX * cosB * cosL + dY * cosB * sinL + dZ * sinB
                        - da * a / Rn + df * Rn * b_a * sinB * sinB;

            return(new GeodeticCoord(Latitude.FromRadians(B + dB), Longitude.FromRadians(L + dL), H + dH));
        }
예제 #3
0
        /// <summary>
        /// Conversion of space rectangular coordinate to geodetic coordinate.
        /// </summary>
        /// <param name="ellipsoid">ellipsoid</param>
        /// <param name="X">X component of space rectangular coordinate</param>
        /// <param name="Y">Y component of space rectangular coordinate</param>
        /// <param name="Z">Z component of space rectangular coordinate</param>
        /// <param name="lng">longitude</param>
        /// <param name="lat">latitude</param>
        /// <param name="hgt">ellipsoid height</param>
        public static void XYZ_BLH(Ellipsoid ellipsoid, double X, double Y, double Z, out Latitude lat, out Longitude lng, out double hgt)
        {
            double a  = ellipsoid.a;
            double ee = ellipsoid.ee;

            double rL, rB, rB0;

            //求解经度
            rL = Math.Atan2(Y, X);

            // 迭代精度为1E-5秒
            rB  = Math.Atan(Z / Math.Sqrt(X * X + Y * Y));
            rB0 = rB + 1;
            while (Math.Abs(rB - rB0) > Settings.Epsilon5)
            {
                rB0 = rB;
                double temp = a * ee * Math.Tan(rB0) / Math.Sqrt(1 + (1 - ee) * Math.Pow(Math.Tan(rB0), 2));
                rB = Math.Atan((Z + temp) / Math.Sqrt(X * X + Y * Y));
            }

            lng = Longitude.FromRadians(rL);
            lat = Latitude.FromRadians(rB);

            hgt = Math.Sqrt(X * X + Y * Y) / Math.Cos(rB) - a / Math.Sqrt(1 - ee * Math.Pow(Math.Sin(rB), 2));
        }
예제 #4
0
        /// <summary>
        /// transform the geodetic datum
        /// </summary>
        /// <param name="point">geodetic point</param>
        /// <param name="from">source ellipsoid</param>
        /// <param name="to">target ellipsoid</param>
        /// <param name="para">three translation parameters</param>
        /// <returns>geodetic point in new datum</returns>
        public static GeodeticCoord Transform(GeodeticCoord point, Ellipsoid from, Ellipsoid to, TransParameters para)
        {
            double B = point.Latitude.Radians;
            double L = point.Longitude.Radians;
            double H = point.Height;

            double sinB = Math.Sin(B);
            double cosB = Math.Cos(B);
            double sinL = Math.Sin(L);
            double cosL = Math.Cos(L);

            double a   = from.SemiMajorAxis;
            double b_a = 1 - from.Flattening;
            double da  = to.SemiMajorAxis - from.SemiMajorAxis;
            double df  = to.Flattening - from.Flattening;

            double ee = from.ee;
            double w  = 1.0 - ee * sinB * sinB;
            double Rm = a * (1.0 - ee) / Math.Pow(w, 1.5);
            double Rn = a / Math.Sqrt(w);

            // formula is from http://earth-info.nga.mil/GandG/coordsys/datums/standardmolodensky.html
            double dB = (-para.Tx * sinB * cosL - para.Ty * sinB * sinL + para.Tz * cosB
                         + da * (Rn * ee * sinB * cosB) / a
                         + df * (Rm / b_a + Rn * b_a) * sinB * cosB) / (Rm + H);
            double dL = (-para.Tx * sinL + para.Ty * cosL) / ((Rn + H) * cosB);
            double dH = para.Tx * cosB * cosL + para.Ty * cosB * sinL + para.Tz * sinB
                        - da * a / Rn + df * Rn * b_a * sinB * sinB;

            return(new GeodeticCoord(Latitude.FromRadians(B + dB), Longitude.FromRadians(L + dL), H + dH));
        }
        /// <summary>
        /// converts geodetic coordinates to Lambert conformal conic projection coordinates.
        /// </summary>
        /// <param name="lng">longitude</param>
        /// <param name="lat">latitude</param>
        /// <param name="easting">easting</param>
        /// <param name="northing">northing</param>
        public override void Forward(Latitude lat, Longitude lng, out double northing, out double easting)
        {
            double rho;

            double rB = lat.Radians;
            double rL = lng.Radians;

            double temp = Math.Abs(Math.Abs(rB) - Math.PI / 2);

            if (temp > 1E-10)
            {
                double t = Get_t(rB);
                rho = SemiMajor * _F * Math.Pow(t, _n);
            }
            else
            {
                temp = rB * _n;
                if (temp <= 0)
                {
                    throw new GeodeticException("");
                }
                rho = 0;
            }

            Longitude L = Longitude.FromRadians(rL - CenteralMaridian.Radians);

            L.Normalize();
            double gamma = _n * L.Radians;

            easting  = rho * Math.Sin(gamma) + FalseEasting;
            northing = _rho - rho * Math.Cos(gamma) + FalseNorthing;
        }
예제 #6
0
        /// <summary>
        /// Directed solution of geodetic problem from start point, distance and azimuth to end point and inverse azimuth.
        /// </summary>
        /// <param name="start">start point of geodesic</param>
        /// <param name="distance">distance of geodesic</param>
        /// <param name="bearing">azimuth of geodesic</param>
        /// <param name="end">end point of geodesic</param>
        /// <param name="ivBearing">inverse azimuth of geodesic</param>
        protected override void Direct(GeoPoint start, double distance, Angle bearing, out GeoPoint end, out Angle ivBearing)
        {
            double lat1 = start.Latitude.Radians;
            double brng = bearing.Radians;
            double dR   = distance / R;

            var lat2 = Math.Asin(Math.Sin(lat1) * Math.Cos(dR) + Math.Cos(lat1) * Math.Sin(dR) * Math.Cos(brng));
            var lng2 = start.Longitude.Radians + Math.Atan2(Math.Sin(brng) * Math.Sin(dR) * Math.Cos(lat1),
                                                            Math.Cos(dR) - Math.Sin(lat1) * Math.Sin(lat2));

            end       = new GeoPoint(Latitude.FromRadians(lat2), Longitude.FromRadians(lng2));
            ivBearing = GetBearing(end, start);
        }
        /// <summary>
        /// converts Lambert conformal conic projection coordinates to geodetic coordinates.
        /// </summary>
        /// <param name="easting">easting</param>
        /// <param name="northing">northing</param>
        /// <param name="lng">longitude</param>
        /// <param name="lat">latitude</param>
        public override void Reverse(double northing, double easting, out Latitude lat, out Longitude lng)
        {
            double rho;
            double temp;

            double dX = easting - FalseEasting;
            double dY = _rho - northing + FalseNorthing;

            if (_n > 0)
            {
                rho  = Math.Sqrt(dX * dX + dY * dY);
                temp = 1.0;
            }
            else
            {
                rho  = -Math.Sqrt(dX * dX + dY * dY);
                temp = -1.0;
            }

            double gamma = 0.0;

            if (rho != 0)
            {
                gamma = Math.Atan2((temp * dX), (temp * dY));
            }

            if ((rho != 0) || (_n > 0.0))
            {
                double t = Math.Pow((rho / (SemiMajor * _F)), 0.1 * _n);
                lat = Latitude.FromRadians(phi2z(t, out long flag));
                if (flag != 0)
                {
                    throw new ArgumentException();
                }
            }
            else
            {
                lat = new Latitude(-90.0);
            }

            lng = Longitude.FromRadians(gamma / _n + CenteralMaridian.Radians);
            lng.Normalize();
        }
예제 #8
0
        /// <summary>
        /// Converts the current instance to a geodetic (latitude/longitude) coordinate using the specified ellipsoid.
        /// </summary>
        /// <param name="ellipsoid">The ellipsoid.</param>
        /// <returns>A <strong>Position</strong> object containing the converted result.</returns>
        /// <remarks>The conversion formula will convert the Cartesian coordinate to
        /// latitude and longitude using the WGS1984 ellipsoid (the default ellipsoid for
        /// GPS coordinates).  The resulting three-dimensional coordinate is accurate to within two millimeters
        /// (2 mm).</remarks>
        public Position3D ToPosition3D(Ellipsoid ellipsoid)
        {
            if (ellipsoid == null)
            {
                throw new ArgumentNullException("ellipsoid");
            }

            #region New code

            /*
             * % ECEF2LLA - convert earth-centered earth-fixed (ECEF)
             * %            cartesian coordinates to latitude, longitude,
             * %            and altitude
             * %
             * % USAGE:
             * % [lat, lon, alt] = ecef2lla(x, y, z)
             * %
             * % lat = geodetic latitude (radians)
             * % lon = longitude (radians)
             * % alt = height above WGS84 ellipsoid (m)
             * % x = ECEF X-coordinate (m)
             * % y = ECEF Y-coordinate (m)
             * % z = ECEF Z-coordinate (m)
             * %
             * % Notes: (1) This function assumes the WGS84 model.
             * %        (2) Latitude is customary geodetic (not geocentric).
             * %        (3) Inputs may be scalars, vectors, or matrices of the same
             * %            size and shape. Outputs will have that same size and shape.
             * %        (4) Tested but no warranty; use at your own risk.
             * %        (5) Michael Kleder, April 2006
             *
             * function [lat, lon, alt] = ecef2lla(x, y, z)
             *
             * % WGS84 ellipsoid constants:
             * a = 6378137;
             * e = 8.1819190842622e-2;
             *
             * % calculations:
             * b   = sqrt(a^2*(1-e^2));
             * ep  = sqrt((a^2-b^2)/b^2);
             * p   = sqrt(x.^2+y.^2);
             * th  = atan2(a*z, b*p);
             * lon = atan2(y, x);
             * lat = atan2((z+ep^2.*b.*sin(th).^3), (p-e^2.*a.*cos(th).^3));
             * N   = a./sqrt(1-e^2.*sin(lat).^2);
             * alt = p./cos(lat)-N;
             *
             * % return lon in range [0, 2*pi)
             * lon = mod(lon, 2*pi);
             *
             * % correct for numerical instability in altitude near exact poles:
             * % (after this correction, error is about 2 millimeters, which is about
             * % the same as the numerical precision of the overall function)
             *
             * k=abs(x)<1 & abs(y)<1;
             * alt(k) = abs(z(k))-b;
             *
             * return
             */

            double x = _x.ToMeters().Value;
            double y = _y.ToMeters().Value;
            double z = _z.ToMeters().Value;

            //% WGS84 ellipsoid constants:
            //a = 6378137;

            double a = ellipsoid.EquatorialRadius.ToMeters().Value;

            //e = 8.1819190842622e-2;

            double e = ellipsoid.Eccentricity;

            //% calculations:
            //b   = sqrt(a^2*(1-e^2));

            double b = Math.Sqrt(Math.Pow(a, 2) * (1 - Math.Pow(e, 2)));

            //ep  = sqrt((a^2-b^2)/b^2);

            double ep = Math.Sqrt((Math.Pow(a, 2) - Math.Pow(b, 2)) / Math.Pow(b, 2));

            //p   = sqrt(x.^2+y.^2);

            double p = Math.Sqrt(Math.Pow(x, 2) + Math.Pow(y, 2));

            //th  = atan2(a*z, b*p);

            double th = Math.Atan2(a * z, b * p);

            //lon = atan2(y, x);

            double lon = Math.Atan2(y, x);

            //lat = atan2((z+ep^2.*b.*sin(th).^3), (p-e^2.*a.*cos(th).^3));

            double lat = Math.Atan2((z + Math.Pow(ep, 2) * b * Math.Pow(Math.Sin(th), 3)), (p - Math.Pow(e, 2) * a * Math.Pow(Math.Cos(th), 3)));

            //N   = a./sqrt(1-e^2.*sin(lat).^2);

            double n = a / Math.Sqrt(1 - Math.Pow(e, 2) * Math.Pow(Math.Sin(lat), 2));

            //alt = p./cos(lat)-N;

            double alt = p / Math.Cos(lat) - n;

            //% return lon in range [0, 2*pi)
            //lon = mod(lon, 2*pi);

            lon = lon % (2 * Math.PI);

            //% correct for numerical instability in altitude near exact poles:
            //% (after this correction, error is about 2 millimeters, which is about
            //% the same as the numerical precision of the overall function)

            //k=abs(x)<1 & abs(y)<1;

            bool k = Math.Abs(x) < 1.0 && Math.Abs(y) < 1.0;

            //alt(k) = abs(z(k))-b;

            if (k)
            {
                alt = Math.Abs(z) - b;
            }

            //return

            return(new Position3D(
                       Distance.FromMeters(alt),
                       Latitude.FromRadians(lat),
                       Longitude.FromRadians(lon)));

            #endregion New code
        }
예제 #9
0
        /// <summary>
        /// converts Lambert equal-area conic projection coordinates to geodetic coordinates.
        /// </summary>
        /// <param name="northing">northing</param>
        /// <param name="easting">easting</param>
        /// <param name="lat">latitude</param>
        /// <param name="lng">longitude</param>
        public override void Reverse(double northing, double easting, out Latitude lat, out Longitude lng)
        {
            //STEP 1
            double east  = (easting - FalseEasting) / ScaleFactor;
            double north = (northing - FalseNorthing) / ScaleFactor;

            double rLng = Math.PI + Math.Atan(east / north) * (_hemisphere == 'S' ? 1 : -1);

            lng = (double.IsNaN(rLng) ? new Longitude(0) : Longitude.FromRadians(rLng));

            // SET TO 0 or it will equate to 180
            if (north >= 0 && east == 0 && _hemisphere == 'S')
            {
                lng = new Longitude(0);
            }

            // SET TO 0 or it will equate to 180
            if (north < 0 && east == 0 && _hemisphere == 'N')
            {
                lng = new Longitude(0);
            }

            lng += CenteralMaridian;
            lng.Normalize();

            //STEP 2
            if (north == 0)
            {
                north = 1;
            }
            double temp = Math.PI + Math.Atan(east / north) * (_hemisphere == 'S' ? 1 : -1);

            //STEP 3
            double a  = SemiMajor;
            double es = SquaredEccentricity;
            double e  = Math.Sqrt(es);
            double b  = a * Math.Sqrt(1 - es);
            double K  = (2 * Math.Pow(a, 2) / b) * Math.Pow(((1 - e) / (1 + e)), (e / 2));

            //STEP 4
            double kCos = K * Math.Abs(Math.Cos(temp));
            double q    = Math.Log(Math.Abs(north) / kCos) / Math.Log(Math.E) * -1;

            //STEP 5
            double rLat = 2 * Math.Atan(Math.Pow(Math.E, q)) - Math.PI / 2;
            double rB   = Math.PI / 2;

            while (Math.Abs(rLat - rB) > Settings.Epsilon5)
            {
                if (double.IsInfinity(rLat))
                {
                    break;
                }
                rB = rLat;

                //STEP 6
                double sLat    = Math.Sin(rLat);
                double bracket = (1 + sLat) / (1 - sLat) * Math.Pow((1 - e * sLat) / (1 + e * sLat), e);
                double fLat    = -q + 1 / 2.0 * Math.Log(bracket);
                double fLat2   = (1 - Math.Pow(e, 2)) / ((1 - Math.Pow(e, 2) * Math.Pow(sLat, 2)) * Math.Cos(rLat));

                //STEP 7
                rLat -= fLat / fLat2;
            }
            if (!double.IsInfinity(rLat))
            {
                rB = rLat;
            }

            //NaN signals poles
            lat = double.IsNaN(rB) ? new Latitude(90) : Latitude.FromRadians(rB);
            if (_hemisphere == 'S')
            {
                lat = -lat;
            }
        }
예제 #10
0
        /// <summary>
        /// Directed solution of geodetic problem from start point, distance and azimuth to end point and inverse azimuth.
        /// </summary>
        /// <param name="start">start point of geodesic</param>
        /// <param name="distance">distance of geodesic</param>
        /// <param name="bearing">azimuth of geodesic</param>
        /// <param name="end">end point of geodesic</param>
        /// <param name="ivBearing">inverse azimuth of geodesic</param>
        protected override void Direct(GeoPoint start, double distance, Angle bearing, out GeoPoint end, out Angle ivBearing)
        {
            double a   = start.Ellipsoid.a;
            double es  = start.Ellipsoid.ee;
            double ses = start.Ellipsoid._ee;

            double B1 = start.Latitude.Radians;
            double L1 = start.Longitude.Radians;
            double A1 = bearing.Radians;

            double u1 = Math.Atan(Math.Sqrt(1 - es) * Math.Tan(B1));                             //u1 is (-90, 90)
            double m  = Math.Cos(u1) * Math.Sin(A1);                                             //sin(m)

            m = Math.Atan(m / Math.Sqrt(1 - m * m));                                             //m is (-90, 90)
            if (m < 0)
            {
                m += 2 * Math.PI;
            }

            double M = Math.Atan(Math.Tan(u1) / Math.Cos(A1));                                   //M is (-90, 90)

            if (M < 0)
            {
                M += Math.PI;                                                                    //change M to (0, 180)
            }
            //compute cofficients
            double KK    = ses * Math.Pow(Math.Cos(m), 2);
            double alpha = Math.Sqrt(1 + ses) * (1 - KK / 4 + 7 * KK * KK / 64 - 15 * Math.Pow(KK, 3) / 256) / a;
            double beta  = KK / 4 - KK * KK / 8 + 37 * Math.Pow(KK, 3) / 512;
            double gamma = KK * KK * (1 - KK) / 128;

            //loop for compute sigma
            double sigma, temp;

            sigma = alpha * distance;
            temp  = 0;
            while (Math.Abs(temp - sigma) > Settings.Epsilon5)                                  //精度0.00001秒
            {
                temp  = sigma;
                sigma = alpha * distance + beta * Math.Sin(sigma) * Math.Cos(2 * M + sigma) + gamma * Math.Sin(2 * sigma) * Math.Cos(4 * M + 2 * sigma);
            }

            double A2 = Math.Atan(Math.Tan(m) / Math.Cos(M + sigma));                            //A2 is (-90, 90)

            if (A2 < 0)
            {
                A2 += Math.PI;
            }
            if (A1 < Math.PI)
            {
                A2 += Math.PI;
            }
            ivBearing = Angle.FromRadians(A2);

            double   u2 = Math.Atan(-Math.Cos(A2) * Math.Tan(M + sigma));                        //u2 is (-90, 90)
            Latitude B  = Latitude.FromRadians(Math.Atan(Math.Sqrt(1 + ses) * Math.Tan(u2)));    //B in (-90, 90)

            double lamda1;

            lamda1 = Math.Atan(Math.Sin(u1) * Math.Tan(A1));                                     //lamda1
            if (lamda1 < 0)
            {
                lamda1 += Math.PI;
            }
            if (m >= Math.PI)
            {
                lamda1 += Math.PI;
            }

            double lamda2;                                                                       //lamda2

            lamda2 = Math.Atan(Math.Sin(u2) * Math.Tan(A2));
            if (Math.Abs(lamda2) < Math.Exp(-15))
            {
                lamda2 = 0;                                                                      //当A2为180度时,上式因舍入误差使得lamda2为负
            }
            if (lamda2 < 0)
            {
                lamda2 += Math.PI;
            }
            if (m >= Math.PI)
            {
                if (M + sigma < Math.PI)
                {
                    lamda2 += Math.PI;
                }
            }
            else
            {
                if (M + sigma > Math.PI)
                {
                    lamda2 += Math.PI;
                }
            }

            KK    = es * Math.Pow(Math.Cos(m), 2);
            alpha = es / 2 + es * es / 8 + Math.Pow(es, 3) / 16 - es * (1 + es) * KK / 16 + 3 * es * KK * KK / 128;
            beta  = es * (1 + es) * KK / 16 - es * KK * KK / 32;
            gamma = es * KK * KK / 256;

            double dL = lamda2 - lamda1 - Math.Sin(m) * (alpha * sigma + beta * Math.Sin(sigma) * Math.Cos(2 * M + sigma) + gamma * Math.Sin(2 * sigma) * Math.Cos(4 * M + 2 * sigma));

            end = new GeoPoint(B, Longitude.FromRadians(L1 + dL));
        }