コード例 #1
0
ファイル: CS_azmed.c プロジェクト: asir6/Colt
int EXP_LVL9 CSazmedI (Const struct cs_Azmed_ *azmed,double ll [2],Const double xy [2])
{
	extern char csErrnam [];

	extern double cs_Radian;			/*  57.29577..... */
	extern double cs_Zero;				/* 0.0 */
	extern double cs_Half;				/* 0.5 */
	extern double cs_One;				/* 1.0 */
	extern double cs_Mone;				/*-1.0 */
	extern double cs_Three;				/* 3.0 */
	extern double cs_Six;				/* 6.0 */
	extern double cs_AnglTest;			/* 0.001 seconds of arc,
										   in radians. */
	extern double cs_NPTest;			/* 0.001 seconds of arc
										   short of the north pole,
										   in radians. */

	int rtn_val;
	int itr_cnt;

	double x = 0.0;			/* initialized to keep the gcc compiler happy */
	double y = 0.0;			/* initialized to keep the gcc compiler happy */
	double c;
	double lat = 0.0;		/* initialized to keep the gcc compiler happy */
	double del_lng;
	double rho;
	double sin_c;
	double cos_c;
	double Az;
	double sin_Az;
	double cos_Az;
	double cos_psi;
	double last_lat;
	double A;
	double B;
	double D;
	double D_third;
	double D_fourth;
	double E;
	double E_sq;
	double E_third;
	double sin_E;
	double F;
	double M;
	double psi;
	double tmp1;
	double tmp2;

	double my_xy [2];

	rtn_val = cs_CNVRT_NRML;

	/* There are two formulae, one for the sphere and
	   one for the ellipsoid.  If the ecentricity of the
	   datum in use is 0.0 exactly, we shall use the
	   spherical formulae.

	   The calculations which immediately follow are required
	   by both cases.  First, we remove the false origin, return
	   to the normal X/Y quadrant, and unrotate the coordinates. */

	if (azmed->quad == 0)
	{
		my_xy [XX] = xy [XX] - azmed->x_off;
		my_xy [YY] = xy [YY] - azmed->y_off;
	}
	else
	{
		CS_quadI (&my_xy [XX],&my_xy [YY],xy,azmed->x_off,
						     azmed->y_off,
						     azmed->quad);
	}
	x = azmed->cos_Az * my_xy [XX] + azmed->sin_Az * my_xy [YY];
	y = azmed->cos_Az * my_xy [YY] - azmed->sin_Az * my_xy [XX];

	/* Rho is the radius of the circle whose center is at the
	   origin and goes thorugh the current point. */

	rho = sqrt (x * x + y * y);
	if (rho < azmed->one_mm)
	{
		/* The coordinate is essentially the origin.  We
		   do the following to avoid a atan2(0,0).

		   If the origin is either pole, the longitude
		   will be undefined. */

		if (azmed->aspect == cs_AZMED_NORTH ||
		    azmed->aspect == cs_AZMED_SOUTH)
		{
			rtn_val = cs_CNVRT_INDF;
		}
		ll [LNG] = azmed->org_lng * cs_Radian;
		ll [LAT] = azmed->org_lat * cs_Radian;
		return (rtn_val);
	}
	if (rho >= azmed->max_rho)
	{
		/* Opps!!! The x and/or y is so large it is outside
		   the circle which defines the extent of the
		   coordinate system.  Convert xy to lie on the
		   bounding circle at the apropriate azimuth. */

		rtn_val = cs_CNVRT_RNG;
		x *= azmed->max_rho / rho;
		y *= azmed->max_rho / rho;
		rho = azmed->max_rho;
	}

	/* Now we can convert back to lat/longs.  We know that rho
	   is not zero which implies that at least one of x and y is
	   not zero. */

	del_lng = cs_Zero;
	if (azmed->ecent == 0.0)
	{
		/* Here for the sphere.  The sine and cosine functions
		   shouldnever return a value greater than one.  Thus,
		   the asin ()'s here should be OK without any checking. */

		c = rho / azmed->ka;
		sin_c = sin (c);
		cos_c = cos (c);

		switch (azmed->aspect) {

		case cs_AZMED_NORTH:

			del_lng = atan2 (x,-y);
			lat     = asin  (cos_c);
			break;

		case cs_AZMED_SOUTH:

			del_lng =  atan2 (x,y);
			lat     = -asin  (cos_c);
			break;

		case cs_AZMED_EQUATOR:

			c = rho / azmed->ka;
			tmp1 = x * sin (c);
			tmp2 = rho * cos (c);
			del_lng = atan2 (tmp1,tmp2);
			tmp1  = (y / rho) * sin_c;
			if (fabs (tmp1) > cs_One)
			{
				tmp1 = (tmp1 >= 0.0) ? cs_One : cs_Mone;
			}
			lat = asin (tmp1);
			break;

		case cs_AZMED_GUAM:

			lat = azmed->org_lat;
			itr_cnt = 16;
			for (;;)
			{
				last_lat = lat;
				tmp1 = x * x * tan (lat) / azmed->two_ka;
				lat = azmed->org_lat + (y - tmp1) / azmed->ka;
				if (fabs (lat - last_lat) < cs_AnglTest)
				{
					break;
				}
				if (--itr_cnt <= 0)
				{
					rtn_val = cs_CNVRT_RNG;
					break;
				}
			}

			/* Longitude is undefined at the poles. */

			if (fabs (lat) < cs_NPTest)
			{
				del_lng = x / (azmed->ka * cos (lat));
			}
			break;

		case cs_AZMED_OBLIQUE:

			tmp1  = cos_c * azmed->sin_org_lat;
			tmp1 += (y / rho) * sin_c * azmed->cos_org_lat;
			if (fabs (tmp1) > cs_One)
			{
				tmp1 = (tmp1 >= 0.0) ? cs_One : cs_Mone;
			}
			lat = asin (tmp1);

			tmp1  = x * sin_c;
			tmp2  = rho * cos_c * azmed->cos_org_lat;
			tmp2 -= y * sin_c * azmed->sin_org_lat;
			del_lng = atan2 (tmp1,tmp2);
			break;

		default:
			CS_stncp (csErrnam,"CS_azmed:3",MAXPATH);
			CS_erpt (cs_ISER);
			rtn_val = -1;
			break;
		}
	}
	else
	{
		/* Here for the ellisoid.  We've already dealt
		   with x and y == 0. */

		switch (azmed->aspect) {

		case cs_AZMED_NORTH:

			del_lng = atan2 (x,-y);
			lat = CSmmIcal (&azmed->mmcofI,(azmed->Mp - rho));
			break;

		case cs_AZMED_SOUTH:

			del_lng = atan2 (x,y);
			lat = CSmmIcal (&azmed->mmcofI,(rho - azmed->Mp));
			break;

		case cs_AZMED_GUAM:

			itr_cnt = 16;
			lat = azmed->org_lat;
			for (;;)
			{
				last_lat = lat;
				tmp1 = sin (lat);
				tmp1 = cs_One - azmed->e_sq * tmp1 * tmp1;
				tmp1 = x * x * tan (lat) * sqrt (tmp1);
				tmp1 = y - tmp1 / azmed->two_ka;
				M = azmed->M1 + tmp1;
				lat = CSmmIcal (&azmed->mmcofI,M);
				if (fabs (lat - last_lat) < cs_AnglTest)
				{
					break;
				}
				if (--itr_cnt <= 0)
				{
					rtn_val = cs_CNVRT_RNG;
					break;
				}
			}

			/* Longitude is undefined at the poles. */

			if (fabs (lat) < cs_NPTest)
			{
				tmp1 = sin (lat);
				tmp1 = cs_One - azmed->e_sq * tmp1 * tmp1;
				del_lng = x * sqrt (tmp1) / (azmed->ka * cos (lat));
			}
			break;

		case cs_AZMED_EQUATOR:
		case cs_AZMED_OBLIQUE:

			Az = atan2 (x,y);
			sin_Az = sin (Az);
			cos_Az = cos (Az);
			A = -azmed->e_sq_cos_sq * cos_Az * cos_Az / azmed->one_esq;
			B = cs_Three * azmed->e_sq * (cs_One - A) * azmed->sin_cos *
						cos_Az / azmed->one_esq;
			D = rho / azmed->N1;
			D_third = D * D * D;
			D_fourth = D_third * D;
			E = D;
			E -= A * (cs_One + A) * D_third / cs_Six;
			E -= B * (cs_One + cs_Three * A) * D_fourth / 24.0;
			E_sq = E * E;
			E_third = E_sq * E;
			sin_E = sin (E);
			F = cs_One - (A * E_sq * cs_Half) - (B * E_third / cs_Six);		/*lint !e834 */
			tmp1 = azmed->sin_org_lat * cos (E);
			tmp2 = azmed->cos_org_lat * sin_E * cos_Az;
			psi = asin (tmp1 + tmp2);

			/* Psi is essentially the latitude of the point
			   adjusted for the affect of the ellipsoid.  Thus,
			   it can be zero, and it can be the equivalent of
			   +-90 degrees.

			   In analyzing the following, note that:
			   1) E is the ellipsoidally adjusted angular
			      distance from the origin to the point;
			   2) the formula is actually equation 5-4 of Synder,
			      reorganized to produce the delta longitude.

			   Thus, I conclude that delta longitude goes to
			   zero as cos(psi) approaches zero. */

			cos_psi = cos (psi);
			if (fabs (cos_psi) > cs_AnglTest)
			{
				del_lng = asin (sin_Az * sin_E / cos (psi));
			}

			/* Now, the latitude.  We have a similar problem,
			   but now with sin (psi) == 0. As psi approaches
			   zero, this whole mess reduces to lat = psi,
			   which is zero, of course. */

			if (fabs (psi) > cs_AnglTest)
			{
				tmp1 = azmed->e_sq * F * azmed->sin_org_lat / sin (psi);
				tmp2 = tan (psi) / azmed->one_esq;
				lat = atan ((cs_One - tmp1) * tmp2);
			}
			else
			{
				lat = cs_Zero;
			}
			break;

		default:

			CS_stncp (csErrnam,"CS_azmed:",MAXPATH);
			CS_erpt (cs_ISER);
			rtn_val = -1;
			break;
		}
	}

	/* Longitude is undefined, mathematically, at either pole. */
	if (rtn_val >= 0)
	{
		if (fabs (lat) > cs_NPTest) rtn_val = cs_CNVRT_INDF;

		/* Longitudes are always normalized for this projection. */

		ll [LNG] = (del_lng + azmed->org_lng) * cs_Radian;
		ll [LAT] = lat * cs_Radian;
	}
	return (rtn_val);
}
コード例 #2
0
ファイル: CS_tacyl.c プロジェクト: kanbang/Colt
int EXP_LVL9 CStacylI (Const struct cs_Tacyl_ *tacyl,double ll [2],Const double xy [2])
{
    extern double cs_Zero;
    extern double cs_One;				/*  1.0 */
    extern double cs_Mone;				/* -1.0 */
    extern double cs_Radian;			/*  57.29577... */
    extern double cs_Pi;				/*  3.14159... */
    extern double cs_Pi_o_2;			/*  PI / 2.0 */
    extern double cs_AnglTest;			/* 0.001 arc seconds, in
										   radians. */

    int rtn_val;

    double xx;
    double yy;
    double del_lng;
    double lat;

    double qq;
    double Mc;
    double DD;
    double beta;
    double sin_DD;
    double cos_DD;
    double latc;
    double sin_lat;
    double sin_latc;
    double cos_latc;
    double esin_latc;
    double betac;
    double sin_betac;
    double cos_betac;
    double betap;
    double cos_betap;

    double tmp1;
    double tmp2;
    double tmp3;
    double tmp4;

    rtn_val = cs_CNVRT_NRML;

    /* Remove the false origin. */

    if (tacyl->quad == 0)
    {
        xx = xy [XX] - tacyl->x_off;
        yy = xy [YY] - tacyl->y_off;
    }
    else
    {
        CS_quadI (&xx,&yy,xy,tacyl->x_off,tacyl->y_off,tacyl->quad);
    }

    lat = cs_Zero;
    del_lng = cs_Zero;
    if (tacyl->ecent == 0.0)
    {
        /* Here for the sphere.  There are two special
           cases to deal with.  If X is out of range, we
           will end up taking the square root of a
           negative number.  In this case, assuming
           we are not at a pole (cos_DD != 0.0), we
           set the longitude to be equal to org_lng
           +- _PI/2 taking the sign of X.

           If X is in range, but we are at either pole,
           there is no longitude and we can pick any
           value, like org_lng. */

        DD = yy / tacyl->kah0 + tacyl->org_lat;
        sin_DD = sin (DD);
        cos_DD = cos (DD);

        if (fabs (cos_DD) < cs_AnglTest)
        {
            /* Opps!!! We're at a pole.  Can't divide
               by cos_DD.  Pick the right pole and
               leave longitude ar org_lng. */

            rtn_val = cs_CNVRT_INDF;
            if (sin_DD > 0.0) lat = cs_Pi_o_2;
            else			  lat =  cs_Pi_o_2;
        }
        else
        {
            /* Not at either pole.  Make sure we don't
               take the square root of a negative number. */

            tmp1 = xx * tacyl->h0_o_ka;
            tmp2 = cs_One - tmp1 * tmp1;

            if (tmp2 < cs_AnglTest)
            {
                if (tmp2 < 0.0) rtn_val = cs_CNVRT_RNG;
                tmp2 = cs_Zero;
            }
            else
            {
                tmp2 = sqrt (tmp2);
            }
            sin_lat = tmp2 * sin_DD;
            if (fabs (sin_lat) >= cs_One)
            {
                sin_lat = (sin_lat >= 0.0) ? cs_One : cs_Mone;
            }
            lat = asin (sin_lat);
            tmp2 *= cos_DD;

            /* tmp2 may be zero here, but tmp1 and tmp2
               cannot both be zero.  Therefore, atan2 should
               work OK in all cases. */

            del_lng = atan2 (tmp1,tmp2);
        }
    }
    else
    {
        /* Here for the ellipsoid.  The standard equations
           are indeterminate at the poles.  At the current
           time, the handling of |X| values greater than
           R/h0 produces different results between the
           spherical and ellipsoid cases. X isn't supposed
           to get bigger than this, so it might not make
           any difference to anyone. */

        Mc = tacyl->M0 + yy / tacyl->h0;
        latc = CSmmIcal (&tacyl->mmcofI,Mc);
        sin_latc = sin (latc);
        cos_latc = cos (latc);

        if (fabs (cos_latc) > cs_AnglTest)
        {
            /* Not at a pole. */

            esin_latc = tacyl->ecent * sin_latc;
            tmp1 = (cs_One - esin_latc) / (cs_One + esin_latc);
            tmp1 = tacyl->one_o_2e * log (tmp1);
            tmp2 = cs_One - esin_latc * esin_latc;
            qq = tacyl->one_m_esq * (sin_latc / tmp2 - tmp1);

            /* Seems a bit inefficient, but we need the
               normalizing affect of the asin function
               here.  sin_betac should never be more than
               one, but noise in the low order bits during
               the calculations require that we check to
               prevent asin from generating a floating
               point exception. */

            sin_betac = qq / tacyl->qp;
            if (fabs (sin_betac) >= cs_One)
            {
                sin_betac = (sin_betac >= 0.0) ? cs_One : cs_Mone;
            }
            betac = asin (sin_betac);
            sin_betac = sin (betac);
            cos_betac = cos (betac);

            /* Note what the following does when |X| is
               greater than R/h0: Betap, and hence beta,
               simply wraps back on themselves to computable
               values.  I.e. an X value of R/h0+p is treated
               the same as the value R/h0-p. */

            tmp3 = cos_betac * sqrt (tmp2) / cos_latc;
            tmp4 = xx * tacyl->h0_o_ka * tmp3;
            if (fabs (tmp4) > cs_One)
            {
                rtn_val = cs_CNVRT_RNG;
                tmp4 = (tmp4 >= 0.0) ? cs_One : cs_Mone;
            }
            betap = -asin (tmp4);
            cos_betap = cos (betap);
            beta = asin (cos_betap * sin_betac);

            /* We don't get here if we are at a pole.
               Therefore, tan (betap) should be OK,
               and cos_betac should never be zero.
               Since cos_betac is always positive,
               we can use atan just as well as atan2. */

            del_lng = -atan (tan (betap) / cos_betac);
            lat = CSbtIcalPrec (&tacyl->btcofI,beta);
        }
        else
        {
            /* At a pole, any longitude will do.  We'll
               use the origin longitude by leaving lng
               set to zero. */

            rtn_val = cs_CNVRT_INDF;
            if (latc > 0.0) lat = cs_Pi_o_2;
            else		lat = cs_Pi_o_2;
        }
    }

    if (fabs (del_lng) > cs_Pi)
    {
        del_lng = CS_adj2pi (del_lng);
        rtn_val = cs_CNVRT_RNG;
    }
    ll [LNG] = (del_lng + tacyl->org_lng) * cs_Radian;
    if (fabs (lat) > cs_Pi_o_2) rtn_val = cs_CNVRT_RNG;
    ll [LAT] = CS_adj1pi (lat) * cs_Radian;

    return (rtn_val);
}
コード例 #3
0
ファイル: CS_sinus.c プロジェクト: asir6/Colt
int EXP_LVL9 CSsinusI (Const struct cs_Sinus_ *sinus,double ll [2],Const double xy [2])
{
	extern double cs_Radian;			/* 57.29577..... */
	extern double cs_Pi_o_2;			/* Pi over 2 */
	extern double cs_Mpi_o_2;			/* -Pi over 2 */
	extern double cs_3Pi_o_2;			/* 3 Pi over 2 */
	extern double cs_Zero;				/* 0.0 */
	extern double cs_One;				/* 1.0 */
	extern double cs_NPTest;			/* 0.001 arc seconds short
										   of the north pole in
										   radians. */

	int rtn_val;

	Const struct cs_Zone_ *zp;

	double xx;
	double yy;
	double zn_xx;
	double zn_yy;
	double lat;
	double lng;
	double del_lng;

	double cent_lng;		/* Local central longitude
							   after adjustment for the
							   appropriate zone. */
	double x_off;			/* The false easting appropriate
							   for the zone. */
	double sin_lat;
	double cos_lat;
	double tmp1;

	rtn_val = cs_CNVRT_NRML;

	/* Before we can do much with the inverse, we need to determine
	   which zone the coordinate is in, if zones are active. */

	if (sinus->zone_cnt <= 0)
	{
		/* No zones are active, this is easy. */

		cent_lng = sinus->cent_lng;
		x_off    = sinus->x_off;
		zp = NULL;
	}
	else
	{
		/* We have a complication introduced by variable
		   quadrants.  In order to locate the zone, we
		   must undo the quadrant processing in selected
		   pieces. */

		zn_xx = xy [XX];
		zn_yy = xy [YY];
		if ((sinus->quad & cs_QUAD_SWAP) != 0)
		{
			zn_xx = xy [YY];
			zn_yy = xy [XX];
		}
		zn_yy -= sinus->y_off;

		/* We can now use zn_xx and zn_yy to locate the proper
		   zone. */

		zp = CS_znlocI (sinus->zones,sinus->zone_cnt,zn_xx,zn_yy);
		if (zp != NULL)
		{
			cent_lng = zp->cent_lng;
			x_off    = zp->x_off;
		}
		else
		{
			rtn_val = cs_CNVRT_RNG;
			cent_lng = sinus->cent_lng;
			x_off    = sinus->x_off;
		}
	}

	/* Remove the false origin. */

	if (sinus->quad == 0)
	{
		xx = xy [XX] - x_off;
		yy = xy [YY] - sinus->y_off;
	}
	else
	{
		CS_quadI (&xx,&yy,xy,x_off,sinus->y_off,sinus->quad);
	}

	/* Rather sane stuff from here on out. */

	if (fabs (yy) > sinus->max_yy)
	{
		rtn_val = cs_CNVRT_RNG;
		yy = (yy >= 0.0) ? sinus->max_yy : -sinus->max_yy;
	}

	if (fabs (xx) > sinus->max_xx)
	{
		rtn_val = cs_CNVRT_RNG;
		xx = (xx >= 0.0) ? sinus->max_xx : -sinus->max_xx;
	}

	/* We have now compensated for the zone. */

	del_lng = cs_Zero;
	if (sinus->ecent == 0.0)
	{
		/* Here for the shpere. Cos (lat) will be zero at
		   the poles. In this case, any longitude will do. */

		lat = yy / sinus->ka;
		if (fabs (lat) < cs_NPTest)
		{
			cos_lat = cos (lat);
			del_lng = xx / (sinus->ka * cos_lat);
		}
		else if (rtn_val == cs_CNVRT_NRML)
		{
			lat = (lat > 0.0) ? cs_Pi_o_2 : cs_Mpi_o_2;
			rtn_val = cs_CNVRT_INDF;
		}
	}
	else
	{
		/* Here for the ellipsoid.  Again, the longitude is
		   indeterminate at the poles, and any longitude will
		   do. */

		lat = CSmmIcal (&sinus->mmcofI,yy);
		if (fabs (lat) < cs_NPTest)
		{
			cos_lat = cos (lat);
			sin_lat = sin (lat);
			tmp1 = cs_One - (sinus->e_sq * sin_lat * sin_lat);
			del_lng = (xx * sqrt (tmp1)) / (sinus->ka * cos_lat);
		}
		else if (rtn_val == cs_CNVRT_NRML)
		{
			lat = (lat > 0.0) ? cs_Pi_o_2 : cs_Mpi_o_2;
			rtn_val = cs_CNVRT_INDF;
		}
	}

	if (fabs (del_lng) >= cs_3Pi_o_2)
	{
		rtn_val = cs_CNVRT_RNG;
		del_lng = CS_adj2pi (del_lng);
	}
	lng = del_lng + cent_lng;

	/* If the X and Y coordinates are in the void space between
	   the zones, the resulting longitude will end up in a zone
	   other than the one we started with.  In this case, we have
	   yet another range error, and we adjust the longitude to
	   the appropriate edge of the zone we started out in. */

	if (zp != NULL)
	{
		if (lng < zp->west_lng)
		{
			rtn_val = cs_CNVRT_RNG;
			lng = zp->west_lng;
		}
		if (lng > zp->east_lng)
		{
			rtn_val = cs_CNVRT_RNG;
			lng = zp->east_lng;
		}
	}

	/* Convert to degrees. */

	ll [LNG] = lng * cs_Radian;
	ll [LAT] = lat * cs_Radian;
	return (rtn_val);
}
コード例 #4
0
ファイル: CS_csini.c プロジェクト: auranet/csmap
int EXP_LVL9 CScsiniI (Const struct cs_Csini_ *csini,double ll [2],Const double xy [2])
{
	extern double cs_Radian;			/* 57.29577... */
	extern double cs_Pi;				/* 3.14159... */
	extern double cs_Pi_o_2;			/* pi over 2 */
	extern double cs_Zero;				/* 0.0 */
	extern double cs_Third;				/* 0.3333... */
	extern double cs_Half;				/* 0.5 */
	extern double cs_One;				/* 1.0 */
	extern double cs_Three;				/* 3.0 */
	extern double cs_AnglTest;			/* 0.001 arc seconds, in
										   radians. */
	extern double cs_Huge;				/* an approximation of
										   infinity, not so large
										   that it can't be used in
										   normal calculations
										   without problems. */
	int rtn_val;

	double x;
	double y;

	double lat;
	double del_lng;

	double D;
	double D_2;
	double D_3;
	double D_4;
	double D_5;
	double N1;
	double R1;
	double T1;

	double phi1;
	double sin_phi1;
	double cos_phi1;
	double tan_phi1;

	double tmp1;
	double tmp2;

	rtn_val = cs_CNVRT_NRML;

	if (csini->quad == 0)
	{
		x = xy [XX] - csini->x_off;
		y = xy [YY] - csini->y_off;
	}
	else
	{
		CS_quadI (&x,&y,xy,csini->x_off,csini->y_off,csini->quad);
	}

	if (fabs (x) > csini->max_xx)
	{
		rtn_val = cs_CNVRT_RNG;
		x = (x >= 0.0) ? csini->max_xx : -csini->max_xx;
	}
	if (y < csini->min_yy || y > csini->max_yy)
	{
		rtn_val = cs_CNVRT_RNG;
	}

	if (csini->ecent == 0.0)
	{
		/* Here for a spherical datum.  Cos D is zero at the
		   poles.  Tan (tmp1) is also zero when x is zero. */

		D = (y / csini->ka) + csini->org_lat;
		tmp1 = x / csini->ka;

		tmp2 = sin (D) * cos (tmp1);
		lat = asin (tmp2);

		if (fabs (tmp1) > cs_AnglTest)
		{
			/* This blows up when both arguments are zero,
			   which will happen only at the poles. At the
			   poles, all values of longitudes are
			   equivalent. */

			del_lng = atan2 (tan (tmp1),cos (D));
		}
		else
		{
			if (rtn_val == cs_CNVRT_NRML)
			{
				rtn_val = cs_CNVRT_INDF;
			}
			del_lng = cs_Zero;
		}
	}
	else
	{
		/* Here for an ellipsoid. */

		phi1 = CSmmIcal (&csini->mmcofI,csini->M0 + y);

		sin_phi1 = sin (phi1);
		cos_phi1 = cos (phi1);

		if (fabs (cos_phi1) > cs_AnglTest)
		{
			/* Blows up at the poles, but not really out the
			   useful range of this projection. */

			tan_phi1 = sin_phi1/cos_phi1;
		}
		else
		{
			tan_phi1 = cs_Huge;
		}
		T1 = tan_phi1 * tan_phi1;

		tmp1 = cs_One - (csini->e_sq * (sin_phi1 * sin_phi1));
		tmp2 = sqrt (tmp1);
		N1 = csini->ka / tmp2;
		R1 = csini->R_term / (tmp1 * tmp2);

		D = x / N1;
		D_5 = D * (D_4 = D * (D_3 = D * (D_2 = D * D)));

		/* Compute the latitude. */

		tmp1 = (cs_Half * D_2);
		tmp1 -= (cs_One + cs_Three * T1) * D_4 * (1.0 / 24.0);
		tmp1 *= N1 * tan_phi1 / R1;
		lat = phi1 - tmp1;

		/* Now we can compute a longitude. */

		if (fabs (cos_phi1) > cs_AnglTest)
		{
			tmp1 = D - (T1 * (cs_Third * D_3));
			tmp1 += (cs_One + cs_Three * T1) * T1 * D_5 * (1.0 / 15.0);
			del_lng = tmp1 / cos_phi1;	/* Blows up at the poles. */
		}
		else
		{
			/* Any longitude, like cent_lng, will do just
			   fine. */

			if (rtn_val == cs_CNVRT_NRML)
			{
				rtn_val = cs_CNVRT_INDF;
			}
			del_lng = cs_Zero;
		}
	}

	if (fabs (del_lng) > cs_Pi)
	{
		del_lng = CS_adj2pi (del_lng);
		rtn_val = cs_CNVRT_RNG;
	}
	if (fabs (lat) > cs_Pi_o_2)
	{
		lat = CS_adj1pi (lat);
		rtn_val = cs_CNVRT_RNG;
	}

	ll [LNG] = (del_lng + csini->cent_lng) * cs_Radian;
	ll [LAT] = lat * cs_Radian;
	return (rtn_val);
}