Exemplo n.º 1
0
double EXP_LVL5 CSccsphrR (Const double ll0 [2],Const double ll1 [2])
{
	extern double cs_Zero;			/* 0.0 */
	extern double cs_Half;			/* 0.5 */
	extern double cs_Two;			/* 2.0 */

	double cc;

	double sin_del_lng;
	double sin_del_lat;
	double cos_lat0;
	double cos_lat1;
	double tmp3;

	sin_del_lng = sin (CS_adj2pi (ll1 [LNG] - ll0 [LNG]) * cs_Half);
	sin_del_lat = sin (CS_adj1pi (ll1 [LAT] - ll0 [LAT]) * cs_Half);
	cos_lat0 = cos (CS_adj1pi (ll0 [LAT]));
	cos_lat1 = cos (CS_adj1pi (ll1 [LAT]));
	tmp3 = (sin_del_lat * sin_del_lat) +
		   (cos_lat0 * cos_lat1) * (sin_del_lng * sin_del_lng);
	if (tmp3 > 0.0)
	{
		cc = cs_Two * asin (sqrt (tmp3));
	}
	else
	{
		cc = cs_Zero;
	}
	return (cc);
}
Exemplo n.º 2
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;	
}
Exemplo n.º 3
0
int EXP_LVL9 CSazmedL (Const struct cs_Azmed_ *azmed,int cnt,Const double pnts [][3])
{
	extern double cs_Degree;		/* 1.0 / 57.29...... */
	extern double cs_Pi;			/* 3.14159....  */
	extern double cs_Pi_o_2;		/* PI over 2 */
	extern double cs_AnglTest;		/* 0.001 seconds of arc
									   in radians. */

	int ii;
	int status;

	double lat;
	double lng;
	double del_lng;

	/* Just check all points.  Only one point, the opposite
	   of the origin is a bust. */

	status = cs_CNVRT_OK;
	for (ii = 0;ii < cnt;ii++)
	{
		lat = pnts [ii][LAT] * cs_Degree;
		if (fabs (lat) > cs_Pi_o_2)
		{
			status = cs_CNVRT_DOMN;
			break;
		}
		if (fabs (lat + azmed->org_lat) > cs_AnglTest)
		{
			/* Latitude is definitely not anti-podal.
			   This point is OK. */

			continue;
		}
		lng = pnts [ii][LNG] * cs_Degree;
		del_lng = CS_adj2pi (lng - azmed->org_lng);
		if (fabs (fabs (del_lng) - cs_Pi) < cs_AnglTest)
		{
			/* Point is definitely opposite to the
			   origin.  It's a bust. */

			status = cs_CNVRT_DOMN;
			break;
		}
	}
	return (status);
}
Exemplo n.º 4
0
double EXP_LVL1 CS_azsphr (Const double ll0 [2],Const double ll1 [2])
{
	extern double cs_Degree;		/* PI / 180.0 */
	extern double cs_Radian;		/*  180.0 / PI */

	double az;
	double lng0, lng1;
	double lat0, lat1;
	double del_lng;
	double sin_del_lng, cos_del_lng;
	double sin_lat0, sin_lat1;
	double cos_lat0, cos_lat1;

	double tmp1;
	double tmp2;

	lng0 = ll0 [0] * cs_Degree;
	lat0 = ll0 [1] * cs_Degree;
	lng1 = ll1 [0] * cs_Degree;
	lat1 = ll1 [1] * cs_Degree;

	del_lng = CS_adj2pi (lng1 - lng0);
	sin_del_lng = sin (del_lng);
	cos_del_lng = cos (del_lng);

	sin_lat1 = sin (lat1);
	sin_lat0 = sin (lat0);
	cos_lat0 = cos (lat0);
	cos_lat1 = cos (lat1);

	tmp1 = cos_lat1 * sin_del_lng;
	tmp2 = cos_lat0 * sin_lat1;
	tmp2 -= sin_lat0 * cos_lat1 * cos_del_lng;
	if (fabs (tmp2) > 1.0E-08)
	{
		az = atan2 (tmp1,tmp2);
	}
	else
	{
		/* The latitudes are the same and delta longitude
		   is either zero or 180 (i.e. cos (del_lng) == 1). */

		az = del_lng;
	}
	return (az * cs_Radian);
}
Exemplo n.º 5
0
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);
}
Exemplo n.º 6
0
void EXP_LVL7 CSllnrml (Const double oll [2],Const double ll  [2],double ll1 [2],double ll2 [2])

