public void GetItmCoordinates_ShouldConvertToNorthEast()
        {
            var northEast = new NorthEast { North = 3, East = 4 };
            var converter = Substitute.For<ICoordinatesConverter>();
            converter.Wgs84ToItm(Arg.Any<LatLon>()).Returns(northEast);
            _itmGridController = new ItmGridController(converter);

            var response = _itmGridController.GetItmCoordinates(1, 2);

            Assert.AreEqual(northEast.North, response.North);
            Assert.AreEqual(northEast.East, response.East);
        }
        /// <summary>
        /// Local Grid to Lat/Lon conversion
        /// </summary>
        /// <param name="northEast"></param>
        /// <param name="from"></param>
        /// <param name="to"></param>
        /// <returns></returns>
        private LatLon Grid2LatLon(NorthEast northEast, string from, string to)
        {
            double y = northEast.North + Grids[from].FalseNorthing;
            double x = northEast.East - Grids[from].FalseEasting;
            double M = y / Grids[from].ScaleFactor;

            double a = Datums[to].EquatorialEarthRadius;
            double b = Datums[to].PolarEarthRadius;
            double e = Datums[to].Eccentricity;
            double esq = Datums[to].EccentricitySquared;

            double mu = M / (a * (1 - e * e / 4 - 3 * Math.Pow(e, 4) / 64 - 5 * Math.Pow(e, 6) / 256));

            double ee = Math.Sqrt(1 - esq);
            double e1 = (1 - ee) / (1 + ee);
            double j1 = 3 * e1 / 2 - 27 * e1 * e1 * e1 / 32;
            double j2 = 21 * e1 * e1 / 16 - 55 * e1 * e1 * e1 * e1 / 32;
            double j3 = 151 * e1 * e1 * e1 / 96;
            double j4 = 1097 * e1 * e1 * e1 * e1 / 512;

            // Footprint Latitude
            double fp = mu + j1 * Math.Sin(2 * mu) + j2 * Math.Sin(4 * mu) + j3 * Math.Sin(6 * mu) + j4 * Math.Sin(8 * mu);

            double sinfp = Math.Sin(fp);
            double cosfp = Math.Cos(fp);
            double tanfp = sinfp / cosfp;
            double eg = (e * a / b);
            double eg2 = eg * eg;
            double C1 = eg2 * cosfp * cosfp;
            double T1 = tanfp * tanfp;
            double R1 = a * (1 - e * e) / Math.Pow(1 - (e * sinfp) * (e * sinfp), 1.5);
            double N1 = a / Math.Sqrt(1 - (e * sinfp) * (e * sinfp));
            double D = x / (N1 * Grids[from].ScaleFactor);

            double Q1 = N1 * tanfp / R1;
            double Q2 = D * D / 2;
            double Q3 = (5 + 3 * T1 + 10 * C1 - 4 * C1 * C1 - 9 * eg2 * eg2) * (D * D * D * D) / 24;
            double Q4 = (61 + 90 * T1 + 298 * C1 + 45 * T1 * T1 - 3 * C1 * C1 - 252 * eg2 * eg2) * (D * D * D * D * D * D) / 720;
            double Q5 = D;
            double Q6 = (1 + 2 * T1 + C1) * (D * D * D) / 6;
            double Q7 = (5 - 2 * C1 + 28 * T1 - 3 * C1 * C1 + 8 * eg2 * eg2 + 24 * T1 * T1) * (D * D * D * D * D) / 120;
            // result lon
            return new LatLon
            {
                Latitude = fp - Q1 * (Q2 - Q3 + Q4),
                Longitude = Grids[from].CentralLongitude + (Q5 - Q6 + Q7) / cosfp
            };
        }
        /// <summary>
        /// Israel New Grid (ITM) to WGS84 conversion
        /// </summary>
        /// <param name="northEast">North East Coordinates in ITM grid</param>
        /// <returns>Latitide and Longitude in WGS84</returns>
        public LatLon ItmToWgs84(NorthEast northEast)
        {
            // 1. Local Grid (ITM) -> GRS80
            var latLon80 = Grid2LatLon(northEast, ITM, GRS80);

            // 2. Molodensky GRS80->WGS84
            var latLon84 = Molodensky(latLon80, GRS80, WGS84);

            // final results
            return ToDegrees(latLon84);
        }
        /// <summary>
        /// Israel Old Grid (ICS) to WGS84 conversion
        /// </summary>
        /// <param name="northEast">North East Coordinates in ICS grid</param>
        /// <returns>Latitide and Longitude in WGS84</returns>
        public LatLon IcsToWgs84(NorthEast northEast)
        {
            // 1. Local Grid (ICS) -> Clark_1880_modified
            var latLon80 = Grid2LatLon(northEast, ICS, CLARK80M);

            // 2. Molodensky Clark_1880_modified -> WGS84
            var latLon84 = Molodensky(latLon80, CLARK80M, WGS84);

            // final results
            return ToDegrees(latLon84);
        }