Example #1
0
int EXP_LVL9 CSwinklF (Const struct cs_Winkl_ *winkl,double xy [2],Const double ll [2])
{
	extern double cs_Degree;
	extern double cs_Pi;
	extern double cs_Pi_o_2;
	extern double cs_3Pi_o_2;
	extern double cs_Two_pi;

	int rtn_val;

	double del_lng;
	double lng;
	double lat;

	double xx;
	double yy;

	rtn_val = cs_CNVRT_NRML;

	/* For this projection, we only support the spherical form,
	   therefore there is only one set of equations.  These are
	   pretty simple. */
	lat = ll [LAT] * cs_Degree;
	if (fabs (lat) > cs_Pi_o_2)
	{
		rtn_val = cs_CNVRT_RNG;
		lat = CS_adj1pi (lat);
	}

	lng = ll [LNG] * cs_Degree;
	del_lng = lng - winkl->org_lng;
	
	/* For this projection, we assure that the central meridian is the center of
	   the  map; this implying that delta longitude is always less than or equal
	   to pi, and greater than minus pi. */
	if (fabs (del_lng) > cs_3Pi_o_2)
	{
		rtn_val = cs_CNVRT_RNG;
	}
	if (fabs (del_lng) > cs_Pi)
	{
		del_lng = CS_adj2pi (del_lng);
	}
	rtn_val = CSwinklB (winkl,&xx,&yy,del_lng,lat);
	
	if (winkl->quad == 0)
	{
		xy [XX] = xx + winkl->x_off;
		xy [YY] = yy + winkl->y_off;
	}
	else
	{
		CS_quadF (xy,xx,yy,winkl->x_off,winkl->y_off,winkl->quad);
	}
	return rtn_val;	
}
Example #2
0
int EXP_LVL9 CSunityF (Const struct cs_Unity_ *unity,double xy [2],Const double ll [2])
{
	extern double cs_Zero;			/*    0.0 */
	extern double cs_K90;			/*   90.0 */
	extern double cs_Km90;			/*  -90.0 */
	extern double cs_K270;			/*  270.0 */
	extern double cs_Km270;			/* -270.0 */

	int rtn_val;

	double lng;

	rtn_val = cs_CNVRT_NRML;

	/* If the lat/long we have been provided are not within internal
	   standards, we have a domain problem.  This should only happen
	   if we are called directly by an application program. */

	xy [XX] = ll [LNG];
	xy [YY] = ll [LAT];
	if (xy [XX] <= cs_Km270 || xy [XX] > cs_K270)
	{
		rtn_val = cs_CNVRT_DOMN;
		xy [XX] = CS_adj270 (xy [XX]);
	}
	if (xy [YY] < cs_Km90 || xy [YY] > cs_K90)
	{
		rtn_val = cs_CNVRT_DOMN;
		xy [YY] = CS_adj90 (xy [YY]);
	}

	/* Convert to user form. */

	xy [XX] = (xy [XX] - unity->gwo_lng) * unity->unit_s;
	xy [YY] =  xy [YY] * unity->unit_s;

	/* Normalize longitude, if necessary, to acheive the user's
	   desired range. */


	if (xy [XX] < unity->usr_min || xy [XX] > unity->usr_max)
	{
		lng = xy [XX] - unity->usr_min;
		lng = fmod (lng,unity->usr_2pi);
		if (lng < 0.0) lng += unity->usr_2pi;
		if (lng > unity->usr_rng) lng -= unity->usr_2pi;
		xy [XX] = unity->usr_min + lng;
	}
	if (unity->quad != 0)
	{
		CS_quadF (xy,xy [XX],xy [YY],cs_Zero,cs_Zero,unity->quad);
	}
	return (rtn_val);
}
Example #3
0
int EXP_LVL9 CSkrovkF (Const struct cs_Krovk_ *krovk,double xy [2],Const double lnglat [2])
{
	int rtn_val;

	double theta;
	double rho;
	double tmp;
	double llO [2];
	double llS [2];
	double deltaXY [2];

	/* Do the forward calculation. */
	rtn_val = CSkrovkB2 (krovk,lnglat,llS,llO,&theta,&rho);

	/* Now to cartesian coordnates. */
	xy [XX] = rho * cos (theta);
	xy [YY] = rho * sin (theta);

	/* Apply the 95 adjustment if appropriate. */
	if (krovk->apply95)
	{
		CSkrovk95 (deltaXY,xy);
		xy [XX] -= deltaXY [XX];
		xy [YY] -= deltaXY [YY];
	}

	/* We do some strange stuff here to get a normal coordinate system out of
	   this.  That is, a coordinate system which works well in a traditional
	   graphic system such as AutoCAD.  For the 95 variation, the false origin
	   values are negative to help achieve the desired result.
	   
	   The actual definition of the Krovak requires that Y increases to the
	   west and that X increases to the south.  This would produce a very
	   strange image in AutoCAD, i.e. mirrored about the origin.  The desired
	   result is, therefore, a coordinate system which produces negative
	   values, such that when treated algebraically, X increases to the east
	   and Y increases to the north.  The absolute values, however, adhere
	   to the definition of Krovak (excepting the swap of the axes). */
	CS_quadF (xy,xy [XX],xy [YY],krovk->x_off,krovk->y_off,krovk->quad);
	tmp = xy [XX];
	xy [XX] = -xy [YY];
	xy [YY] = -tmp;

	return (rtn_val);
}
Example #4
0
int EXP_LVL9 CSazmedF (Const struct cs_Azmed_ *azmed,double xy [2],Const double ll [2])
{
	extern char csErrnam [MAXPATH];

	extern double cs_Degree;			/* 1.0 / RADIAN  */
	extern double cs_Pi;				/* 3.14159... */
	extern double cs_Two_pi;			/* 2 PI */
	extern double cs_Mpi;				/* -3.14159.... */
	extern double cs_Pi_o_2;			/* PI over 2 */
	extern double cs_Mpi_o_2;			/* Minus PI over 2 */
	extern double cs_Zero;				/* 0.0 */
	extern double cs_One;				/* 1.0 */
	extern double cs_Mone;				/*-1.0 */
	extern double cs_Two;				/* 2.0 */
	extern double cs_Four;				/* 4.0 */
	extern double cs_Six;				/* 6.0 */
	extern double cs_Seven;				/* 7.0 */
	extern double cs_Eight;				/* 8.0 */
	extern double cs_NPTest;			/* 0.001 seconds of arc
										   short of the north pole
										   in radians. */
	extern double cs_AnglTest;			/* 0.001 seconds of arc
										   in radians. */
	extern double cs_AnglTest1;			/* 1.0 - 0.001 seconds of
										   arc in radians.  Could
										   also be considered to
										   be the cosine of
										   cs_AnglTest. */

	int rtn_val;

	double lng;		/* The given longitude, after conversion
					   to radians. */
	double lat;		/* The given latitude after conversion
					   to radians. */
	double x = 0.0;			/* initialized to keep the gcc compiler happy */
	double y = 0.0;			/* initialized to keep the gcc compiler happy */

	double M;
	double N;
	double H;
	double H_sq;
	double H_sq_7;
	double GH;
	double rho;
	double psi;
	double del_lng;
	double sin_del_lng;
	double cos_del_lng;
	double sin_lat;
	double cos_lat;
	double cos_c;
	double c;
	double Az;
	double sin_Az;
	double cos_Az;
	double s;
	double s_sq;
	double s_third;
	double s_fourth;
	double s_fifth;
	double tmp1;
	double tmp2;
	double tmp3;
	double tmp4;

	rtn_val = cs_CNVRT_NRML;

	/* There are two formulae, one for the sphere and
	   one for the ellipsoid.  If the ecentricity
	   of the dataum in use is 0.0 exactly, we
	   shall use the spherical formulae.  There
	   is a miminal amount of stuff which is
	   common to both which we perform first. */

	lng = cs_Degree * ll [LNG];
	lat = cs_Degree * ll [LAT];

	if (fabs (lat) > cs_NPTest)
	{
		rtn_val = cs_CNVRT_INDF;
		if (fabs (lat) > cs_Pi_o_2)
		{
			rtn_val = cs_CNVRT_RNG;
			lat = CS_adj1pi (lat);
		}
	}

	del_lng = lng - azmed->org_lng;
	if      (del_lng > cs_Pi  && azmed->org_lng < 0.0) del_lng -= cs_Two_pi;
	else if (del_lng < cs_Mpi && azmed->org_lng > 0.0) del_lng += cs_Two_pi;
	if (del_lng > cs_Pi || del_lng <= cs_Mpi)
	{
		/* Note, the inverse can't distinguish between -180
		   and +180; therefore we return a range status for
		   -180. */

		rtn_val = cs_CNVRT_RNG;
		del_lng = CS_adj2pi (del_lng);
	}
	sin_del_lng = sin (del_lng);
	cos_del_lng = cos (del_lng);
	sin_lat = sin (lat);
	cos_lat = cos (lat);

	/* See if the datum is a sphere or an ellipsoid. */

	if (azmed->ecent == 0.0)
	{
		/* Here for the sphere. */

		switch (azmed->aspect) {

		case cs_AZMED_NORTH:

			tmp1 = (cs_Pi_o_2 - lat) * azmed->ka;
			x = tmp1 * sin_del_lng;
			y = -tmp1 * cos_del_lng;
			break;

		case cs_AZMED_SOUTH:

			tmp1 = (cs_Pi_o_2 + lat) * azmed->ka;
			x = tmp1 * sin_del_lng;
			y = tmp1 * cos_del_lng;
			break;

		case cs_AZMED_EQUATOR:

			cos_c = cos_lat * cos_del_lng;
			c = acos (cos_c);
			if (fabs (c) < cs_AnglTest)
			{
				/* At the origin. */
				tmp1 = cs_Zero;
			}
			else if (cos_c < -cs_AnglTest1)
			{
				/* AntiPodal */
				rtn_val = cs_CNVRT_RNG;
				tmp1 = azmed->ka * cs_Pi;
			}
			else
			{
				/* Normal */
				tmp1 = azmed->ka * c / sin (c);
			}

			x = tmp1 * cos_lat * sin_del_lng;
			y = tmp1 * sin_lat;
			break;

		case cs_AZMED_GUAM:

			x = azmed->ka * del_lng * cos_lat;
			tmp1 = x * x * tan (lat) / azmed->two_ka;
			y = azmed->ka * (lat - azmed->org_lat) + tmp1;
			break;

		case cs_AZMED_OBLIQUE:

			cos_c = azmed->sin_org_lat * sin_lat +
				azmed->cos_org_lat * cos_lat * cos_del_lng;
			c = acos (cos_c);

			/* C is the angular distance from the origin.  A
			   zero value indicates the orgin which would cause
			   a division by sin (0); but otherwise is a
			   perfectly normal value for this projection.

			   As c approaches PI, however, we approach the
			   point opposite the origin, and this point is
			   not well defined. */

			if (fabs (c) <= cs_AnglTest)
			{
				/* The origin. */
				tmp1 = cs_Zero;
			}
			else if (cos_c < -cs_AnglTest1)
			{
				/* Antipodal to the origin. */
				rtn_val = cs_CNVRT_RNG;
				tmp1 = azmed->ka * cs_Pi;
			}
			else
			{
				/* Normal, We can divide by sin (c). */
				tmp1 = azmed->ka * (c / sin (c));
			}

			x = tmp1 * cos_lat * sin_del_lng;
			y = tmp1 * (azmed->cos_org_lat * sin_lat -
				    azmed->sin_org_lat * cos_lat * cos_del_lng);
			break;
	
		default:

			CS_stncp (csErrnam,"CS_azmed:1",MAXPATH);
			CS_erpt (cs_ISER);
			rtn_val = -1;
			break;
		}
	}
	else
	{
		switch (azmed->aspect) {

		case cs_AZMED_NORTH:

			M = CSmmFcal (&azmed->mmcofF,lat,sin_lat,cos_lat);
			rho = azmed->Mp - M;
			x =  rho * sin_del_lng;
			y = -rho * cos_del_lng;
			break;

		case cs_AZMED_SOUTH:

			M = CSmmFcal (&azmed->mmcofF,lat,sin_lat,cos_lat);
			rho = azmed->Mp + M;
			x = rho * sin_del_lng;
			y = rho * cos_del_lng;
			break;

		case cs_AZMED_GUAM:

			M = CSmmFcal (&azmed->mmcofF,lat,sin_lat,cos_lat);
			tmp1 = sqrt (azmed->e_sq * sin_lat * sin_lat);
			x = azmed->ka * del_lng * cos_lat / tmp1;
			tmp2 = tan (lat) * x * x * tmp1 / azmed->two_ka;
			y = M - azmed->M1 + tmp2;							  /*lint !e834 */
			break;

		case cs_AZMED_EQUATOR:
		case cs_AZMED_OBLIQUE:

			/* Compute Az, the azimuth of the point with respect
			   to the origin on the ellipsoid.

			   Psi is the latitude of the point, adjusted for
			   the ellipsoid.  This is zero or cs_Pi_o_2 if the
			   latitude is a pole (don't want to divide by
			   cos (lat) in this case. */

			if (fabs (lat) > cs_NPTest)
			{
				/* Point is a pole. */
				psi = (lat > 0.0) ? cs_Pi_o_2 : cs_Mpi_o_2;
			}
			else
			{
				/* Cosine (lat) will not be zero, we can
				   compute psi safely. */

				tmp1 = azmed->e_sq * sin_lat * sin_lat;
				N = azmed->ka / sqrt (cs_One - tmp1);
				tmp2 = (azmed->one_esq * tan (lat)) + azmed->psi_t1 /
							      (N * cos_lat);
				psi = atan (tmp2);
			}
			tmp3 = (azmed->cos_org_lat * tan (psi)) -
			       (azmed->sin_org_lat * cos_del_lng);

			/* Tmp3 and sin_del_lng will both be zero if the
			   point is the origin.  Most atan2's (not all) will
			   bomb if both args are zero. */

			if (fabs (sin_del_lng) > cs_AnglTest)
			{
				Az = atan2 (sin_del_lng,tmp3);
				sin_Az = sin (Az);
				cos_Az = cos (Az);
			}
			else
			{
				/* del_lng is zero, we do a quick and
				   dirty atan2. */

				sin_Az = cs_Zero;
				if (tmp3 >= 0.0)
				{
					Az = cs_Zero;
					cos_Az = cs_One;
				}
				else
				{
					Az = cs_Mpi;
					cos_Az = cs_Mone;
				}
			}

			/* Ok, we have the azimuth.  Need to compute the
			   angular distance to the point on the ellipsoid.
			   In the case of small angles, the sine and the
			   angle are equivalent. */

			if (fabs (sin_Az) < cs_AnglTest)
			{
				/* Here to avoid a divide by sin (Az). */

				tmp4 = azmed->cos_org_lat * sin (psi) -
				       azmed->sin_org_lat * cos (psi);
				s = asin (tmp4);
				if (cos_Az < 0.0)
				{
					s = -s;
				}
			}
			else
			{
				s = asin (sin_del_lng * cos (psi) / sin_Az);
			}

			/* S is essentially the angular distance over a
			   sphere. Convert to c, the linear distance over
			   the ellipsoid, via a power series calculation. */

			s_sq = s * s;
			s_third = s_sq * s;
			s_fourth = s_sq * s_sq;
			s_fifth = s_fourth * s;

			H = azmed->e_cos_p1 * cos_Az / azmed->rt_one_esq;
			H_sq = H * H;
			H_sq_7 = cs_Seven * H_sq;
			GH = azmed->G * H;

			tmp2 = H_sq * (cs_Four - H_sq_7);
			tmp2 -= azmed->G_sq_3 * (cs_One - H_sq_7);

			tmp1 = cs_One;
			tmp1 -= s_sq * H_sq * (cs_One - H_sq) / cs_Six;
			tmp1 += (s_third / cs_Eight) * GH * (cs_One - cs_Two * H_sq);
			tmp1 += (s_fourth / 120.0) * tmp2;
			tmp1 -= (s_fifth / 48.0) * GH;
			c = azmed->N1 * s * tmp1;

			x = c * sin_Az;
			y = c * cos_Az;
			break;

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

	/* Add the rotation, quad effect, and offset. */
	if (rtn_val >= 0)
	{
		xy [XX] = azmed->cos_Az * x - azmed->sin_Az * y;
		xy [YY] = azmed->cos_Az * y + azmed->sin_Az * x;
		if (azmed->quad == 0)
		{
			xy [XX] += azmed->x_off;
			xy [YY] += azmed->y_off;
		}
		else
		{
			CS_quadF (xy,xy [XX],xy [YY],azmed->x_off,azmed->y_off,
								azmed->quad);
		}
	}
	return (rtn_val);
}
Example #5
0
int EXP_LVL9 CSvdgrnF (Const struct cs_Vdgrn_ *vdgrn,double xy [2],Const double ll [2])
{
	extern double cs_Degree;			/* 1.0 / RADIAN  */
	extern double cs_Pi;				/* 3.14159..... */
	extern double cs_Two_pi;			/* 2 pi */
	extern double cs_Mpi;				/* -3.14159..... */
	extern double cs_Pi_o_2;			/* Pi over 2 */
	extern double cs_Zero;				/* 0.0 */
	extern double cs_Half;				/* 0.5 */
	extern double cs_One;				/* 1.0 */
	extern double cs_Two;				/* 2.0 */
	extern double cs_NPTest;			/* 0.001 seconds of arc
										   short of the north pole,
										   in radians. */
	extern double cs_AnglTest;			/* 0.001 seconds of arc,
										   in radians. */

	int rtn_val;

	double lng;				/* The given longitude, after conversion
							   to radians. */
	double lat;				/* The given latitude after conversion
							   to radians. */
	double del_lng;
	double abs_lat;
	double xx;
	double yy;

	double theta;
	double sin_theta, cos_theta;

	double A, A_sq;
	double P, P_sq;
	double G;
	double Q;
	double tmp1, tmp2, tmp3;

	rtn_val = cs_CNVRT_NRML;

	/* For this projection, we only support the spherical form,
	   therefore there is only one set of equations. */

	lng = ll [LNG] * cs_Degree;
	del_lng = lng - vdgrn->org_lng;
	if      (del_lng > cs_Pi  && vdgrn->org_lng < 0.0) del_lng -= cs_Two_pi;
	else if (del_lng < cs_Mpi && vdgrn->org_lng > 0.0) del_lng += cs_Two_pi;
	if (fabs (del_lng) > cs_Pi)
	{
		rtn_val = cs_CNVRT_RNG;
		del_lng = CS_adj2piI (del_lng);
	}

	lat = ll [LAT] * cs_Degree;
	abs_lat = fabs (lat);
	if (abs_lat > cs_NPTest)
	{
		rtn_val = cs_CNVRT_INDF;
		if (abs_lat > cs_Pi_o_2)
		{
			rtn_val = cs_CNVRT_RNG;
			lat = CS_adj1pi (lat);
			abs_lat = fabs (lat);
		}
	}

	if (abs_lat > cs_NPTest)
	{
		/* The sign of yy gets reversed below, we can simply
		   use cs_Pi here. */

		xx = cs_Zero;
		yy = cs_Pi * vdgrn->ka;
	}
	else if (abs_lat <= cs_AnglTest)
	{
		/* This is the calculation for the equator.

		   The sign of X gets reversed below, we need to use
		   the absolute value here. */

		xx = vdgrn->ka * fabs (del_lng);
		yy = cs_Zero;
	}
	else if (fabs (del_lng) < cs_AnglTest)
	{
		/* We're on the central meridian, BUT NOT on the
		   equator, and not at either pole. Npte, sign of
		   result is dealt with below. */

		xx = cs_Zero;
		theta = asin (abs_lat / cs_Pi_o_2);
		yy = cs_Pi * vdgrn->ka * tan (theta * cs_Half);
	}
	else
	{
		/* OK, we're not at either pole, or the equator.  The
		   rest of this should be pretty safe. */

		sin_theta = fabs (lat) * vdgrn->two_ovr_pi;
		cos_theta = sqrt (cs_One - sin_theta * sin_theta);

		tmp1 = (cs_Pi / del_lng) - (del_lng / cs_Pi);
		A = cs_Half * fabs (tmp1);
		A_sq = A * A;

		G = cos_theta / (sin_theta + cos_theta - cs_One);

		P = G * ((cs_Two / sin_theta) - cs_One);
		P_sq = P * P;

		Q = A_sq + G;

		tmp1 = P_sq + A_sq;
		tmp2 = G - P_sq;

		tmp3 = tmp1 * ((G * G) - P_sq);
		tmp3 = (A_sq * tmp2 * tmp2) - tmp3;
		if (tmp3 < 0.0) tmp3 = cs_Zero;
		tmp3 = (A * tmp2) + sqrt (tmp3);
		xx = vdgrn->piR * tmp3 / tmp1;

		tmp3 = ((A_sq + cs_One) * tmp1) - (Q * Q);
		if (tmp3 < 0.0) tmp3 = cs_Zero;
		tmp3 = (P * Q) - (A * sqrt (tmp3));
		yy = vdgrn->piR * tmp3 / tmp1;
	}

	/* Apply the appropriate sign and false origin. */

	xy [XX] = (del_lng >= 0.0) ? xx : -xx;
	xy [YY] = (lat     >= 0.0) ? yy : -yy;

	if (vdgrn->quad == 0)
	{
		xy [XX] += vdgrn->x_off;
		xy [YY] += vdgrn->y_off;
	}
	else
	{
		CS_quadF (xy,xy [XX],xy [YY],vdgrn->x_off,vdgrn->y_off,vdgrn->quad);
	}

	return (rtn_val);
}
Example #6
0
int EXP_LVL9 CSsinusF (Const struct cs_Sinus_ *sinus,double xy [2],Const double ll [2])
{
	extern double cs_Degree;			/* 1.0 / RADIAN  */
	extern double cs_Pi_o_2;			/* Pi over 2 */
	extern double cs_3Pi_o_2;			/* 3 Pi over 2 */
	extern double cs_Two_pi;			/* 2 Pi */
	extern double cs_One;				/* 1.0 */
	extern double cs_NPTest;			/* 0.001 seconds of arc
										   short of the north
										   pole, in radians. */

	int rtn_val;

	Const struct cs_Zone_ *zp;

	double lng;			/* The given longitude, after conversion
						   to radians. */
	double lat;			/* The given latitude after conversion
						   to radians. */

	double cent_lng;		/* Local central meridian after adjust-
							   ment for appropriate zones. */
	double x_off;			/* Local false easting after adjustment
							   for the appropriate zone. */
	double del_lng;
	double sin_lat;
	double cos_lat;
	double tmp1;

	rtn_val = cs_CNVRT_NRML;

	/* Convert the latitude and longitude to radians. */

	lat = cs_Degree * ll [LAT];
	if (fabs (lat) > cs_NPTest)
	{
		rtn_val = cs_CNVRT_INDF;
		if (fabs (lat) > cs_Pi_o_2)
		{
			rtn_val = cs_CNVRT_RNG;
			lat = CS_adj1pi (lat);
		}
	}
	lng = cs_Degree * ll [LNG];

	/* If there are any interrupted zones for this coordinate
	   system, select the proper zone for this longitude and
	   latitude.  Once selected, we use the zone to establish
	   the origin longitude and the appropriate false easting
	   for the zone. */

	if (sinus->zone_cnt > 0)
	{
		zp = CS_znlocF (sinus->zones,sinus->zone_cnt,lng,lat);
		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;
		}
	}
	else
	{
		zp = NULL;
		cent_lng = sinus->cent_lng;
		x_off    = sinus->x_off;
	}

	/* Perform the conversion. */

	del_lng = lng - cent_lng;
	if      (del_lng >  cs_3Pi_o_2 && cent_lng < 0.0) del_lng -= cs_Two_pi;
	else if (del_lng < -cs_3Pi_o_2 && cent_lng > 0.0) del_lng += cs_Two_pi;
	if (fabs (del_lng) >= cs_3Pi_o_2)
	{
		rtn_val = cs_CNVRT_RNG;
		del_lng = CS_adj2pi (del_lng);
	}

	if (sinus->ecent == 0.0)
	{
		/* Here for the sphere. */

		xy [XX] = sinus->ka * del_lng * cos (lat);
		xy [YY] = sinus->ka * lat;
	}
	else
	{
		/* Here for the ellipsoid. Tmp1 should never be zero. */

		sin_lat = sin (lat);
		cos_lat = cos (lat);
		tmp1 = cs_One - (sinus->e_sq * sin_lat * sin_lat);
		xy [XX] = sinus->ka * del_lng * cos_lat / sqrt (tmp1);
		xy [YY] = CSmmFcal (&sinus->mmcofF,lat,sin_lat,cos_lat);
	}

	/* Apply the false easting and northing.  Notice that the X
	   is now relative to the zone origin, thus we must use
	   the zone False Easting. */

	if (sinus->quad == 0)
	{
		xy [XX] += x_off;
		xy [YY] += sinus->y_off;
	}
	else
	{
		CS_quadF (xy,xy [XX],xy [YY],x_off,sinus->y_off,sinus->quad);
	}

	/* That's it. */

	return (rtn_val);
}
Example #7
0
int EXP_LVL9 CSorthoF (Const struct cs_Ortho_ *ortho,double xy [2],Const double ll [2])
{
	extern double cs_Degree;			/* 1.0 / RADIAN  */
	extern double cs_Pi;				/* 3.14159... */
	extern double cs_Mpi;				/* -3.14159... */
	extern double cs_Two_pi;			/* 2 Pi */
	extern double cs_Pi_o_2;			/* Pi over 2 */
	extern double cs_NPTest;			/* 0.001 seconds of arc
										   short of the north pole,
										   in radians. */

	int rtn_val;

	double lng;				/* The given longitude, after conversion
							   to radians. */
	double lat;				/* The given latitude after conversion
							   to radians. */
	double cos_c;			/* cosine of the angular distance from the
							   origin to the point. */
	double del_lng;
	double sin_del_lng;
	double cos_del_lng;
	double sin_lat;
	double cos_lat;

	double tmp;

	rtn_val = cs_CNVRT_NRML;

	/* For this projection, we only support the spherical form,
	   therefore there is only one set of equations.  These are
	   pretty simple. */

	lng = cs_Degree * ll [0];
	lat = cs_Degree * ll [1];

	if (fabs (lat) > cs_NPTest)
	{
		rtn_val = cs_CNVRT_INDF;
		if (fabs (lat) > cs_Pi_o_2)
		{
			rtn_val = cs_CNVRT_RNG;
			lat = CS_adj1pi (lat);
		}
	}

	del_lng = lng - ortho->org_lng;
	if      (del_lng > cs_Pi  && ortho->org_lng < 0.0) del_lng -= cs_Two_pi;
	else if (del_lng < cs_Mpi && ortho->org_lng > 0.0) del_lng += cs_Two_pi;
	if (fabs (del_lng) > cs_Pi)
	{
		rtn_val = cs_CNVRT_RNG;
		del_lng = CS_adj2pi (del_lng);
	}

	sin_del_lng = sin (del_lng);
	cos_del_lng = cos (del_lng);
	sin_lat = sin (lat);
	cos_lat = cos (lat);

	/* Is this point in range? */

	cos_c = (ortho->sin_org_lat * sin_lat) +
			(ortho->cos_org_lat * cos_lat * cos_del_lng);
	if (cos_c <= 0.0)
	{
		rtn_val = cs_CNVRT_RNG;
	}

	/* Certain computation efficiencies could be obtained by
	    handling the various aspects separately.  However, these
	    efficiences amount to two multiplies at most.  Therefore,
	    we would not save very much after we decide which aspect
	    to compute.

	    No divides, no atan2's, no square roots, no logs.  The
	    programmer's paradise. */

	xy [XX] = ortho->ka * cos_lat * sin_del_lng;
	tmp = (ortho->cos_org_lat * sin_lat) -
		  (ortho->sin_org_lat * cos_lat * cos_del_lng);
	xy [YY] = ortho->ka * tmp;

	if (ortho->quad == 0)
	{
		xy [XX] += ortho->x_off;
		xy [YY] += ortho->y_off;
	}
	else
	{
		CS_quadF (xy,xy [XX],xy [YY],ortho->x_off,ortho->y_off,
												  ortho->quad);
	}
	return (rtn_val);
}
Example #8
0
int EXP_LVL9 CSpstroF (Const struct cs_Pstro_ *pstro,double xy [2],Const double ll [2])

{
	extern char csErrnam [MAXPATH];

	extern double cs_Degree;			/* 1.0 / RADIAN  */
	extern double cs_Half;				/* 0.5 */
	extern double cs_One;				/* 1.0 */
	extern double cs_Pi;				/* 3.14159... */
	extern double cs_Pi_o_2;			/* PI over 2 */
	extern double cs_Pi_o_4;			/* PI over 4 */
	extern double cs_NPTest;			/* 0.001 seconds of arc
										   short of the north pole,
										   in radians. */
	extern double cs_Huge;				/* Huge value, but not too huge. */

	int rtn_val;

	double lng;				/* The given longitude, after conversion
							   to radians. */
	double lat;				/* The given latitude after conversion
							   to radians. */
	double x;
	double y;

	double del_lng;
	double sin_del_lng;
	double cos_del_lng;
	double sin_lat;

	double t;
	double rho;
	double tmp1;
	double tmp2;
	double tmp3;

	rtn_val = cs_CNVRT_NRML;

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

	lat = cs_Degree * ll [LAT];
	if (fabs (lat) > cs_NPTest)
	{
		rtn_val = cs_CNVRT_INDF;
		if (fabs (lat) > cs_Pi_o_2)
		{
			rtn_val = cs_CNVRT_RNG;
			lat = CS_adj1pi (lat);
		}
	}
	lng = cs_Degree * ll [LNG];
	
	/* We first adjust the following so that we can use much
	   of the code below for the southern polar aspect without
	   duplicating it with minor sign changes. */

	if (pstro->aspect == cs_STERO_SOUTH && pstro->ecent != 0.0)
	{
		lat = -lat;
		del_lng = pstro->org_lng - lng;
	}
	else
	{
		del_lng = lng - pstro->org_lng;
	}
	if (fabs (del_lng) > cs_Pi) del_lng = CS_adj2pi (del_lng);

	sin_del_lng = sin (del_lng);
	cos_del_lng = cos (del_lng);
	sin_lat = sin (lat);

	/* See if the datum is a sphere or an ellipsoid. */

	if (pstro->ecent == 0.0)
	{
		/* Here for the sphere. */

		switch (pstro->aspect) {

		case cs_STERO_NORTH:

			tmp1 = cs_Pi_o_4 - (lat * cs_Half);
			tmp1 = pstro->two_ka * tan (tmp1);

			x = tmp1 * sin_del_lng;
			y = -tmp1 * cos_del_lng;
			break;

		case cs_STERO_SOUTH:

			tmp1 = cs_Pi_o_4 + (lat * cs_Half);
			tmp1 = pstro->two_ka * tan (tmp1);

			x = tmp1 * sin_del_lng;
			y = tmp1 * cos_del_lng;
			break;
	
		default:
			x = y = -cs_Huge;
			CS_stncp (csErrnam,"CS_pstro:1",MAXPATH);
			CS_erpt (cs_ISER);
			rtn_val = -1;
			break;
		}									/*lint !e744 */
	}
	else
	{
		/* Here for an ellipsoid model of the earth. */

		tmp1 = pstro->ecent * sin_lat;
		tmp2 = (cs_One - tmp1) / (cs_One + tmp1);
		tmp2 = pow (tmp2,pstro->e_o_2);
		tmp3 = lat * cs_Half;
		t       = tan (cs_Pi_o_4 - tmp3) / tmp2;

		switch (pstro->aspect) {

		case cs_STERO_NORTH:

			rho = pstro->two_ka * t / pstro->e_term;

			x = rho * sin_del_lng;
			y = -rho * cos_del_lng;
			break;

		case cs_STERO_SOUTH:

			rho = pstro->two_ka * t / pstro->e_term;

			x = -rho * sin_del_lng;
			y = rho * cos_del_lng;
			break;

		default:

			x = y = -cs_Huge;
			CS_stncp (csErrnam,"CS_pstro:1",MAXPATH);
			CS_erpt (cs_ISER);
			rtn_val = -1;
			break;
		}									/*lint !e744 */
	}
	
	/* Adjust for the selected quadrant, and, finally, add false
	   easting and false northing. */

	xy [XX] = x;							/*lint !e644 */
	xy [YY] = y;							/*lint !e644 */

	if (pstro->quad == 0)
	{
		xy [XX] = x + pstro->x_off;
		xy [YY] = y + pstro->y_off;
	}
	else
	{
		CS_quadF (xy,x,y,pstro->x_off,pstro->y_off,pstro->quad);
	}
	return (rtn_val);
}
Example #9
0
int EXP_LVL9 CSmrcatF (Const struct cs_Mrcat_ *mrcat,double xy [2],Const double ll [2])
{
	extern double cs_One;				/* 1.0 */
	extern double cs_Degree;			/* 1.0 / 57.29577... */
	extern double cs_Two_pi;			/* 2 pi */
	extern double cs_Pi;				/*  Pi, i.e. 3.14159 */
	extern double cs_NPTest;			/* 0.001 arc seconds
										   short of the north
										   pole in radians. */
	extern double cs_SPTest;			/* 0.001 arc seconds
										   short of the south
										   pole in radians. */

	int rtn_val;

	double lng;
	double lat;
	double del_lng;

	double sin_lat;
	double esin_lat;

	double tmp1;
	double tmp2;

	rtn_val = cs_CNVRT_NRML;
	lng = ll [0] * cs_Degree;
	lat = ll [1] * cs_Degree;

	/* Deal with X, it's easy. */

	lng = cs_Degree * ll [LNG];
	del_lng = lng - mrcat->cent_lng;
	if      (del_lng >  cs_Pi) del_lng -= cs_Two_pi;
	else if (del_lng < -cs_Pi) del_lng += cs_Two_pi;
	if (fabs (del_lng) >= cs_Pi)
	{
		rtn_val = cs_CNVRT_RNG;
		del_lng = CS_adj2pi (del_lng);
	}
	xy [XX] = mrcat->Rfact * del_lng;

	/* Bogus values of latitude can cause big problems. */

	if (fabs (lat) > cs_NPTest)
	{
		rtn_val = cs_CNVRT_RNG;
		lat = CS_adj1pi (lat);
		if (lat > cs_NPTest)
		{
			lat = cs_NPTest;
		}
		if (lat < cs_SPTest)
		{
			lat = cs_SPTest;
		}
	}

	/* We should be OK now. */

	sin_lat = sin (lat);
	tmp1 = (cs_One + sin_lat) / (cs_One - sin_lat);

	if (mrcat->ecent == 0.0)
	{
		/* Here for a sphere. */
		
		xy [YY] = mrcat->Rfact_2 * log (tmp1);
	}
	else
	{
		/* Here for an ellipsoid. */

		esin_lat = mrcat->ecent * sin_lat;
		tmp2 = (cs_One - esin_lat) / (cs_One + esin_lat);
		tmp2 = tmp1 * pow (tmp2,mrcat->ecent);
		xy [YY] = mrcat->Rfact_2 * log (tmp2);
	}

	if (mrcat->quad == 0)
	{
		xy [XX] += mrcat->x_off;
		xy [YY] += mrcat->y_off;
	}
	else
	{
		CS_quadF (xy,xy [XX],xy [YY],mrcat->x_off,mrcat->y_off,mrcat->quad);
	}

	return (rtn_val);
}
Example #10
0
int EXP_LVL9 CSnzlndF (Const struct cs_Nzlnd_ *nzlnd,double xy [2],Const double ll [2])
{
	extern double cs_Degree;			/*  1.0 / RADIAN  */
	extern double cs_Zero;				/*  0.0 */
	extern double cs_One;				/*  1.0 */
	extern double cs_Mone;				/* -1.0 */
	extern double cs_Eight;				/*  8.0 */
	extern double cs_K180;				/*  180.0 */
	extern double cs_Km180;				/* -180.0 */
	extern double cs_K360;				/*  360.0 */

	int ii;
	int rtn_val;

	double del_lng;
	double del_lat;
	double del_psi;
	struct cs_Cmplx_ theta;

	rtn_val = cs_CNVRT_NRML;

	/* Note, the following look different than the sources as
	   the sources assume south latitude to be positive.  Our
	   convention is that south latitude is negative. */

	del_lng = (ll [LNG] - nzlnd->org_lng);
	if      (del_lng > cs_K180  && nzlnd->org_lng < 0.0) del_lng -= cs_K360;
	else if (del_lng < cs_Km180 && nzlnd->org_lng > 0.0) del_lng += cs_K360;
	if (fabs (del_lng) > cs_Eight)
	{
		rtn_val = cs_CNVRT_RNG;
		del_lng = (del_lng > 0.0) ? cs_Eight : -cs_Eight;
	}
	del_lng *= cs_Degree;

	del_lat = (ll [LAT] - nzlnd->org_lat);
	if (fabs (del_lat) > cs_Eight)
	{
		rtn_val = cs_CNVRT_RNG;
		del_lat = (del_lat > 0.0) ? cs_Eight : -cs_Eight;
	}
	del_lat *= nzlnd->lat_kk;

	del_psi = cs_Zero;
	for (ii = 9;ii >= 0;ii--)
	{
		del_psi = (del_psi + nzlnd->A_ary [ii]) * del_lat;
	}

	if (fabs (del_lng) > cs_One)
	{
		rtn_val = cs_CNVRT_RNG;
		del_lng = (del_lng > 0.0) ? cs_One : cs_Mone;
	}
	if (fabs (del_psi) > cs_One)
	{
		rtn_val = cs_CNVRT_RNG;
		del_psi = (del_psi > 0.0) ? cs_One : cs_Mone;
	}

	theta.real = del_psi;
	theta.img  = del_lng;
	CS_iisrs (&theta,nzlnd->B_ary,6,&theta);

	xy [XX] = (theta.img  * nzlnd->ka);
	xy [YY] = (theta.real * nzlnd->ka);

	if (nzlnd->quad == 0)
	{
		xy [XX] += nzlnd->x_off;
		xy [YY] += nzlnd->y_off;
	}
	else
	{
		CS_quadF (xy,xy [XX],xy [YY],nzlnd->x_off,nzlnd->y_off,
												  nzlnd->quad);
	}
	return (rtn_val);
}
Example #11
0
int EXP_LVL9 CStacylF (Const struct cs_Tacyl_ *tacyl,double xy [2],Const double ll [2])
{
    extern double cs_Zero;				/*  0.0 */
    extern double cs_One;				/*  1.0 */
    extern double cs_Mone;				/* -1.0 */
    extern double cs_Degree;			/*  1.0 / 57.29577... */
    extern double cs_Pi;				/*  3.14159... */
    extern double cs_Pi_o_2;			/*  PI/2 */
    extern double cs_AnglTest;			/* 0.001 arc seconds, in
										   radians. */
    extern double cs_NPTest;			/* 0.001 seconds of arc
										   short of the north pole,
										   in radians. */

    int rtn_val;

    double lng;
    double lat;
    double del_lng;

    double sin_lat;
    double esin_lat;

    double sin_beta;
    double beta, beta_c;
    double lat_c, sin_lat_c, cos_lat_c;
    double sin_del_lng;
    double cos_del_lng;
    double qq;
    double Mc;
    double tmp1;
    double tmp2;

    rtn_val = cs_CNVRT_NRML;

    /* The following is required by both the sperical and
       ellipsoidal forms. */

    lng = ll [LNG] * cs_Degree;
    del_lng = lng - tacyl->org_lng;

    /* The following statement is used to deal with the 180 degree crack. */

    if (fabs (del_lng) > cs_Pi) del_lng = CS_adj2pi (del_lng);

    sin_del_lng = sin (del_lng);
    cos_del_lng = cos (del_lng);


    lat = ll [LAT] * cs_Degree;
    if (fabs (lat) > cs_NPTest)
    {
        rtn_val = cs_CNVRT_INDF;
        if (fabs (lat) > cs_Pi_o_2)
        {
            rtn_val = cs_CNVRT_RNG;
            lat = CS_adj1pi (lat);
        }
    }

    if (tacyl->ecent == 0.0)
    {
        /* Here for the sphere. */

        xy [XX] = tacyl->ka_o_h0 * cos (lat) * sin_del_lng;
        if (fabs (cos_del_lng) > cs_AnglTest)
        {
            tmp1 = atan (tan (lat) / cos_del_lng);
        }
        else
        {
            /* We are 90 degrees or so away from the
               central meridian.  There is a singularity
               at del_lng == 90 and lat == 0.0

               However, there is a very rational result
               for this singularity point. */

            rtn_val = cs_CNVRT_RNG;
            if      (lat > cs_AnglTest) tmp1 = cs_Pi_o_2;
            else if (lat < cs_AnglTest) tmp1 = -cs_Pi_o_2;
            else			    tmp1 = cs_Zero;
        }
        xy [YY] = tacyl->kah0 * (tmp1 - tacyl->org_lat);
    }
    else
    {
        /* Here for the ellipsoid.  If we are at 90 degrees
           of longitude from the central meridian, the normal
           equations are indeterminate.  However, the result
           is well defined. */

        sin_lat = sin (lat);
        esin_lat = tacyl->ecent * sin_lat;
        tmp1 = (cs_One - esin_lat) / (cs_One + esin_lat);
        tmp1 = tacyl->one_o_2e * log (tmp1);
        tmp2 = sin_lat / (cs_One - esin_lat * esin_lat);
        qq = tacyl->one_m_esq * (tmp2 - tmp1);

        sin_beta = qq / tacyl->qp;
        if (fabs (sin_beta) >= cs_One)
        {
            sin_beta = (sin_beta >= 0.0) ? cs_One : cs_Mone;
        }
        beta = asin (sin_beta);
        if (fabs (cos_del_lng) > cs_AnglTest)
        {
            beta_c = atan (tan (beta) / cos_del_lng);
        }
        else
        {
            rtn_val = cs_CNVRT_RNG;
            if      (beta > cs_AnglTest) beta_c = cs_Pi_o_2;
            else if (beta < cs_AnglTest) beta_c = -cs_Pi_o_2;
            else			     beta_c = cs_Zero;
        }

        lat_c = CSbtIcalPrec (&tacyl->btcofI,beta_c);
        sin_lat_c = sin (lat_c);
        cos_lat_c = cos (lat_c);

        Mc = CSmmFcal (&tacyl->mmcofF,lat_c,sin_lat_c,cos_lat_c);
        xy [YY] = tacyl->h0 * (Mc - tacyl->M0);

        if (fabs (cos_del_lng) > cs_AnglTest)
        {
            tmp1 = cs_One - tacyl->e_sq * sin_lat_c * sin_lat_c;
            tmp1 = cos (beta_c) * sqrt (tmp1);
            tmp2 = cos (beta) * cos_lat_c * sin_del_lng;
            xy [XX] = tacyl->ka_o_h0 * (tmp2 / tmp1);
        }
        else
        {
            if (sin_del_lng >= 0.0) xy [XX] = tacyl->ka_o_h0;
            else			xy [XX] = -tacyl->ka_o_h0;
        }
    }

    if (tacyl->quad == 0)
    {
        xy [XX] += tacyl->x_off;
        xy [YY] += tacyl->y_off;
    }
    else
    {
        CS_quadF (xy,xy [XX],xy [YY],tacyl->x_off,tacyl->y_off,tacyl->quad);
    }
    return (rtn_val);
}
Example #12
0
int EXP_LVL9 CScsiniF (Const struct cs_Csini_ *csini,double xy [2],Const double ll [2])
{
	extern double cs_Degree;			/* 1.0 / 57.29577... */
	extern double cs_Pi;				/* 3.14159... */
	extern double cs_Half;				/* 0.5 */
	extern double cs_One;				/* 1.0 */
	extern double cs_Five;				/* 5.0 */
	extern double cs_Six;				/* 6.0 */
	extern double cs_Eight;				/* 8.0 */
	extern double cs_Pi_o_2;			/* Pi over 2 */
	extern double cs_NPTest;			/* 0.001 seconds of arc
										   short of the north pole,
										   in radians. */
	extern double cs_EETest;			/* 0.001 arc seconds short
										   of 90 degrees, in
										   readians. */
	extern double cs_WETest;			/* 0.001 arc seconds short
										   of -90 degrees, in
										   readians. */

	int rtn_val;

	double lng;
	double lat;
	double del_lng;

	double A;
	double A_2;
	double A_3;
	double A_4;
	double A_5;
	double B;
	double C;
	double M;
	double N;
	double T;

	double sin_lat;
	double cos_lat;
	double tan_lat;

	double tmp1;
	double tmp2;

	rtn_val = cs_CNVRT_NRML;

	lng = ll [0] * cs_Degree;
	lat = ll [1] * cs_Degree;

	if (fabs (lat) > cs_NPTest)
	{
		rtn_val = cs_CNVRT_INDF;
		if (fabs (lat) > cs_Pi_o_2)
		{
			rtn_val = cs_CNVRT_RNG;
			lat = CS_adj1pi (lat);
		}
	}

	del_lng = lng - csini->cent_lng;

	/* The following statement is required to handle the case where
	   the central meridian is -179, and the provided longitude is
	   +179, for example. */

	if (fabs (del_lng) > cs_Pi) del_lng = CS_adj2pi (del_lng);

	/* Del_lng of 90 degrees is a problem for this
	   projection. */

	if (fabs (del_lng) > cs_EETest)
	{
		rtn_val = cs_CNVRT_RNG;
		del_lng = (del_lng >= 0.0) ? cs_EETest : cs_WETest;
	}

	cos_lat = cos (lat);
	tan_lat = tan (lat);

	if (csini->ecent == 0.0)
	{
		/* Here for a sphere. */

		B = cos_lat * sin (del_lng);
		xy [XX] = csini->ka * asin (B);

		/* We've dealt with a del_lng of 90 degree above. */

		tmp1 = tan_lat / cos (del_lng);
		xy [YY] = csini->ka * (atan (tmp1) - csini->org_lat);
	}
	else
	{
		/* Here for an ellipsoid. */

		A = cos_lat * del_lng;
		A_2 = A * A;
		A_3 = A_2 * A;
		A_4 = A_2 * A_2;
		A_5 = A_3 * A_2;

		C = csini->C_term * cos_lat * cos_lat;

		sin_lat = sin (lat);
		tmp1 = csini->e_sq * sin_lat * sin_lat;
		N = csini->ka / sqrt (cs_One - tmp1);

		T = tan_lat * tan_lat;

		M = CSmmFcal (&csini->mmcofF,lat,sin_lat,cos_lat);

		/* Now for the x value. */

		tmp1 = A - (T * A_3 * (1.0 / 6.0));
		tmp2 = cs_Eight - T + cs_Eight * C;
		tmp1 = tmp1 + (tmp2 * T * A_5 * (1.0 / 120.0));
		xy [XX] = N * tmp1;

		/* Now the y. */

		tmp1 = cs_Five - T + (cs_Six * C);
		tmp1 = tmp1 * A_4 * (1.0 / 24.0);
		tmp1 += A_2 * cs_Half;
		xy [YY] = M - csini->M0 + (N * tan_lat * tmp1);
	}

	if (csini->quad == 0)
	{
		xy [XX] += csini->x_off;
		xy [YY] += csini->y_off;
	}
	else
	{
		CS_quadF (xy,xy [XX],xy [YY],csini->x_off,csini->y_off,
							  csini->quad);
	}

	return (rtn_val);
}
Example #13
0
int EXP_LVL9 CSlmtanF (Const struct cs_Lmtan_ *lmtan,double xy [2],Const double ll [2])
{
	extern double cs_Degree;			/* 1.0 / RADIAN  */
	extern double cs_Pi;				/* 3.14159... */
	extern double cs_Mpi;				/* -3.14159... */
	extern double cs_Two_pi;			/* 2 PI */
	extern double cs_Pi_o_2;			/* PI / 2.0  */
	extern double cs_Pi_o_4;			/* PI / 4.0  */
	extern double cs_Zero;				/* 0.0 */
	extern double cs_One;				/* 1.0 */
	extern double cs_Half;				/* 0.5 */
	extern double cs_NPTest;			/* 0.001 arc seconds short
										   of the north pole, in
										   in radians. */
	extern double cs_SPTest;			/* 0.001 arc seconds short
										   of the south pole, in
										   in radians. */

	int rtn_val;

	double lng;			/* The given longitude, after conversion
						   to radians. */
	double lat;			/* The given latitude after conversion
						   to radians. */
	double del_lng;
	double L0;
	double Gamma;
	double R;
	double tmp1;
	double tmp2;

	rtn_val = cs_CNVRT_NRML;

	lng = cs_Degree * ll [LNG];
	lat = cs_Degree * ll [LAT];

	/* Compute the polar angle, Gamma, also known as the
	   convergence angle. */

	del_lng = lng - lmtan->org_lng;
	if      (del_lng > cs_Pi  && lmtan->org_lng < 0.0) del_lng -= cs_Two_pi;
	else if (del_lng < cs_Mpi && lmtan->org_lng > 0.0) del_lng += cs_Two_pi;
	if (fabs (del_lng) > cs_Pi)
	{
		rtn_val = cs_CNVRT_RNG;
		del_lng = CS_adj2piI (del_lng);
	}
	Gamma = lmtan->sin_org_lat * del_lng;

	/* Now, we compute the radius of the polar arc. R will be
	   negative (lmtan->c is negative) if the south pole is
	   the focus pole of the coordinate system. */

	if (fabs (lat) > cs_NPTest)
	{
		if ((lat > 0.0) == (lmtan->sin_org_lat > 0.0))		/*lint !e731 !e777 */
		{
			rtn_val = cs_CNVRT_INDF;
		}
		if (fabs (lat) > cs_Pi_o_2)
		{
			rtn_val = cs_CNVRT_RNG;
			lat = CS_adj1pi (lat);
		}
	}
	if (lat > cs_NPTest)
	{
		R = (lmtan->sin_org_lat > 0.0) ? cs_Zero : lmtan->max_R;
	}
	else if (lat < cs_SPTest)
	{
		R = (lmtan->sin_org_lat < 0.0) ? cs_Zero : lmtan->max_R;
	}
	else
	{
		tmp1 = lmtan->ecent * sin (lat);
		tmp1 = (cs_One + tmp1) / (cs_One - tmp1);
		tmp1 = lmtan->e_ovr_2 * log (tmp1);
		tmp2 = cs_Pi_o_4 + (lat * cs_Half);

		/* Tmp2 can be zero (and thus tan(tmp2) can be zero)
		   at the south pole, but we've already dealt with
		   that. */

		tmp2 = log (tan (tmp2));
		L0 = tmp2 - tmp1;
		R = lmtan->c * exp (-lmtan->sin_org_lat * L0);
	}

	/* Convert to cartesian coordinates. Note, ys has the false
	   northing and the radius of the origin latitude built into
	   it by the setup function. */

	xy [XX] = R * sin (Gamma);
	xy [YY] = lmtan->R0 - (R * cos (Gamma));

	if (lmtan->quad == 0)
	{
		xy [XX] += lmtan->x_off;
		xy [YY] += lmtan->y_off;
	}
	else
	{
		CS_quadF (xy,xy [XX],xy [YY],lmtan->x_off,lmtan->y_off,
												  lmtan->quad);
	}

	return (rtn_val);
}