public override MathTransform Inverse()
 {
     if (_inverse == null)
     {
         _inverse = new HotineObliqueMercatorProjection(_Parameters.ToProjectionParameter(), this);
     }
     return(_inverse);
 }
        public HotineObliqueMercatorProjection(IEnumerable<ProjectionParameter> parameters, HotineObliqueMercatorProjection inverse)
            : base(parameters, inverse)
        {
            Authority = "EPSG";
            AuthorityCode = 9812;
            Name = "Hotine_Oblique_Mercator";

            _azimuth = Degrees2Radians(_Parameters.GetParameterValue("azimuth"));
            var rectifiedGridAngle = Degrees2Radians(_Parameters.GetParameterValue("rectified_grid_angle"));
            

            sincos(lat_origin, out _sinP20, out _cosP20);
            var con = 1.0 - _es * Math.Pow(_sinP20, 2);
            var com = Math.Sqrt(1.0 - _es);
            _bl = Math.Sqrt(1.0 + _es * Math.Pow(_cosP20, 4.0) / ( 1.0 - _es ));
            _al = _semiMajor * _bl * scale_factor * com / con;

            double f;
            if (Math.Abs(lat_origin) < EPSLN)
            {
                //ts = 1.0;
                _d = 1.0;
                _el = 1.0;
                f = 1.0;
            }
            else
            {
                var ts = tsfnz(_e, lat_origin, _sinP20);
                con = Math.Sqrt(con);
                _d = _bl * com / ( _cosP20 * con );
                if ( ( _d * _d - 1.0 ) > 0.0 )
                {
                    if ( lat_origin >= 0.0 )
                        f = _d + Math.Sqrt(_d * _d - 1.0);
                    else
                        f = _d - Math.Sqrt(_d * _d - 1.0);
                }
                else
                    f = _d;
                _el = f * Math.Pow(ts, _bl);
            }

            var g = .5 * ( f - 1.0 / f );
            var gama = asinz(Math.Sin(_azimuth) / _d);
            lon_origin = lon_origin - asinz(g * Math.Tan(gama)) / _bl;

            con = Math.Abs(lat_origin);
            if ( ( con > EPSLN ) && ( Math.Abs(con - HALF_PI) > EPSLN ) )
            {
                sincos(gama, out _singam, out _cosgam);
                sincos(_azimuth, out _sinaz, out _cosaz);
                if ( lat_origin >= 0 )
                    _u = ( _al / _bl ) * Math.Atan(Math.Sqrt(_d * _d - 1.0) / _cosaz);
                else
                    _u = -( _al / _bl ) * Math.Atan(Math.Sqrt(_d * _d - 1.0) / _cosaz);
            }
            else
            {
                throw new ArgumentException("Input data error");
            }

            sincos(rectifiedGridAngle, out _singrid, out _cosgrid);

        }
        public override IMathTransform Inverse()
        {
            if (_inverse == null)
            {
                _inverse = new HotineObliqueMercatorProjection(_Parameters.ToProjectionParameter(), this);
            }
            return _inverse;

        }
        public HotineObliqueMercatorProjection(IEnumerable <ProjectionParameter> parameters, HotineObliqueMercatorProjection inverse)
            : base(parameters, inverse)
        {
            Authority     = "EPSG";
            AuthorityCode = 9812;
            Name          = "Hotine_Oblique_Mercator";

            _azimuth = DegreesToRadians(_Parameters.GetParameterValue("azimuth"));
            double rectifiedGridAngle = DegreesToRadians(_Parameters.GetParameterValue("rectified_grid_angle"));


            sincos(lat_origin, out _sinP20, out _cosP20);
            double con = 1.0 - _es * Math.Pow(_sinP20, 2);
            double com = Math.Sqrt(1.0 - _es);

            _bl = Math.Sqrt(1.0 + _es * Math.Pow(_cosP20, 4.0) / (1.0 - _es));
            _al = _semiMajor * _bl * scale_factor * com / con;

            double f;

            if (Math.Abs(lat_origin) < EPSLN)
            {
                //ts = 1.0;
                _d  = 1.0;
                _el = 1.0;
                f   = 1.0;
            }
            else
            {
                double ts = tsfnz(_e, lat_origin, _sinP20);
                con = Math.Sqrt(con);
                _d  = _bl * com / (_cosP20 * con);
                if ((_d * _d - 1.0) > 0.0)
                {
                    if (lat_origin >= 0.0)
                    {
                        f = _d + Math.Sqrt(_d * _d - 1.0);
                    }
                    else
                    {
                        f = _d - Math.Sqrt(_d * _d - 1.0);
                    }
                }
                else
                {
                    f = _d;
                }
                _el = f * Math.Pow(ts, _bl);
            }

            double g    = .5 * (f - 1.0 / f);
            double gama = asinz(Math.Sin(_azimuth) / _d);

            lon_origin = lon_origin - asinz(g * Math.Tan(gama)) / _bl;

            con = Math.Abs(lat_origin);
            if ((con > EPSLN) && (Math.Abs(con - HALF_PI) > EPSLN))
            {
                sincos(gama, out _singam, out _cosgam);
                sincos(_azimuth, out _sinaz, out _cosaz);
                if (lat_origin >= 0)
                {
                    _u = (_al / _bl) * Math.Atan(Math.Sqrt(_d * _d - 1.0) / _cosaz);
                }
                else
                {
                    _u = -(_al / _bl) * Math.Atan(Math.Sqrt(_d * _d - 1.0) / _cosaz);
                }
            }
            else
            {
                throw new ArgumentException("Input data error");
            }

            sincos(rectifiedGridAngle, out _singrid, out _cosgrid);
        }