Exemplo n.º 1
0
int EXP_LVL9 CSmrcatX (Const struct cs_Mrcat_ *mrcat,int cnt,Const double pnts [][3])
{
	int ii;
	int rtn_val;

	double test_val;
	double dummy;

	rtn_val = cs_CNVRT_OK;

	/* All X values are within the domain of the function.  However,
	   in the cartesian frame of reference, an absolute value of
	   Y greater than yy_max is outside of the domain. */

	for (ii = 0;ii < cnt && rtn_val == cs_CNVRT_OK;ii++)
	{
		if (mrcat->quad == 0)
		{
			test_val = pnts [ii][YY] - mrcat->y_off;
		}
		else
		{
			CS_quadI (&test_val,&dummy,pnts [ii],mrcat->x_off,
												 mrcat->y_off,
												 mrcat->quad);
		}

		if (fabs (test_val) > mrcat->yy_max)
		{
			rtn_val = cs_CNVRT_DOMN;
			break;
		}
	}
	return (rtn_val);
}
Exemplo n.º 2
0
static int CSlmtanXP (	Const struct cs_Lmtan_ *lmtan,Const double xy [2],double *gamma)
{
	double my_xx, my_yy;
	double R;

	/* Convert to polar coordinates. */

	if (lmtan->quad == 0)
	{
		my_xx = xy [XX] - lmtan->x_off;
		my_yy = xy [YY] - lmtan->y_off;
	}
	else
	{
		CS_quadI (&my_xx,&my_yy,xy,lmtan->x_off,lmtan->y_off,lmtan->quad);
	}
	my_yy -= lmtan->R0;
	R = sqrt (my_xx * my_xx + my_yy * my_yy);
	if (R < lmtan->one_mm || R > lmtan->max_R)
	{
		return (cs_CNVRT_DOMN);
	}
	*gamma = atan2 (my_xx,-my_yy);
	if (fabs (*gamma) > lmtan->max_Gamma)
	{
		return (cs_CNVRT_DOMN);
	}
	return (cs_CNVRT_OK);
}
Exemplo n.º 3
0
int EXP_LVL9 CStacylX (Const struct cs_Tacyl_ *tacyl,int cnt,Const double pnts [][3])
{
    int ii;
    int rtn_val;

    double xx, yy;

    rtn_val = cs_CNVRT_OK;

    /* Check that all X's and Y's are within the basic
       range.  No special checks are required for lines and/or
       regions. */

    for (ii = 0; ii < cnt; ii++)
    {
        if (tacyl->quad == 0)
        {
            xx = pnts [ii][XX] - tacyl->x_off;
            yy = pnts [ii][YY] - tacyl->y_off;
        }
        else
        {
            CS_quadI (&xx,&yy,pnts [ii],tacyl->x_off,tacyl->y_off,tacyl->quad);
        }
        if (fabs (xx) > tacyl->max_xx || fabs (yy) > tacyl->max_yy)
        {
            rtn_val = cs_CNVRT_DOMN;
            break;
        }
    }
    return (rtn_val);
}
Exemplo n.º 4
0
int EXP_LVL9 CSazmedX (Const struct cs_Azmed_ *azmed,int cnt,Const double pnts [][3])
{
	int ii;
	int rtn_val;

	double dd;
	double xx, yy;

	rtn_val = cs_CNVRT_OK;

	/* Simply check that all X's and Y's are within the maximum
	   radius of the projection.  No special checks are required
	   for lines and/or regions. */

	for (ii = 0;ii < cnt;ii++)
	{
		if (azmed->quad == 0)
		{
			xx = pnts [ii][XX] - azmed->x_off;
			yy = pnts [ii][YY] - azmed->y_off;
		}
		else
		{
			CS_quadI (&xx,&yy,pnts [ii],azmed->x_off,
						    azmed->y_off,
						    azmed->quad);
		}

		dd = sqrt (xx * xx + yy * yy);
		if (dd > azmed->max_rho)
		{
			rtn_val = cs_CNVRT_DOMN;
			break;
		}
	}
	return (rtn_val);
}
Exemplo n.º 5
0
int EXP_LVL9 CSazmedI (Const struct cs_Azmed_ *azmed,double ll [2],Const double xy [2])
{
	extern char csErrnam [];

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

	int rtn_val;
	int itr_cnt;

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

	double my_xy [2];

	rtn_val = cs_CNVRT_NRML;

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

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

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

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

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

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

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

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

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

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

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

		switch (azmed->aspect) {

		case cs_AZMED_NORTH:

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

		case cs_AZMED_SOUTH:

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

		case cs_AZMED_EQUATOR:

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

		case cs_AZMED_GUAM:

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

			/* Longitude is undefined at the poles. */

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

		case cs_AZMED_OBLIQUE:

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

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

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

		switch (azmed->aspect) {

		case cs_AZMED_NORTH:

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

		case cs_AZMED_SOUTH:

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

		case cs_AZMED_GUAM:

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

			/* Longitude is undefined at the poles. */

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

		case cs_AZMED_EQUATOR:
		case cs_AZMED_OBLIQUE:

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

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

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

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

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

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

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

		default:

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

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

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

		ll [LNG] = (del_lng + azmed->org_lng) * cs_Radian;
		ll [LAT] = lat * cs_Radian;
	}
	return (rtn_val);
}
Exemplo n.º 6
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.º 7
0
int EXP_LVL9 CSvdgrnI (Const struct cs_Vdgrn_ *vdgrn,double ll [2],Const double xy [2])
{
	/* We undefine the following as these identifiers are used
	   as variables in order to match the notation used in Synder. */

	extern double cs_Radian;			/*  57.29577..... */
	extern double cs_Pi;				/* 3.14159....  */
	extern double cs_Mpi;				/*-3.14159....  */
	extern double cs_Pi_o_3;			/* PI / 3.0 */
	extern double cs_Zero;				/* 0.0 */
	extern double cs_Third;				/* 0.33333..... */
	extern double cs_One;				/* 1.0 */
	extern double cs_Mone;				/* -1.0 */
	extern double cs_Two;				/* 2.0 */
	extern double cs_Three;				/* 3.0 */
	extern double cs_Nine;				/* 9.0 */
	extern double cs_Pi_o_2;			/* Pi over 2 */
	extern double cs_Mpi_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 x;
	double y;

	double lat;
	double del_lng;

	double xx, xx2;
	double yy, yy2, two_yy2;
	double xx2_yy2, xx2_yy2_sq;
	double c1;
	double c2, c2_sq, c2_cube;
	double c3, c3_sq, c3_cube;
	double dd;
	double a1;
	double m1;
	double theta1;

	double tmp;

	rtn_val = cs_CNVRT_NRML;

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

	/* Deal with bogus x and y coordinates.  Should do this without
	   the square root for performance purposes. */

	tmp = sqrt (x * x + y * y);
	if (tmp > vdgrn->piR)
	{
		rtn_val = cs_CNVRT_RNG;
		x *= vdgrn->piR / tmp;
		y *= vdgrn->piR / tmp;
	}

	/* Set up all repeated variations of X and Y. */

	xx = x / vdgrn->piR;
	yy = y / vdgrn->piR;
	xx2 = xx * xx;
	yy2 = yy * yy;
	two_yy2 = yy2 + yy2;
	xx2_yy2 = xx2 + yy2;
	xx2_yy2_sq = xx2_yy2 * xx2_yy2;

	/* Compute the internal constants. */

	c1 = -(fabs (yy) * (cs_One + xx2_yy2));

	c2 = c1 - two_yy2 + xx2;
	c2_sq = c2 * c2;
	c2_cube = c2_sq * c2;

	c3 = cs_One - (cs_Two * c1) + two_yy2 + xx2_yy2_sq;
	c3_sq = c3 * c3;
	c3_cube = c3_sq * c3;

	/* Compute the latitude.  The ((3 * dd) / (a1 * m1))
	   term goes to infinity when Y is zero.  Since Y == 0 means
	   the equator for this projection, we punt and simply
	   set lat = 0.0 in this case. */

	if (fabs (y) <= vdgrn->one_mm)
	{
		lat = cs_Zero;
	}
	else
	{
		tmp = (cs_Two * c2_cube / c3_cube) - (cs_Nine * c1 * c2 / c3_sq);
		dd = (yy2 / c3) + (tmp / 27.0);
		a1 = (c1 - (c2_sq / (cs_Three * c3))) / c3;
		m1 = cs_Two * sqrt ((-a1) / cs_Three);
		tmp = (cs_Three * dd) / (a1 * m1);

		/* tmp, at this point, should never be greater than
		   one.  However, noise in the lower bits makes the
		   following necessary. */

		if (fabs (tmp) >= cs_One)
		{
			tmp = (tmp >= 0.0) ? cs_One : cs_Mone;
		}
		theta1 = cs_Third * acos (tmp);
		tmp = cos (theta1 + cs_Pi_o_3);
		lat = cs_Pi * ((-m1 * tmp) - (c2 / (cs_Three * c3)));
		if (y < 0) lat = -lat;
	}

	/* If xx is zero, the following falls apart, but longitude
	   is equal to the origin longitude. */

	if (fabs (x) < vdgrn->one_mm)
	{
		del_lng = cs_Zero;
	}
	else
	{
		tmp = cs_One + cs_Two * (xx2 - yy2) + xx2_yy2_sq;
		tmp = xx2_yy2 - cs_One + sqrt (tmp);
		/* Following divide by 2X causes the blow up. */
		del_lng = ((cs_Pi * tmp) / (cs_Two * xx));
	}

	/* Convert the results to degrees. */

	if (fabs (del_lng) > cs_Pi)
	{
		del_lng = (del_lng > 0.0) ? cs_Pi : cs_Mpi;
		rtn_val = cs_CNVRT_RNG;
	}
	if (fabs (lat) > cs_NPTest)
	{
		rtn_val = cs_CNVRT_INDF;
		if (fabs (lat) > cs_Pi_o_2)
		{
			rtn_val = cs_CNVRT_RNG;
			lat = (lat > 0.0) ? cs_Pi_o_2 : cs_Mpi_o_2;
		}
	}
	ll [LNG] = (del_lng + vdgrn->org_lng) * cs_Radian;
	ll [LAT] = lat * cs_Radian;

	return (rtn_val);
}
Exemplo n.º 8
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.º 9
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.º 10
0
int EXP_LVL9 CSorthoI (Const struct cs_Ortho_ *ortho,double ll [2],Const double xy [2])
{
	extern double cs_Radian;			/* 57.29577..... */
	extern double cs_Zero;				/*  0.0 */
	extern double cs_One;				/*  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. */

	int rtn_val;

	double x;
	double y;
	double rho;

	double lat;
	double del_lng;
	double sin_c;
	double cos_c;

	double tmp;

	rtn_val = cs_CNVRT_NRML;

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

	del_lng = cs_Zero;
	rho = sqrt (x * x + y * y);
	if (rho < ortho->one_mm)
	{
		/* This code eliminates many possible glitches in the
		   code below. */

		lat = ortho->org_lat;
	}
	else
	{
		/* The latitude calculation is common to all aspects.
		   c is the angular distance from the origin to the
		   point being converted.  Thus, by limiting rho
		   to ka, -pi/4 <= c >= pi/4, and cos_c is always
		   positive (possibly zero), and since we have already
		   handled the case of rho == 0, sin_c will never be
		   zero. */

		if (rho > ortho->ka)
		{
			rtn_val = cs_CNVRT_RNG;
			x *= ortho->ka / rho;
			y *= ortho->ka / rho;
			rho = ortho->ka;
		}
		sin_c = rho / ortho->ka;
		cos_c = sqrt (cs_One - (sin_c * sin_c));

		/* We handled rho == 0 above. */

		tmp = (y * sin_c * ortho->cos_org_lat) / rho;
		tmp = (cos_c * ortho->sin_org_lat) + tmp;
		lat = asin (tmp);

		/* The longitude calculation is much faster for the
		   two polar aspects.  There is no mathematical reason
		   for having three different cases.

		   Note, we force the values of sin_org_lat and
		   cos_org_lat to hard values in the setup function. */

		if (ortho->org_lat >= cs_NPTest)
		{
			/* Here for the north polar aspect:
			   cos_org_lat = 0, sin_org_lat = +1.
			   Since rho is not zero, we know that
			   either x or y is not zero. */

			del_lng = atan2 (x,-y);
		}
		else if (ortho->org_lat <= cs_SPTest)
		{
			/* Here for the south polar aspect:
			   cos_org_lat = 0, sin_org_lat = -1 */

			del_lng = atan2 (x,y);
		}
		else if (fabs (ortho->org_lat) <= cs_AnglTest)
		{
			/* Here for the equatorial aspect:
			   cos_org_lat = 1, sin_org_lat = 0.

			   Careful, there is a point at which both args
			   to atan2 here could be zero: x=0,y=ka.  If x is
			   zero, the point is on the central meridian.

			   Since this is an equatorial aspect, we need not
			   worry about polar wrap around. */

			if (fabs (x) > ortho->one_mm)
			{
				del_lng = atan2 (x * sin_c,rho * cos_c);
			}
		}
		else
		{
			/* Here for the oblique aspect. Again, if x == 0,
			   it is possible for both arguments to atan2 to
			   be zero. (org_lat=pi/4, c=pi/4). */

			if (fabs (x) > ortho->one_mm)
			{
				tmp = (rho * ortho->cos_org_lat * cos_c) -
					  (  y * ortho->sin_org_lat * sin_c);

				del_lng = atan2 (x * sin_c,tmp);
			}
		}
	}
	if (fabs (lat) > cs_NPTest && rtn_val == cs_CNVRT_NRML)
	{
		rtn_val = cs_CNVRT_INDF;
	}
		
	/* Convert the results to degrees. */

	ll [LNG] = (del_lng + ortho->org_lng) * cs_Radian;
	ll [LAT] = lat * cs_Radian;

	return (rtn_val);
}
Exemplo n.º 11
0
int EXP_LVL9 CSpstroI (Const struct cs_Pstro_ *pstro,double ll [2],Const double xy [2])
{
	extern double cs_Radian;			/*  57.29577..... */
	extern double cs_Two;				/* 2.0 */
	extern double cs_Pi_o_2;			/* PI over 2.0 */
	extern double cs_NPTest;			/* 0.001 seconds of arc
										   short of the north pole,
										   in radians. */

	int rtn_val;

	double x;
	double y;

	double c;
	double t;
	double chi;
	double rho;
	double cos_c;

	rtn_val = cs_CNVRT_NRML;

	/* Adjust for a non-standard quadrant. */

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

	/* If x and y are now both zero, or very close to it,
	   we must just set the result to the origin of the
	   projection.  We don't want to divide by rho if it's
	   zero. */

	rho = sqrt (x * x + y * y);
	if (rho <= pstro->one_mm)
	{
		/* The coordinate is essentially zero.  Return
		   the origin of the coordinate system. */

		ll [LNG] = pstro->org_lng * cs_Radian;
		ll [LAT] = pstro->org_lat * cs_Radian;
		return (rtn_val);
	}
		
	/* Now we can convert back to lat/longs. */

	if (pstro->ecent == 0.0)
	{
		/* Here for the sphere.  Note, we have already
		   filtered out cases where rho is zero (or very
		   close to zero).

		   Note, rho can approach infinity, although considering
		   values greater than two_ka out of the domain would
		   be generally acceptable. Read c as the angular distance
		   from the origin. */

		c = cs_Two * atan (rho / pstro->two_ka);
		cos_c = cos (c);

		switch (pstro->aspect) {

		default:
		case cs_STERO_NORTH:

			ll [LNG] = pstro->org_lng + atan2 (x,-y);
			ll [LAT] = asin (cos_c);
			break;

		case cs_STERO_SOUTH:

			ll [LNG] = -pstro->org_lng + atan2 (-x,y);
			ll [LAT] = -asin (cos_c);
			break;
		}
	}
	else
	{
		/* Here for the ellisoid. */

		switch (pstro->aspect) {

		default:
		case cs_STERO_NORTH:

			ll [LNG] = pstro->org_lng + atan2 (x,-y);
			t = rho * pstro->e_term / pstro->two_ka;
			chi = cs_Pi_o_2 - (cs_Two * atan (t));
			ll [LAT] = CSchiIcal (&pstro->chicofI,chi);
			break;

		case cs_STERO_SOUTH:

			ll [LNG] = pstro->org_lng - atan2 (-x,y);
			t = rho * pstro->e_term / pstro->two_ka;
			chi = (cs_Two * atan (t)) - cs_Pi_o_2;
			ll [LAT] = CSchiIcal (&pstro->chicofI,chi);
			break;
		}
	}
	if (fabs (ll [LAT]) > cs_NPTest && rtn_val == cs_CNVRT_NRML)	/*lint !e774 */
	{
		rtn_val = cs_CNVRT_INDF;
	}

	/* Convert the results to degrees. */

	ll [LNG] *= cs_Radian;
	ll [LAT] *= cs_Radian;

	return (rtn_val);
}
Exemplo n.º 12
0
int EXP_LVL9 CSlmtanI (Const struct cs_Lmtan_ *lmtan,double ll [2],Const double xy [2])
{
	extern double cs_Pi_o_2;			/* PI / 2.0  */
	extern double cs_Radian;			/* 57.29577..... */
	extern double cs_Zero;				/* 0.0 */
	extern double cs_One;				/* 1.0 */
	extern double cs_Two;				/* 2.0 */
	extern double cs_AnglTest;			/* 0.001 arc seconds,
										   in radians. */

	int i_cnt;
	int rtn_val;

	double x;
	double y;
	double R;
	double L;
	double exp_L;
	double Gamma;
	double del_lng;
	double new_lat;
	double last_lat;
	double tmp1;

	rtn_val = cs_CNVRT_NRML;

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

	/* Set R equal to the length of the line from the
	   origin to the point being converted.  Gamma is
	   the angle portion of the polar coordinate system. */

	R = sqrt (x * x + y * y);
	if (R > lmtan->max_R)
	{
		/* R is too large, the coordinates provided must be
		   really bogus. */

		rtn_val = cs_CNVRT_RNG;
		R = lmtan->max_R;
	}

	/* If R is not zero, then at least one of x and y is not zero, and
	   the atan2 function should be happy. */

	if (R > lmtan->one_mm)
	{
		Gamma = atan2 (x,-y);
	}
	else
	{
		/* If R is zero, we are at the focus pole, and any
		   gamma, like zero, will do nicely since longitude is
		   (mathematically) undefined at this point. */

		Gamma = cs_Zero;
		rtn_val = cs_CNVRT_INDF;
	}
	if (fabs (Gamma) > lmtan->max_Gamma)
	{
		/* Coordinate is in the pie slice opposite the
		   central meridian. */

		rtn_val = cs_CNVRT_RNG;
		Gamma = (Gamma > 0.0) ? lmtan->max_Gamma : -lmtan->max_Gamma;
	}

	/* Compute the longitude. sin_org_lat should never be zero as a
	   zero origin latitude is not permitted by CSlmtanQ. If the
	   coordinate system has a south pole focus, sin_org_lat
	   will be negative, thereby effecting the necessary reversal
	   on the sense of gamma. */

	del_lng = Gamma / lmtan->sin_org_lat;

	/* The latitude is a bit more difficult.  We first compute
	   the isometric latitude.  The use of abs_c here precludes
	   taking the log of a negative number.  We've already dealt
	   with the case of R being zero; c and sin_org_lat are
	   never zero. */

	L = -(log (R / lmtan->abs_c) / lmtan->sin_org_lat);
	exp_L = exp (L);
	new_lat = cs_Two * atan (exp_L) - cs_Pi_o_2;

	/* We must now iterate to convert the isometric latitude to
	   the geographic latitude that we desire.  We could use
	   our CSchiIcal function to calculate the latitude without
	   iteration, but we choose to iterate to duplicate the
	   algorithm published by the French NGI which is the primary
	   user of this projection.  If the iteration fails to
	   converge, we assume that we are out of range.  Since we
	   limited latitude to reasonable values above, I don't think
	   this can happen. */

	i_cnt = -12;
	do
	{
		last_lat = new_lat;
		tmp1 = lmtan->ecent * sin (last_lat);
		tmp1 = (cs_One + tmp1) / (cs_One - tmp1);
		tmp1 = pow (tmp1,lmtan->e_ovr_2);
		tmp1 *= exp_L;
		new_lat = cs_Two * atan (tmp1) - cs_Pi_o_2;
		if (i_cnt++ > 0)
		{
		    	rtn_val = cs_CNVRT_RNG;
		    	break;
		}
	} while (fabs (new_lat - last_lat) > cs_AnglTest);

	ll [LNG] = (del_lng + lmtan->org_lng) * cs_Radian;
	ll [LAT] = new_lat * cs_Radian;

	return (rtn_val);
}
Exemplo n.º 13
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.º 14
0
int EXP_LVL9 CSnzlndI (Const struct cs_Nzlnd_ *nzlnd,double ll [2],Const double xy [2])
{
	extern double cs_Radian;			/*  57.29577..... */
	extern double cs_Zero;				/* 0.0 */
	extern double cs_One;				/* 1.0 */
	extern double cs_K90;				/* 90.0 */
	
	int ii;
	int rtn_val;

	double xx;
	double yy;
	double rho;
	double lat;
	double del_psi,del_lat;

	struct cs_Cmplx_ zz;
	struct cs_Cmplx_ theta;
	struct cs_Cmplx_ theta1;
	struct cs_Cmplx_ theta2;

	rtn_val = cs_CNVRT_NRML;

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

	if (fabs (xx) > cs_One || fabs (yy) > cs_One)
	{
		rtn_val = cs_CNVRT_RNG;
		rho = sqrt (xx * xx + yy * yy);

		xx /= rho;
		yy /= rho;
	}

	zz.real = yy;
	zz.img  = xx;
	CS_iisrs (&zz,nzlnd->C_ary,6,&theta);

	for (ii = 0;ii < 2;ii++)
	{
		CS_iisrs1 (&theta,nzlnd->B_ary,6,&theta1);
		CS_iisrs0 (&theta,nzlnd->B_ary,6,&theta2);
		CS_iiadd  (&zz,&theta2,&theta2);
		CS_iidiv  (&theta2,&theta1,&theta);
	}

	del_psi = theta.real;
	del_lat = cs_Zero;
	for (ii = 8;ii >= 0;ii--)
	{
		del_lat = (del_lat + nzlnd->D_ary [ii]) * del_psi;
	}

	ll [LNG] = CS_adj180 (theta.img * cs_Radian) + nzlnd->org_lng;
	lat = CS_adj90  (del_lat / nzlnd->lat_kk) + nzlnd->org_lat;
	if (fabs (lat) > cs_K90)
	{
		rtn_val = cs_CNVRT_RNG;
		lat = CS_adj90 (lat);
	}
	ll [LAT] = lat;
	return (rtn_val);
}
Exemplo n.º 15
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.º 16
0
int EXP_LVL9 CSunityI (Const struct cs_Unity_ *unity,double ll [2],Const double xy [2])
{
	extern double cs_Zero;				/*    0.0 */
	extern double cs_K90;				/*   90.0 */
	extern double cs_Km90;				/*  -90.0 */

	int rtn_val;

	double lcl_xy [2];

	rtn_val = cs_CNVRT_NRML;

	/* Apply the quadrant processing. This is usually used to make
	   west longitude positive. */

	if (unity->quad == 0)
	{
		lcl_xy [XX] = xy [XX];
		lcl_xy [YY] = xy [YY];
	}
	else
	{
		CS_quadI (&lcl_xy [XX],&lcl_xy [YY],xy,cs_Zero,cs_Zero,unity->quad);
	}

	/* See if the user supplied values are with the user's
	   specified range.  If not, we have a domain error,
	   and we normalize to the user's specified range
	   before proceeding. */

	if (lcl_xy [XX] < unity->usr_min || lcl_xy [XX] > unity->usr_max)
	{
		rtn_val = cs_CNVRT_DOMN;
		lcl_xy [XX] -= unity->usr_min;
		lcl_xy [XX] = fmod (lcl_xy [XX],unity->usr_2pi);
		lcl_xy [XX] += unity->usr_min;
	}

	/* Convert the supplied values to internal units and
	   referencing. */

	ll [LNG] = unity->gwo_lng + (lcl_xy [XX] / unity->unit_s);
	ll [LAT] = lcl_xy [YY] / unity->unit_s;

	/* Normalize the longitude to internal standards. */

	ll [LNG] = CS_adj270 (ll [LNG]);

	/* If the resulting latitude is out of range, we do have a
	   problem. */


	if (ll [LAT] < cs_Km90 || ll [LAT] > cs_K90)
	{
		/* Not within the user's expected range. */

		rtn_val = cs_CNVRT_RNG;
		ll [LAT] = CS_adj90 (ll [LAT]);
	}
	return (rtn_val);
}
Exemplo n.º 17
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);
}