{
	extern double cs_Zero;
	extern double cs_One;
	extern double cs_Radian;
	extern double cs_Degree;
	extern double cs_Pi_o_2;
	extern double cs_NPTest;

	double Az;
	double lng;
	double sin_Az;
	double cos_Az;
	double del_lng;
	double sin_lat;
	double cos_lat;
	double cos_org_lat;
	double sin_org_lat;
	double sin_del_lng;
	double cos_del_lng;

	double tmp1;
	double tmp2;
	double tmp3;
	double tmp4;
	double tmp5;
	double tmp6;

	lng = ll [0] * cs_Degree;
	tmp1 = oll [1] * cs_Degree;
	sin_org_lat = sin (tmp1);
	cos_org_lat = cos (tmp1);

	if (fabs (tmp1) < cs_NPTest)
	{
		del_lng = (ll [0] - oll [0]) * cs_Degree;
		sin_del_lng = sin (del_lng);
		cos_del_lng = cos (del_lng);
	}
	else
	{
		del_lng = cs_Zero;
		sin_del_lng = cs_Zero;
		cos_del_lng = cs_One;
	}

	tmp1 = ll [1] * cs_Degree;
	sin_lat = sin (tmp1);
	cos_lat = cos (tmp1);

	/* Compute the azimuth (assume a sphere) of the line from
	   the origin to the point in question. */

	tmp1 = cos_lat * sin_del_lng;
	tmp2 = (cos_org_lat * sin_lat) - (sin_org_lat * cos_lat * cos_del_lng);
	if (tmp2 < 1.0E-06)
	{
		Az = cs_Zero;
	}
	else
	{
		Az = atan2 (tmp1,tmp2);
	}

	/* Add 90 degrees, i.e. the azimuth of the normal line. */

	Az += cs_Pi_o_2;
	Az = CS_adj2pi (Az);

	/* Get the sine and cosine of the azimuth. */

	cos_Az = cos (Az);
	sin_Az = sin (Az);

	/* Compute two new lat/longs, using the appropriate signs
	   of sin_Az and cos_Az to place the new line on either
	   side of the given point. */

	tmp1 = sin_lat * cos_cc;
	tmp2 = cos_lat * cos_cc;
	tmp3 = sin_cc * sin_Az;
	tmp4 = sin_cc * cos_Az;
	tmp5 = cos_lat * tmp4;
	tmp6 = sin_lat * tmp4;

	ll1 [0] = lng + atan2 (tmp3,(tmp2 - tmp6));
	ll1 [0] = CS_adj2pi (ll1 [0]);
	ll1 [1] = asin (tmp1 + tmp5);

	ll2 [0] = lng + atan2 (-tmp3,(tmp2 + tmp6));
	ll2 [0] = CS_adj2pi (ll2 [0]);
	ll2 [1] = asin (tmp1 - tmp5);

	/* Adjust the longitudes to be in correct quads. */

	ll1 [0] *= cs_Radian;
	ll1 [1] *= cs_Radian;
	ll2 [0] *= cs_Radian;
	ll2 [1] *= cs_Radian;

	CS_adjll (ll1);
	CS_adjll (ll2);

	/* That's it. */

	return;
}
Exemplo n.º 7
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);
}
Exemplo n.º 8
0
double EXP_LVL1 CS_llazdd (	double e_rad,
							double e_sq,
							Const double ll_from [2],
							Const double ll_to [2],
							double *dist)

