/// <summary>
        /// Converts UTM coordinate to Signed Degree Lat/Long
        /// </summary>
        /// <param name="utm">utm</param>
        /// <returns>Coordinate</returns>
        /// <example>
        /// The following example creates (converts to) a signed degree lat long based on a UTM object.
        /// <code>
        /// UniversalTransverseMercator utm = new UniversalTransverseMercator("T", 32, 233434, 234234);
        /// double[] signed = UniversalTransverseMercator.ConvertUTMtoSignedDegree(utm);
        /// Coordinate c = new Coordinate(signed[0], signed[1], new EagerLoad(false));
        /// Console.WriteLine(c); //N 2º 7' 2.332" E 6º 36' 12.653"
        /// </code>
        /// </example>
        public static double[] ConvertUTMtoSignedDegree(UniversalTransverseMercator utm)
        {
            bool southhemi = false;

            Regex upsCheck = new Regex("[AaBbYyZz]");

            if (upsCheck.IsMatch(utm.latZone))
            {
                Coordinate c = UPS.UPS_To_Geodetic(utm, new EagerLoad(false));
                return(new double[] { c.Latitude.ToDouble(), c.Longitude.ToDouble() });
            }

            if (utm.latZone == "A" || utm.latZone == "B" || utm.latZone == "C" || utm.latZone == "D" || utm.latZone == "E" || utm.latZone == "F" || utm.latZone == "G" || utm.latZone == "H" || utm.latZone == "J" ||
                utm.latZone == "K" || utm.latZone == "L" || utm.latZone == "M")
            {
                southhemi = true;
            }

            double cmeridian;

            double x = utm.Easting - 500000.0;
            double UTMScaleFactor = 0.9996;

            x /= UTMScaleFactor;

            /* If in southern hemisphere, adjust y accordingly. */
            double y = utm.Northing;

            if (southhemi)
            {
                y -= 10000000.0;
            }

            y /= UTMScaleFactor;

            cmeridian = UTMCentralMeridian(utm.LongZone);

            double[] signed = UTMtoSigned(x, y, cmeridian, utm.equatorial_radius, utm.inverse_flattening);


            return(signed);
        }
        /// <summary>
        /// Converts UTM coordinate to Lat/Long
        /// </summary>
        /// <param name="utm">utm</param>
        /// <param name="eagerLoad">EagerLoad</param>
        /// <returns>Coordinate</returns>
        /// <example>
        /// The following example creates (converts to) a geodetic Coordinate object based on a UTM object.
        /// Performance is maximized by turning off EagerLoading.
        /// <code>
        /// EagerLoad el = new EagerLoad(false);
        /// UniversalTransverseMercator utm = new UniversalTransverseMercator("T", 32, 233434, 234234);
        /// Coordinate c = UniversalTransverseMercator.ConvertUTMtoLatLong(utm, el);
        /// Console.WriteLine(c); //N 2º 7' 2.332" E 6º 36' 12.653"
        /// </code>
        /// </example>
        public static Coordinate ConvertUTMtoLatLong(UniversalTransverseMercator utm, EagerLoad eagerLoad)
        {
            bool  southhemi = false;
            Regex upsCheck  = new Regex("[AaBbYyZz]");

            if (upsCheck.IsMatch(utm.latZone))
            {
                return(UPS.UPS_To_Geodetic(utm, eagerLoad));
            }

            Regex regex = new Regex("[CcDdEeFfGgHhJjKkLlMm]");

            if (regex.IsMatch(utm.latZone))
            {
                southhemi = true;
            }

            double cmeridian;

            double x = utm.Easting - 500000.0;
            double UTMScaleFactor = 0.9996;

            x /= UTMScaleFactor;

            /* If in southern hemisphere, adjust y accordingly. */
            double y = utm.Northing;

            if (southhemi)
            {
                y -= 10000000.0;
            }

            y /= UTMScaleFactor;

            cmeridian = UTMCentralMeridian(utm.LongZone);

            Coordinate c = UTMtoLatLong(x, y, cmeridian, utm.equatorial_radius, utm.inverse_flattening, eagerLoad);

            return(c);
        }
        /// <summary>
        /// Assigns UTM values based of Lat/Long
        /// </summary>
        /// <param name="lat">DD Latitude</param>
        /// <param name="longi">DD longitude</param>
        /// <param name="utm">UTM Object to modify</param>
        /// <param name="szone">specified zone (for under/over projection</param>
        internal void ToUTM(double lat, double longi, UniversalTransverseMercator utm, int?szone = null)
        {
            //Switch to UPS
            if (lat < -80 || lat > 84)
            {
                UPS ups = new UPS();
                ups.Geodetic_To_UPS(lat, longi, utm);
                systemType = UTM_Type.UPS;
                return;
            }
            else
            {
                systemType = UTM_Type.UTM;
            }

            //Within UTM BOUNDS
            string letter   = "";
            double easting  = 0;
            double northing = 0;
            int    zone;

            if (szone == null)
            {
                zone = (int)Math.Floor(longi / 6 + 31);
            }
            else
            {
                zone = szone.Value;
            }
            if (lat < -72)
            {
                letter = "C";
            }
            else if (lat < -64)
            {
                letter = "D";
            }
            else if (lat < -56)
            {
                letter = "E";
            }
            else if (lat < -48)
            {
                letter = "F";
            }
            else if (lat < -40)
            {
                letter = "G";
            }
            else if (lat < -32)
            {
                letter = "H";
            }
            else if (lat < -24)
            {
                letter = "J";
            }
            else if (lat < -16)
            {
                letter = "K";
            }
            else if (lat < -8)
            {
                letter = "L";
            }
            else if (lat < 0)
            {
                letter = "M";
            }
            else if (lat < 8)
            {
                letter = "N";
            }
            else if (lat < 16)
            {
                letter = "P";
            }
            else if (lat < 24)
            {
                letter = "Q";
            }
            else if (lat < 32)
            {
                letter = "R";
            }
            else if (lat < 40)
            {
                letter = "S";
            }
            else if (lat < 48)
            {
                letter = "T";
            }
            else if (lat < 56)
            {
                letter = "U";
            }
            else if (lat < 64)
            {
                letter = "V";
            }
            else if (lat < 72)
            {
                letter = "W";
            }
            else
            {
                letter = "X";
            }

            double a = utm.equatorial_radius;
            double f = 1.0 / utm.inverse_flattening;
            double b = a * (1 - f);   // polar radius

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

            double drad = Math.PI / 180;
            double k0   = 0.9996;

            double phi = lat * drad;                              // convert latitude to radians
            double lng = longi * drad;                            // convert longitude to radians
            double utmz;

            if (szone == null)
            {
                utmz = 1 + Math.Floor((longi + 180) / 6.0);
            }
            else
            {
                utmz = szone.Value;
            }
            // longitude to utm zone
            double zcm = 3 + 6.0 * (utmz - 1) - 180;                     // central meridian of a zone
            // this gives us zone A-B for below 80S
            double esq  = (1 - (b / a) * (b / a));
            double e0sq = e * e / (1 - Math.Pow(e, 2));
            double M    = 0;

            double N = a / Math.Sqrt(1 - Math.Pow(e * Math.Sin(phi), 2));
            double T = Math.Pow(Math.Tan(phi), 2);
            double C = e0sq * Math.Pow(Math.Cos(phi), 2);
            double A = (longi - zcm) * drad * Math.Cos(phi);

            // calculate M (USGS style)
            M = phi * (1 - esq * (1.0 / 4.0 + esq * (3.0 / 64.0 + 5.0 * esq / 256.0)));
            M = M - Math.Sin(2.0 * phi) * (esq * (3.0 / 8.0 + esq * (3.0 / 32.0 + 45.0 * esq / 1024.0)));
            M = M + Math.Sin(4.0 * phi) * (esq * esq * (15.0 / 256.0 + esq * 45.0 / 1024.0));
            M = M - Math.Sin(6.0 * phi) * (esq * esq * esq * (35.0 / 3072.0));
            M = M * a;     //Arc length along standard meridian

            double M0 = 0; // if another point of origin is used than the equator

            // Calculate the UTM values...
            // first the easting
            var x = k0 * N * A * (1 + A * A * ((1 - T + C) / 6 + A * A * (5 - 18 * T + T * T + 72.0 * C - 58 * e0sq) / 120.0)); //Easting relative to CM

            x = x + 500000;                                                                                                     // standard easting

            // Northing

            double y  = k0 * (M - M0 + N * Math.Tan(phi) * (A * A * (1 / 2.0 + A * A * ((5 - T + 9 * C + 4 * C * C) / 24.0 + A * A * (61 - 58 * T + T * T + 600 * C - 330 * e0sq) / 720.0)))); // first from the equator
            double yg = y + 10000000;                                                                                                                                                          //yg = y global, from S. Pole

            if (y < 0)
            {
                y = 10000000 + y;   // add in false northing if south of the equator
            }

            //Last zone is 60, but will hit 61 at 180 degrees exactly. Reset to 1.
            if (zone == 61)
            {
                zone = 1;
            }

            easting  = x;
            northing = y;

            utm.latZone    = letter;
            utm.longZone   = zone;
            utm.easting    = easting;
            utm.northing   = northing;
            utm.systemType = systemType;
        }