{
	extern double cs_Pi;			/* 3.14159.... */
	extern double cs_Mpi;			/* -3.14159.... */
	extern double cs_Pi_o_2;		/* 1.570796.... */
	extern double cs_Degree;		/* 1.0 / 57.29577... */
	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_Two;			/* 2.0 */
	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. */
	extern double cs_SPTest;		/* 0.001 seconds of arc short of
									   the south pole, in radians. */

	double az;
	double mm, mp;
	double del_lng;
	double del_lat;

	double cc;				/* Angular distance between the
							   two points on a sphere, in
							   radians of course. */
	double sin_co2;			/* sine of one half of the angular
							   distance, i.e. c over 2 */
	double tmp1;
	double tmp2;

	double from [2];
	double to [2];

	struct cs_MmcofF_ mm_cof;

	/* Convert the degrees we have been provided with to
	   radians for our computations. */

	from [LNG] = CS_adj2pi (ll_from [LNG] * cs_Degree);
	from [LAT] = CS_adj1pi (ll_from [LAT] * cs_Degree);

	to [LNG] = CS_adj2pi (ll_to [LNG] * cs_Degree);
	to [LAT] = CS_adj1pi (ll_to [LAT] * cs_Degree);

	del_lng = CS_adj2pi (to [LNG] - from [LNG]);
	del_lat = CS_adj1pi (to [LAT] - from [LAT]);

	/* Deal with the zero length arc. */

	if (fabs (del_lng) <= cs_AnglTest && fabs (del_lat) <= cs_AnglTest)
	{
		*dist = cs_Zero;
		return (cs_Zero);
	}

	/* Deal with the antipodal case.  Another situation which can
	   cause floating point exceptions. */

	if (fabs (del_lng) > (cs_Pi - cs_AnglTest))
	{ 
		/* Here only when it makes sense to check the latitude
		   for the anti-posal case.  This is not trivial. */

		tmp1 = CS_adj1pi (from [LAT]);
		tmp2 = CS_adj1pi (to [LAT]);
		if (fabs (tmp1 + tmp2) < cs_AnglTest)
		{
			/* Antipodal. The distance is tricky. */

			if (e_sq == 0.0)
			{
				/* Sphere. */

				*dist = cs_Pi * e_rad;
			}
			else
			{
				/* Ellipsoid. */

				CSmmFsu (&mm_cof,e_rad,e_sq);
				*dist = cs_Two * CSmmFcal (&mm_cof,cs_Pi_o_2,
								   cs_One,
								   cs_Zero);
			}

			/* The shortest distance is over a pole.  We could
			   choose either pole. By always using the north pole,
			   the returned results are the same for any antipodal
			   points. */

			return (cs_Zero);
		}
	}

	/* Now, we deal with the case where one of the two points is at
	   a pole.  This is a bit easier now that we know that only one
	   points can be at a pole. */

	if (fabs (from [LAT]) > cs_NPTest || fabs (to   [LAT]) < cs_SPTest)
	{
		/* One of the two points is a pole.  Compute the distance
		   to the pole from the equator for this ellipsoid. */

		if (e_sq == 0.0)
		{
			mp = cs_Pi_o_2 * e_rad;
		}
		else
		{
			CSmmFsu (&mm_cof,e_rad,e_sq);
			mp = CSmmFcal (&mm_cof,cs_Pi_o_2,cs_One,cs_Zero);
		}

		if (fabs (to [LAT]) > cs_NPTest)
		{
			/* The TO point is a pole.  The forward azimuth
			   is zero if its the north pole, -180 if its the
			   south pole. */

			if (to [LAT] > 0.0) az = cs_Zero;
			else		    az = cs_Mpi;

			/* Compute the distance of the from point
			   from the equator. */

			if (e_sq == 0.0)
			{
				mm = cs_Pi_o_2 * e_rad * sin (from [LAT]);
			}
			else
			{
				mm = CSmmFcal (&mm_cof,from [LAT],
						       sin (from [LAT]),
						       cos (from [LAT]));		/*lint !e645 */
			}
		}
		else
		{
			/* The FROM point is a pole.  The azimuth is -180
			   if its the north pole, zero if it is the south
			   pole. */

			if (from [LAT] > 0.0) az = cs_Mpi;
			else		      az = cs_Zero;

			/* Distance of the TO point from the equator. */

			if (e_sq == 0.0)
			{
				mm = cs_Pi_o_2 * e_rad * sin (to [LAT]);
			}
			else
			{
				mm = CSmmFcal (&mm_cof,to [LAT],
						       sin (to [LAT]),
						       cos (to [LAT]));
			}
		}

		/* Compute the distance. */

		if ((to [LAT] * from [LAT]) > 0.0) *dist = mp - fabs (mm);
		else				   *dist = mp + fabs (mm);

		return (az * cs_Radian);
	}

	/* Now, we calculate the angular length of the arc.  If the arc
	   length exceeds a specific value, we use the geodetic function,
	   CSllazdd to compute the necessary information.  Otherwise,
	   we use the spherical trigonometry given here. */

	tmp1 = sin (del_lng * cs_Half);
	tmp1 = cos (from [LAT]) * cos (to [LAT]) * tmp1 * tmp1;
	tmp2 = sin (del_lat * cs_Half);
	tmp2 *= tmp2;
	sin_co2 = sqrt (tmp2 + tmp1);

	if (e_sq != 0.0)
	{
		return (CSllazdd (e_rad,e_sq,from,to,dist));
	}

	cc = cs_Two * asin (sin_co2);
	*dist = cc * e_rad;
	az = asin (sin (del_lng) * cos (to [LAT]) / sin (cc));
	return (az * cs_Radian);
}
Exemplo n.º 9
0
static double CSllazdd (	double e_rad,
							double e_sq,
							double from [2],
							double to [2],
							double *dist)
{
	extern double cs_Radian;		/* 180 / pi */
	extern double cs_Zero;			/* 0.0 */
	extern double cs_One;			/* 1.0 */
	extern double cs_Two;			/* 2.0 */
	extern double cs_Three;			/* 3.0 */
	extern double cs_Four;			/* 4.0 */
	extern double cs_Six;			/* 6.0 */

	int itr_brk;

	double del_lng;
	double rr;
	double tu1, tu2;
	double cu1, cu2;
	double su1;
	double ss, sa, sx, sy;
	double cx, cy, cz;
	double cc, dd, ee;
	double xx, yy;
	double c2a;
	double faz, baz;
	double flat;
	double tmp1;

	/* To keep compilers and lint happy. */
	sy = cy = yy = c2a = cz = ee = cs_Zero;
	
	/* We use the flattening of the ellipsoid several times. */
	flat = cs_One - sqrt (cs_One - e_sq);
	rr = cs_One - flat;

	tu1 = rr * sin (from [LAT]) / cos (from [LAT]); 
	tu2 = rr * sin (to [LAT]) / cos (to [LAT]); 

	cu1 = cs_One / sqrt (cs_One + tu1 * tu1);
	su1 = cu1 * tu1;
	cu2 = cs_One / sqrt (cs_One + tu2 * tu2);

	ss = cu1 * cu2;
	baz = ss * tu2;
	faz = baz * tu1;

	/* We now have a rough approximation of the forward
	   azimuth, faz, the back azimuth, baz, and the
	   geodetic distance between the two points.  These
	   are just rough approximations.  We enter a
	   iterative loop which will recompute these
	   values until the difference between successive
	   approximations of the azimuth is less than delta. */

	del_lng = CS_adj2pi (to [LNG] - from [LNG]);
	xx = del_lng;
	itr_brk = 16;
	do
	{
		sx = sin (xx);
		cx = cos (xx);
		tu1 = cu2 * sx;
		tu2 = baz - (su1 * cu2 * cx);
		if (--itr_brk <= 0) break;
		sy = sqrt (tu1 * tu1 + tu2 * tu2);
		cy = ss * cx + faz;
		yy = atan2 (sy,cy);
		sa = ss * sx / sy;
		c2a = -sa * sa + cs_One;
		cz = faz + faz;
		if (c2a > 0.0)
		{
			cz = -cz / c2a + cy;
		}
		ee = (cs_Two * cz * cz) - cs_One;
		cc = c2a * flat * ((-cs_Three * c2a + cs_Four) * flat + cs_Four) / 16.0;
		dd = xx;
		xx = ((ee * cy * cc + cz) * sy * cc + yy) * sa;
		xx = (cs_One - cc) * xx * flat + del_lng;
	} while (fabs (dd - xx) > 0.5E-13);
	faz = atan2 (tu1,tu2);

	/* In the following, 1.0 / rr / rr is eqivalent to
	   1.0 / (rr * rr) */

	xx = sqrt ((cs_One / rr / rr - cs_One) * c2a + cs_One) + cs_One;
	xx = (xx - cs_Two) / xx;

	cc = cs_One - xx;
	cc = (((xx * xx) / cs_Four) + cs_One) / cc;

	dd = ((0.375 * xx * xx) - cs_One) * xx;

	xx = ee * cy;

	ss = cs_One - ee - ee;

	tmp1 = (sy * sy * cs_Four) - cs_Three;
	tmp1 = (tmp1 * ss * cz * dd) / cs_Six;
	tmp1 = (tmp1 - xx) * dd / cs_Four;
	tmp1 = (tmp1 + cz) * sy * dd + yy;

	ss = tmp1 * cc * e_rad * rr;

	*dist = ss;
	return (faz * cs_Radian);
}
Exemplo n.º 10
0
int EXP_LVL9 CSwinklI (Const struct cs_Winkl_ *winkl,double ll [2],Const double xy [2])
{
	extern double cs_Half;
	extern double cs_One;
	extern double cs_Radian;			/*  57.29577..... */
	extern double cs_3Pi_o_2;			/* 3 Pi over 2 */
	extern double cs_Pi_o_2;			/* Pi over 2 */
	extern double cs_AnglTest;
	extern double cs_Mpi;
	extern double cs_Pi;

	static double cnvrgK = 0.90;

	int rtn_val;
	int itr_cnt;

	double xx;
	double yy;
	double dd;
	double lat;
	double lng;
	double del_lng;
	double newX;
	double newY;
	double deltaX;
	double deltaY;

	rtn_val = cs_CNVRT_NRML;

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

	// Compute a first guess for the latitude and longitude using the
	// Equirectangular Inverse (which is easy enough) and an approximation of
	// the difference of the two.
	lat     = (yy / winkl->ka);
	del_lng  = xx / ( winkl->Rcos_ref_lat);			// equidistant
	del_lng *= (cs_One + 0.38 * cos (lat));			// Aitoff adjustment (approx)
	if (del_lng < cs_Mpi) del_lng = cs_Mpi + cs_AnglTest;
	else if (del_lng > cs_Pi) del_lng = cs_Pi - cs_AnglTest;

	itr_cnt = 0;
	do
	{
		rtn_val = CSwinklB (winkl,&newX,&newY,del_lng,lat);
		deltaX = newX - xx;
		deltaY = newY - yy;
		dd = sqrt (deltaX * deltaX + deltaY * deltaY);
		lat -= (deltaY / winkl->ka) * cnvrgK;
		del_lng -= (deltaX / winkl->Rcos_ref_lat) * cnvrgK;
		itr_cnt += 1;
	} while (itr_cnt < 40 && dd > winkl->one_mm);
	if (itr_cnt >= 40)
	{
		rtn_val = cs_CNVRT_ERR;
	}
	lng = (winkl->org_lng + del_lng);
	if (fabs (lng) >= cs_Pi)
	{
		lng = CS_adj2pi (lng);
	}

	ll [LNG] = lng * cs_Radian;
	ll [LAT] = lat * cs_Radian;
	return rtn_val;
}
Exemplo n.º 11
0
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);
}
Exemplo n.º 12
0
int EXP_LVL9 CSkrovkI (Const struct cs_Krovk_ *krovk,double lnglat [2],Const double xy [2])
{
	extern double cs_Radian;		/*  57.29577..... */
	extern double cs_Pi;			/*  Pi */
	extern double cs_Pi_o_2;		/*  Pi over 2 */
	extern double cs_Pi_o_4;		/*  Pi over 4 */
	extern double cs_Half;			/*  0.5 */
	extern double cs_One;			/*  1.0 */
	extern double cs_Two;			/*  2.0 */

	int rtn_val;

	double xx, yy;
	double rho, theta;
	double lngO, latO;
	double lngS, latS;
	double lngE, latE;

	double sinLatO, cosLatO;
	double sinLngS;
	double sinLatS, cosLatS;
	double tmp1;

	double tmp_xy [2];
	double deltaXY [2];

	rtn_val = cs_CNVRT_NRML;

	/* We use tmpxy as we don't want to change the provided parameters
	   on the user, that just isn't very nice. */
	tmp_xy [XX] = -xy [YY];
	tmp_xy [YY] = -xy [XX];

	/* Undo the strange stuff we did to get the desired result as far as
	   the axis numbers.  See the tail end of the forward function for
	   a description of what's going on here. */
	CS_quadI (&xx,&yy,tmp_xy,krovk->x_off,krovk->y_off,krovk->quad);

	/* Undo the 95 adjustment if appropriate. */
	if (krovk->apply95)
	{
		/* Note that this does not actually produce a real inverse.
		   The result is close, but not true.  A true mathematical
		   inverse does not exist (perhaps why the source doesn't
		   provide one).  We'll have to come up with a numerical
		   approximation to the inverse if the creep factor is too
		   large. */
		tmp_xy [XX] = xx;
		tmp_xy [YY] = yy;
		CSkrovk95 (deltaXY,tmp_xy);
		xx += deltaXY [XX];
		yy += deltaXY [YY];
	}

	/* Convert the X and Y to polar coordinates. */
	theta = atan2 (yy,xx);
	rho = sqrt (yy * yy + xx * xx);

	/* Check the results for bogus values. */
	if (rho < krovk->pole_test)
	{
		/* If rho is very small, the point is on the pole and we can
		   simply return that value now. */
		lnglat [LNG] = krovk->poleLng * cs_Radian;
		lnglat [LAT] = krovk->poleLat * cs_Radian;
		return rtn_val;
	}
	if (rho > krovk->infinity)
	{
		/* If rho is huge, we respond with a point at the opposite pole. */
		lnglat [LNG] = CS_adj2pi (krovk->poleLng - cs_Pi) * cs_Radian;
		lnglat [LAT] = -krovk->poleLat * cs_Radian;
		return rtn_val;
	}
	if (fabs (theta) >= krovk->theta_max)
	{
		/* Opps, the point is in the conic crack.  Adjust. */
		theta = theta > 0.0 ? krovk->theta_max : -krovk->theta_max;
	}

	/* Convert the polar coordinates to lat/long on the oblique sphere.  This
	   uses the Lambert Conformal technique, not necessarily the same
	   formulas. */
	lngO = theta / krovk->nn;
	tmp1 = pow (krovk->tanTermI / rho,krovk->one_o_nn);
	latO = cs_Two * atan (tmp1) - cs_Pi_o_2;
	/* From the Czech document test case:
		 lngO =? 21.8191895277777; latO =? 77.7249551388888 */

	/* Convert from the oblique sphere to the gausian surface. */
	sinLatO = sin (latO);
	cosLatO = cos (latO);
	sinLatS = krovk->sinLatQ * sinLatO - krovk->cosLatQ * cosLatO * cos (lngO);
	cosLatS = sqrt (cs_One - sinLatS * sinLatS);
	latS = atan (sinLatS / cosLatS);
	sinLngS = (cosLatO / cosLatS) * sin (lngO);
	lngS = krovk->lngQ - asin (sinLngS);

	/* Convert from the gausian surface to the ellipsoid. If the
	   reference is a sphere, don't really need to do anything. */
	if (krovk->ecent == 0.0)
	{
		lngE = lngS;
		latE = latS;
	}
	else
	{
		lngE = lngS / krovk->alpha;
		latE = CSkrovkB3 (krovk,latS);
	}

	/* Convert the results to degrees. */
	lnglat [LNG] = (lngE + krovk->orgLng) * cs_Radian;
	lnglat [LAT] = latE * cs_Radian;
	return (rtn_val);
}
Exemplo n.º 13
0
double EXP_LVL9 CScsiniH (Const struct cs_Csini_ *csini,Const double ll [2])
{
	extern double cs_Degree;			/* 1.0 / 57.29577... */
	extern double cs_One;				/* 1.0 */
	extern double cs_Eight;				/* 8.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
										   calculations without
										   problems. */
	extern double cs_SclInf;			/* 9.9E+04, the value we
										   return for an infinite
										   scale factor. */

	double h;
	double xx;
	double lng;
	double lat;
	double del_lng;

	double sin_lat;
	double cos_lat;
	double tan_lat;

	double N, C, T, B;
	double A, A_3, A_5;

	double tmp1;

	lng = ll [LNG] * cs_Degree;
	lat = ll [LAT] * cs_Degree;
	del_lng = CS_adj2pi (lng - csini->cent_lng);
	cos_lat = cos (lat);

	if (csini->ecent == 0.0)
	{
		/* Here for a spherical.  Blows up at the equator
		   when del_lng is 90 degrees. */

		B = cos_lat * sin (del_lng);
		tmp1 = cs_One - (B * B);
		if (tmp1 > cs_AnglTest)
		{
			h = cs_One / sqrt (tmp1);
		}
		else
		{
			h = cs_SclInf;
		}
	}
	else
	{
		/* Here for an ellipsoid.  We need to compute the X
		   location of the given point first.  Note, this
		   can bust if we're not careful. */

		A = cos_lat * (del_lng);
		A_5 = A * A * (A_3 = A * A * A);

		C = csini->C_term * cos_lat * cos_lat;

		sin_lat = sin (lat);

		/* Blows up at the poles. */

		if (fabs (cos_lat) > cs_AnglTest)
		{
			tan_lat = sin_lat / cos_lat;
			T = tan_lat * tan_lat;
		}
		else
		{
			T = cs_Huge;
		}

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

		/* Now for the X value. */

		xx = A - (T * A_3 * (1.0 / 6.0));
		xx -= (cs_Eight - T + cs_Eight * C) * T * A_5 * (1.0 / 120.0);
		xx *= N;

		/* Now for H.  We use Synder's equation 13-9, with Az set
		   to zero, thus cosine squared Az is 1.0. */

		h = cs_One + ((xx * tmp1) * (xx * tmp1)) / csini->s_term;
	}
	return (h);
}
Exemplo n.º 14
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);
}
Exemplo n.º 15
0
double EXP_LVL9 CSorthoH (Const struct cs_Ortho_ *ortho,Const double ll [2])
{
	extern double cs_Degree;			/*  1.0 / RADIAN */
	extern double cs_Pi_o_2;			/*  Pi over 2 */
	extern double cs_Mone;				/* -1.0 */
	extern double cs_AnglTest;			/* 0.001 arc seconds in radians. */
	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. */

	double lng;
	double lat;
	double del_lng;
	double h;

	double cos_lat;
	double sin_lat;
	double cos_del_lng;

	lat = ll [LAT] * cs_Degree;
	if (fabs (lat) > cs_Pi_o_2)
	{
		return (cs_Mone);
	}
	sin_lat = sin (lat);

	/* We can save significant computation by examining the
	   aspect of the projection. Note, the setup function sets
	   sin_org_lat and cos_org_lat to hard values appropriate for
	   each aspect. */

	if (ortho->org_lat >= cs_NPTest)
	{
		/* North polar aspect. */

		h = sin_lat;
	}
	else if (ortho->org_lat <= cs_SPTest)
	{
		/* South polar aspect. */

		h = -sin_lat;
	}
	else
	{
		lng = ll [LNG] * cs_Degree;
		del_lng = CS_adj2pi (lng - ortho->org_lng);
		cos_del_lng = cos (del_lng);
		cos_lat = cos (lat);

		if (fabs (ortho->org_lat) <= cs_AnglTest)
		{
			/* Equatorial aspect. */

			h = cos_lat * cos_del_lng;
		}
		else
		{
			/* Oblique aspect. */

			h = (ortho->sin_org_lat * sin_lat) +
			    (ortho->cos_org_lat * cos_lat * cos_del_lng);
		}
	}
	return (h);
}
Exemplo n.º 16
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);
}
Exemplo n.º 17
0
int EXP_LVL9 CSmrcatI (Const struct cs_Mrcat_ *mrcat,double ll [2],Const double xy [2])
{
	extern double cs_Radian;			/* 57.29577... */
	extern double cs_Pi_o_2;			/* Pi / 2.0 */
	extern double cs_3Pi_o_2;			/* 3 Pi / 2.0 */
	extern double cs_Two;				/* 2.0 */

	int rtn_val;

	double xx;
	double yy;

	double chi;
	double lat;
	double del_lng;
	double tmp1;

	rtn_val = cs_CNVRT_NRML;

	/* Remove whatever offsets are active. */

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

	/* Check the Y value for range. */

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

	/* The longitude calculation is the same for both the
	   spherical and ellipsoidal cases.  There may be a
	   slight difference if the standard parallel is not
	   the equator, but tis is taken care of during set up
	   and shows up in the Rfact variable. */

	del_lng = xx / mrcat->Rfact;
	if (fabs (del_lng) >= cs_3Pi_o_2)
	{
	    	rtn_val = cs_CNVRT_RNG;
		del_lng = CS_adj2pi (del_lng);
	}

	/* The following is used for sphere and ellipsoid. */

	tmp1 = exp (-yy / mrcat->Rfact);
	chi = cs_Pi_o_2 - cs_Two * atan (tmp1);

	/* Finish off the latitude as appropriate. */

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

		lat = chi;
	}
	else
	{
		/* Here for an ellipsoid.  This is a series
		   expansion used in other projections, so we
		   have a function to do this for us. */

		lat = CSchiIcal (&mrcat->chicofI,chi);
	}

	ll [LNG] = (del_lng + mrcat->cent_lng) * cs_Radian;
	ll [LAT] = lat * cs_Radian;
	return (rtn_val);
}
Exemplo n.º 18
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);
}
Exemplo n.º 19
0
double EXP_LVL9 CSsinusH (Const struct cs_Sinus_ *sinus,Const double ll [2])
{
	extern double cs_Degree;			/* 1.0 / RADIAN  */
	extern double cs_Pi_o_2;			/* Pi over 2 */
	extern double cs_One;				/* 1.0 */
	extern double cs_Mone;				/* -1.0 */
	extern double cs_SclInf;			/* 9.9E+04, the value we
										   return for an infinite
										   scale factor. */
	extern double cs_NPTest;			/* 0.001 arc seconds short
										   of the north pole, in
										   radians. */
	int status;

	Const struct cs_Zone_ *zp;

	double hh;
	double lng;
	double lat;

	double del_lng;
	double sin_lat;
	double cent_lng;

	double ll_dd;
	double xy_dd;
	double del_xx, del_yy;
	double xy1 [2];
	double xy2 [2];
	double ll1 [2];
	double ll2 [2];

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

	/* A latitude above either pole is an error.  At either pole,
	   the scale is 1.0.  We deal with these now to prevent
	   divides by zero below. */

	if (fabs (lat) > cs_NPTest)
	{
		if (fabs (lat) > cs_Pi_o_2)
		{
			return (cs_Mone);
		}
		else
		{
			return (cs_One);
		}
	}

	/* Determine which zone we're in, assuming there are some
	   zones active. */

	if (sinus->zone_cnt > 0)
	{
		zp = CS_znlocF (sinus->zones,sinus->zone_cnt,lng,lat);
		if (zp != NULL)
		{
			cent_lng = zp->cent_lng;
		}
		else
		{
			/* Opps!!!  No zone, even though they are
			   active.  The lat/long are bogus. */

			return (cs_Mone);
		}
	}
	else
	{
		zp = NULL;
		cent_lng = sinus->cent_lng;
	}

	/* Different algorithms for sphere or ellipsoid. */

	if (sinus->ecent == 0.0)
	{
		del_lng = CS_adj2pi (lng - cent_lng);
		sin_lat = sin (lat);
		hh = sqrt (cs_One + (del_lng * del_lng) * (sin_lat * sin_lat));
	}
	else
	{
		/* We haven'y located a formula for the ellipsoid yet.

		   Establish two points along the meridian which are
		   about 1 second (about 30 meters) apart from each
		   other, with the point in question in the middle.
		   Then convert each point to the equivalent grid
		   coordinates. */

		ll1 [LNG] = ll [LNG];
		ll1 [LAT] = ll [LAT] - (0.5 / 3600.0);
		status = CSsinusF (sinus,xy1,ll1);
		if (status != cs_CNVRT_NRML)
		{
			return (cs_Mone);
		}

		ll2 [LNG] = ll [LNG];
		ll2 [LAT] = ll [LAT] + (0.5 / 3600.0);
		status = CSsinusF (sinus,xy2,ll2);
		if (status != cs_CNVRT_NRML)
		{
			return (cs_Mone);
		}

		/* Calculate the geodetic distance between the two
		   lat/long points.  Note, we provide the geodetic
		   calculator with the scaled radius of the earth
		   so that the distance it computes will be in the
		   same units as the X and Y coordinates. */

		CS_llazdd (sinus->ka,sinus->e_sq,ll1,ll2,&ll_dd);

		/* Calculate the grid distance between the two points. */

		del_xx = xy1 [XX] - xy2 [XX];
		del_yy = xy1 [YY] - xy2 [YY];
		xy_dd = sqrt (del_xx * del_xx + del_yy * del_yy);

		/* Return the ratio of the two distances as the
		   meridian scale factor at the indicated point.
		   ll_dd should never be zero here, but just in
		   case: */

		if (ll_dd > sinus->one_mm)
		{
			hh = xy_dd / ll_dd;
		}
		else
		{
			hh = cs_SclInf;
		}
	}
	return (hh);
}
Exemplo n.º 20
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);
}
Exemplo n.º 21
0
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);
}
Exemplo n.º 22
0
int EXP_LVL1 CS_azddll (double e_rad,
			double e_sq,
			Const double ll_from [2],
			double az,
			double dist,
			double ll_to [2])

{
	extern double cs_Pi;			/* 3.14159.... */
	extern double cs_Degree;		/* 1.0 / 57.29577... */
	extern double cs_Radian;		/* 57.29577... */
	extern double cs_Zero;			/* 0.0 */
	extern double cs_Fourth;		/* 0.25*/
	extern double cs_One;			/* 1.0 */
	extern double cs_Two;			/* 2.0 */
	extern double cs_Three;			/* 3.0 */
	extern double cs_Four;			/* 4.0 */

	int status;
	int itr_cnt;

	double rr, rr2;
	double sf, cf;
	double sy, cy;
	double tu, cu, su;
	double sa, cz;
	double c2a;
	double xx, yy;
	double cc, dd, ee;
	double tmp;
	double faz, baz;
	double flat;

	double from [2];

	status = 0;

	/* Convert to radians. */

	from [LNG] = CS_adj2pi (ll_from [LNG] * cs_Degree);
	from [LAT] = CS_adj1pi (ll_from [LAT] * cs_Degree);
	faz = az * cs_Degree;

	/* CS-MAP is driven by eccentricity, this guy works off
	   flattening */

	flat = cs_One - sqrt (cs_One - e_sq);

	/* The following is a conversion from FORTRAN of the
	   Subroutine named DIRCT1 in the FOWARD program. I
	   really have no idea as to what is going on here,
	   ither then there is what appears to be a Newton
	   Rhapson iteration.

	   We have followed the variable nomenclature used in
	   the FORWARD program with two exceptions:

	   1) we have used lower case,
	   2) we have doubled up all single letter variable names.
	*/

	rr = cs_One - flat;
	rr2 = rr * rr;
	tu = rr * sin (from [LAT]) / cos (from [LAT]);
	sf = sin (faz);
	cf = cos (faz);
	if (fabs (tu) >= 1.0E-13 || fabs (cf) >= 1.0E-13)
	{
		baz = cs_Two * atan2 (tu,cf);
	}
	else
	{
		baz = cs_Zero;
	}
	cu = cs_One / sqrt (cs_One + tu * tu);
	su = tu * cu;
	sa = cu * sf;
	c2a = cs_One - sa * sa;

	tmp = c2a * (cs_One / rr2 - cs_One) + cs_One;
	xx = sqrt (tmp) + cs_One;
	xx = (xx - cs_Two) / xx;

	cc = cs_One - xx;
	cc = (cs_Fourth * xx * xx + cs_One) / cc;

	dd = (0.375 * xx * xx - cs_One) * xx;
	tu = dist /  rr / e_rad / cc;
	yy = tu;

	itr_cnt = 20;
	do
	{
		sy = sin (yy);
		cy = cos (yy);
		cz = cos (baz + yy);
		ee = cz * cz * cs_Two - cs_One;
		cc = yy;
		xx = ee * cy;
		yy = ee + ee - cs_One;
		tmp = cs_Four * sy * sy - cs_Three;
		tmp *= yy * cz * dd * (1.0 / 6.0);
		tmp += xx;
		tmp *= dd * cs_Fourth;
		tmp -= cz;
		tmp *= sy * dd;
		yy = tmp + tu;
	} while (fabs (yy - cc) > 0.5E-13 && itr_cnt-- > 0);
	if (itr_cnt <= 0) status = -1;

	baz = (cu * cy * cf) - (su * sy);
	cc = rr * sqrt ((sa * sa) + (baz * baz));
	dd = (su * cy) + (cu * sy * cf);
	ll_to [LAT] = atan2 (dd,cc);

	cc = (cu * cy) - (su * sy * cf);
	xx = atan2 (sy * sf,cc);
	tmp = (cs_Four - cs_Three * c2a) * flat + cs_Four;
	cc = tmp * c2a * flat / 16.0;
	tmp = (ee * cy * cc) + cz;
	tmp *= sy * cc;
	dd = (tmp + yy) * sa;
	tmp = (cs_One - cc) * dd * flat;
	ll_to [LNG] = from [LNG] + xx - tmp;
	baz = atan2 (sa,baz) + cs_Pi;

	/* Convert back to degrees. */

	ll_to [LNG] = CS_adj2pi (ll_to [LNG]) * cs_Radian;
	ll_to [LAT] *= cs_Radian;

	return (status);
}
Exemplo n.º 23
0
double EXP_LVL9 CSazmedK (Const struct cs_Azmed_ *azmed,Const double ll [2])
{
	extern double cs_Degree;			/* 1.0 / 57.29577... */
	extern double cs_Radian;			/* 57.29577... */
	extern double cs_Pi_o_2;			/* PI / 2.0 */
	extern double cs_One;				/* 1.0 */
	extern double cs_Mone;				/* -1.0 */
	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. */
	extern double cs_AnglTest1;			/* 1 - sin of 0.001 seconds
										   of arc. */
	extern double cs_SclInf;			/* 9.9E+04, the value we
										   return for an infinite
										   scale factor. */

	int status;

	double kk;
	double lng;
	double lat;
	double del_lng;
	double sin_lat;
	double cos_lat;
	double cos_cc;
	double cc;
	double xy_dd;
	double ll_dd;
	double del_xx;
	double del_yy;
	double rho;
	double tmp;
	double M;

	double oll [2];
	double ll1 [2];
	double ll2 [2];
	double xy1 [2];
	double xy2 [2];

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

		lat = ll [LAT] * cs_Degree;
		lng = ll [LNG] * cs_Degree;
		del_lng = CS_adj2pi (lng - azmed->org_lng);

		/* What aspect? */

		switch (azmed->aspect) {

		case cs_AZMED_NORTH:

			if (lat >= cs_NPTest)
			{
				kk = cs_One;
			}
			else if (lat <= cs_SPTest)
			{
				kk = cs_SclInf;
			}
			else
			{
				kk = (cs_Pi_o_2 - lat) / cos (lat);
			}
			break;

		case cs_AZMED_SOUTH:

			if (lat <= cs_SPTest)
			{
				kk = cs_One;
			}
			else if (lat >= cs_NPTest)
			{
				kk = cs_SclInf;
			}
			else
			{
				kk = (cs_Pi_o_2 + lat) / cos (lat);
			}
			break;

		default:
		case cs_AZMED_GUAM:
		case cs_AZMED_EQUATOR:
		case cs_AZMED_OBLIQUE:

			lng = ll [LNG] * cs_Degree;
			del_lng = CS_adj2pi (lng - azmed->org_lng);

			/* Read cc as the angular distance to the
			   point in question, from the origin. */

			cos_cc = azmed->sin_org_lat * sin (lat) +
					azmed->cos_org_lat * cos (lat) *
					cos (del_lng);

			if (cos_cc > cs_AnglTest1)
			{
				/* The origin. */
				kk = cs_One;
			}
			else if (cos_cc < -cs_AnglTest1)
			{
				/* AntiPodal */
				kk = cs_SclInf;
			}
			else
			{
				/* We can divide by sin (cc). */
				cc = acos (cos_cc);
				kk = cc / sin (cc);
			}
			break;
		}
	}
	else
	{
		/* Here for the ellipsoidal case. */

		switch (azmed->aspect) {

		case cs_AZMED_NORTH:

			lat = ll [LAT] * cs_Degree;
			if (lat >= cs_NPTest)
			{
				kk = cs_One;
			}
			else if (lat < cs_SPTest)
			{
				kk = cs_SclInf;
			}
			else
			{
				/* Here when we can divide by cos (lat) */

				sin_lat = sin (lat);
				cos_lat = cos (lat);
				M = CSmmFcal (&azmed->mmcofF,lat,sin_lat,cos_lat);
				rho = azmed->Mp - M;
				tmp = cs_One - azmed->e_sq * sin_lat * sin_lat;
				kk = rho * sqrt (tmp) / (cos_lat * azmed->ka);
			}
			break;

		case cs_AZMED_SOUTH:

			lat = ll [LAT] * cs_Degree;
			if (lat <= cs_SPTest)
			{
				kk = cs_One;
			}
			else if (lat >= cs_NPTest)
			{
				kk = cs_SclInf;
			}
			else
			{
				/* Here when we can divide by cos (lat) */

				sin_lat = sin (lat);
				cos_lat = cos (lat);
				M = CSmmFcal (&azmed->mmcofF,lat,sin_lat,cos_lat);
				rho = M + azmed->Mp;
				tmp = cs_One - azmed->e_sq * sin_lat * sin_lat;
				kk = rho * sqrt (tmp) / (cos_lat * azmed->ka);
			}
			break;

		default:
		case cs_AZMED_GUAM:
		case cs_AZMED_EQUATOR:
		case cs_AZMED_OBLIQUE:

			/* We do not have analytical formulas for these aspects,
			   so until we do:

			   CSllnrml computes the lat/long of two points
			   which form a geodesic of one arc second which
			   is normal to the geodesic from the origin
			   (oll) to the point in question (ll). */

			oll [0] = azmed->org_lng * cs_Radian;
			oll [1] = azmed->org_lat * cs_Radian;
			CSllnrml (oll,ll,ll1,ll2);

			/* Convert the resulting lat/longs to cartesian
			   coordinates. */

			status = CSazmedF (azmed,xy1,ll1);
			if (status != cs_CNVRT_NRML)
			{
				return (cs_Mone);
			}
			status = CSazmedF (azmed,xy2,ll2);
			if (status != cs_CNVRT_NRML)
			{
				return (cs_Mone);
			}

			/* Calculate the geodetic distance between the two
			   lat/long points.  Note, we provide the geodetic
			   calculator with the scaled radius of the earth
			   so that the distance it computes will be in the
			   same units as the X and Y coordinates. */

			CS_llazdd (azmed->ka,azmed->e_sq,ll1,ll2,&ll_dd);

			/* Calculate the grid distance between the two
			   points. */

			del_xx = xy1 [XX] - xy2 [XX];
			del_yy = xy1 [YY] - xy2 [YY];
			xy_dd = sqrt (del_xx * del_xx + del_yy * del_yy);

			/* Return the ratio of the two distances as the
			   parallel scale factor at the indicated point. */

			kk = xy_dd / ll_dd;
			break;
		}
	}
	return (kk);
}
Exemplo n.º 24
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);
}
Exemplo n.º 25
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);
}
Exemplo n.º 26
0
int EXP_LVL9 CSlmtanL (Const struct cs_Lmtan_ *lmtan,int cnt,Const double pnts [][3])
{
	extern double cs_Degree;		/* 1.0 / 57.2... */
	extern double cs_Pi;			/*  PI */
	extern double cs_NPTest;		/* .001 seconds of arc short of
									   the north pole, in radians. */

	int ii;
	int status;
	int sgn_lng1, sgn_lng2;

	double tmp;
	double del_lng1, del_lng2;

	/* Check all the points.  */

	status = cs_CNVRT_OK;
	for (ii = 0;ii < cnt;ii++)
	{
		tmp = pnts [ii][LAT] * cs_Degree;
		if (fabs (tmp) > cs_NPTest)
		{
			status = cs_CNVRT_DOMN;
			break;
		}
	}
	if (cnt <= 1 || status != cs_CNVRT_OK)
	{
		return (status);
	}

	/* Now, need to see if any segment cross the back side of the
	   central meridian. */

	tmp = pnts [0][LNG] * cs_Degree;
	del_lng1 = CS_adj2pi (tmp - lmtan->org_lng);
	sgn_lng1 = (del_lng1 < 0.0);
	for (ii = 1;ii < cnt;ii++)
	{
		/* Does the line cross the back azimuth of the
		   central meridian??? */

		tmp = pnts [ii][LNG] * cs_Degree;
		del_lng2 = CS_adj2pi (tmp - lmtan->org_lng);
		sgn_lng2 = (del_lng2 < 0.0);
		if (sgn_lng1 != sgn_lng2)
		{
			/* Crosses the central meridian or the back
			   azimuth.  Which one? */

			tmp = fabs (del_lng1) + fabs (del_lng2);
			if (tmp > cs_Pi)
			{
				/* Opps!!! We have a problem. */

				status = cs_CNVRT_DOMN;
				break;
			}
		}

		/* Set up for the next segment. */

		del_lng1 = del_lng2;
		sgn_lng1 = sgn_lng2;
	}

	return (status);
}