Ejemplo n.º 1
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);
}
Ejemplo n.º 2
0
void EXP_LVL9 CSazmedS (struct cs_Csprm_ *csprm)
{
	extern short cs_QuadMin;		/* -4 */
	extern short cs_QuadMap [];
	extern double cs_Pi;			/* 3.14159.... */
	extern double cs_Pi_o_2;		/*  PI / 2.0     */
	extern double cs_Mpi_o_2;		/*  PI / 2.0     */
	extern double cs_Radian;		/* 180.0 / pi */
	extern double cs_Degree;		/* 1.0 / RADIAN  */
	extern double cs_One;			/* 1.0 */
	extern double cs_Two;			/* 2.0 */
	extern double cs_Mone;			/* -1.0 */
	extern double cs_Zero;			/* 0.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. */
	extern double cs_SPTest;		/* 0.001 seconds of arc
									   short of the south pole,
									   in radians. */
	extern double cs_Km180;			/* -180.0 */
	extern double cs_K180;			/*  180.0 */
	extern double cs_Km90;			/* -90.0 */
	extern double cs_K90;			/*  90.0 */
	extern double cs_K60;			/*  60.0 */
	extern double cs_Ten;			/*  10.0 */

	struct cs_Azmed_ *azmed;

	double height;
	double tmp1;

	azmed = &csprm->proj_prms.azmed;

	height = cs_Zero;
	if (csprm->prj_code == cs_PRJCOD_AZEDE)
	{
		height = csprm->csdef.prj_prm2 * csprm->csdef.unit_scl;
	}

	/* Transfer the necessary arguments to the
	   "azmed" structure.  Notice, the conversion
	   from degrees to radians which is performed
	   in the process. */

	azmed->org_lng = csprm->csdef.org_lng * cs_Degree;
	azmed->org_lat = csprm->csdef.org_lat * cs_Degree;
	azmed->k = csprm->csdef.scale;
	azmed->x_off = csprm->csdef.x_off;
	azmed->y_off = csprm->csdef.y_off;
	azmed->ecent = csprm->datum.ecent;
	azmed->e_sq = azmed->ecent * azmed->ecent;
	azmed->one_esq = cs_One - azmed->e_sq;
	azmed->rt_one_esq = sqrt (azmed->one_esq);
	azmed->ka = (csprm->datum.e_rad + height) * azmed->k;
	azmed->two_ka = azmed->ka + azmed->ka;
	azmed->cos_org_lat = cos (azmed->org_lat);
	azmed->sin_org_lat = sin (azmed->org_lat);
	azmed->Az = csprm->csdef.prj_prm1 * cs_Degree;
	azmed->quad = cs_QuadMap [csprm->csdef.quad - cs_QuadMin];
	azmed->aspect = 0;
	azmed->one_mm = 0.001 * csprm->csdef.scale;

	/* The following fix is required for the test cases from
	   Synder which use the unit sphere, and a sphere with
	   a radius of 3. */

	if (csprm->datum.e_rad <= 3.0)
	{
		azmed->one_mm = azmed->ka / 6.3E+09;
	}

	/* Compute the sine and cosine of the Y axis azimuth. These will
	   not change. */

	if (fabs (azmed->Az) < cs_AnglTest)
	{
		azmed->sin_Az = cs_Zero;
		azmed->cos_Az = cs_One;
	}
	else
	{
		azmed->sin_Az = sin (azmed->Az);
		azmed->cos_Az = cos (azmed->Az);
	}

	/* If we are very close to either a north or south polar
	   aspect, set the sine's and cosine's to their correct
	   values.  The sine and cosine functions tend to leave
	   us just a bit short on these numbers.  We also set the
	   polar flag, which is used in the sphereical inverse
	   equations (perhaps elsewhere later on).  The polar
	   variable is zero if the aspect is oblique. */

	if (fabs (azmed->org_lat) < cs_AnglTest)
	{
		/* Equatorial Aspect */

		azmed->aspect      = cs_AZMED_EQUATOR;
		azmed->org_lat     = cs_Zero;
		azmed->cos_org_lat = cs_One;
		azmed->sin_org_lat = cs_Zero;
	}
	else if (azmed->org_lat > cs_NPTest)
	{
		azmed->aspect      = cs_AZMED_NORTH;
		azmed->org_lat     = cs_Pi_o_2;
		azmed->cos_org_lat = cs_Zero;
		azmed->sin_org_lat = cs_One;
	}
	else if (azmed->org_lat < cs_SPTest)
	{
		azmed->aspect      = cs_AZMED_SOUTH;
		azmed->org_lat     = cs_Mpi_o_2;
		azmed->cos_org_lat = cs_Zero;
		azmed->sin_org_lat = cs_Mone;
	}
	else
	{
		azmed->aspect      = cs_AZMED_OBLIQUE;
		azmed->cos_org_lat = cos (azmed->org_lat);
		azmed->sin_org_lat = sin (azmed->org_lat);
	}

	/* If the ecentricity is zero, we have a sphere, and
	   nothing special to do here. */

	if (azmed->ecent == 0.0)
	{
		azmed->max_rho = azmed->ka * cs_Pi;
	}
	else
	{
		/* Here only for an ellipsoid. */

		CSmmFsu (&azmed->mmcofF,azmed->ka,azmed->e_sq);
		CSmmIsu (&azmed->mmcofI,azmed->ka,azmed->e_sq);

		azmed->Mp = CSmmFcal (&azmed->mmcofF,cs_Pi_o_2,cs_One,cs_Zero);
		azmed->M1 = CSmmFcal (&azmed->mmcofF,azmed->org_lat,
						     azmed->sin_org_lat,
						     azmed->cos_org_lat);

		azmed->e_sin_p1 = azmed->ecent * azmed->sin_org_lat;
		azmed->e_cos_p1 = azmed->ecent * azmed->cos_org_lat;

		azmed->e_sq_sin_sq = azmed->e_sin_p1 * azmed->e_sin_p1;
		azmed->e_sq_cos_sq = azmed->e_cos_p1 * azmed->e_cos_p1;

		azmed->N1 = azmed->ka / sqrt (cs_One - azmed->e_sq_sin_sq);

		azmed->psi_t1 = azmed->e_sq * azmed->N1 * azmed->sin_org_lat;
		azmed->sin_cos = azmed->sin_org_lat * azmed->cos_org_lat;
		azmed->G = azmed->ecent * azmed->sin_org_lat /
					   azmed->rt_one_esq;
		azmed->G_sq_3 = azmed->G * azmed->G * 3.0;
		azmed->max_rho = azmed->Mp * cs_Two;
	}

	/* Set up the coordinate checking information.  If the user has
	   specified a useful range, we use it without checking it.
	   Otherwise, we compute what I, the programmer, consider to
	   be the useful range of the projection.  Note, values are in
	   degrees and longitude values are relative to the origin
	   longitude. */

	csprm->cent_mer = azmed->org_lng * cs_Radian;
	if (csprm->csdef.ll_min [LNG] == 0.0 &&
	    csprm->csdef.ll_max [LNG] == 0.0)
	{
		/* We're to calculate the useful range.  The useful
		   range is within 1200 KM of the origin.  We use
		   the approximation of 10 degrees of longitude at
		   the equator equals 1200 KM. */

		switch (azmed->aspect) {

		case cs_AZMED_NORTH:

			csprm->min_ll [LNG] = cs_Km180;
			csprm->max_ll [LNG] = cs_K180;
			csprm->min_ll [LAT] = cs_K60;
			csprm->max_ll [LAT] = cs_K90;
			break;

		case cs_AZMED_SOUTH:

			csprm->min_ll [LNG] = cs_Km180;
			csprm->max_ll [LNG] = cs_K180;
			csprm->min_ll [LAT] = cs_Km90;
			csprm->max_ll [LAT] = -cs_K60;
			break;

		default:
		case cs_AZMED_EQUATOR:
		case cs_AZMED_OBLIQUE:
		case cs_AZMED_GUAM:

			csprm->min_ll [LNG] = -cs_Ten;
			csprm->max_ll [LNG] = cs_Ten;
			tmp1 = azmed->org_lat * cs_Radian;
			csprm->min_ll [LAT] = tmp1 - cs_Ten;
			if (csprm->min_ll [LAT] < cs_Km90)
			{
				csprm->min_ll [LAT] = cs_Km90;
			}
			csprm->max_ll [LAT] = tmp1 + cs_Ten;
			if (csprm->max_ll [LAT] > cs_K90)
			{
				csprm->max_ll [LAT] = cs_K90;
			}
			break;
		}
	}
	else
	{
		/* The definition includes a useful range specification.
		   We use these values without checking.  We expect the
		   user to give us absolute values, and we convert
		   to values relative to the central meridian. */

		csprm->min_ll [LNG] = CS_adj180 (csprm->csdef.ll_min [LNG] - csprm->cent_mer);
		csprm->min_ll [LAT] = csprm->csdef.ll_min [LAT];
		csprm->max_ll [LNG] = CS_adj180 (csprm->csdef.ll_max [LNG] - csprm->cent_mer);
		csprm->max_ll [LAT] = csprm->csdef.ll_max [LAT];
	}

	/* Similarly with the X's and Y's.  If the coordinate system
	   definition carries some values, we use them.  If not, we
	   calculate some appropriate values. */

	if (csprm->csdef.xy_min [XX] == 0.0 &&
	    csprm->csdef.xy_max [XX] == 0.0)
	{
		/* Choose an arbitrary limit of the equivalant of
		   1,200,000 meters from the origin. */

		tmp1 = 1200000.0 * csprm->csdef.scale;
		csprm->min_xy [XX] = -tmp1;
		csprm->min_xy [YY] = -tmp1;
		csprm->max_xy [XX] =  tmp1;
		csprm->max_xy [YY] =  tmp1;

		CS_quadMM (csprm->min_xy,csprm->max_xy,azmed->x_off,
						       azmed->y_off,
						       azmed->quad);
	}
	else
	{
		/* Use what ever the user has given us.  No adjustment
		   necessary.  Note: we don't check anything. */

		csprm->min_xy [XX] = csprm->csdef.xy_min [XX];
		csprm->min_xy [YY] = csprm->csdef.xy_min [YY];
		csprm->max_xy [XX] = csprm->csdef.xy_max [XX];
		csprm->max_xy [YY] = csprm->csdef.xy_max [YY];
	}

	/* That's all the calculations.  Stuff some function
	   addresses and we are done. */

	csprm->ll2cs    = (cs_LL2CS_CAST)CSazmedF;
	csprm->cs2ll    = (cs_CS2LL_CAST)CSazmedI;
	csprm->cs_scale = (cs_SCALE_CAST)CSazmedK;
	csprm->cs_sclk  = (cs_SCALK_CAST)CSazmedK;
	csprm->cs_sclh  = (cs_SCALH_CAST)CSazmedH;
	csprm->cs_cnvrg = (cs_CNVRG_CAST)CSazmedC;
	csprm->llchk    = (cs_LLCHK_CAST)CSazmedL;
	csprm->xychk    = (cs_XYCHK_CAST)CSazmedX;

	return;
}
Ejemplo n.º 3
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);
}
Ejemplo n.º 4
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);
}
Ejemplo n.º 5
0
void EXP_LVL9 CSsinusS (struct cs_Csprm_ *csprm)
{
	extern short cs_QuadMin;			/* -4 */
	extern short cs_QuadMap [];
	extern double cs_Radian;				/*  57.2957...  */
	extern double cs_Degree;				/*   1.0 / RADIAN  */
	extern double cs_3Pi_o_2;				/* 3 Pi over 2 */
	extern double cs_Pi_o_2;				/* Pi over 2 */
	extern double cs_Zero;					/*   0.0 */
	extern double cs_Half;					/*   0.5 */
	extern double cs_One;					/*   1.0 */
	extern double cs_Mone;					/*   1.0 */
	extern double cs_K180;					/* 180.0 */
	extern double cs_K90;					/*  90.0 */
	extern double cs_Km90;					/* -90.0 */

	int ii;

	struct cs_Sinus_ *sinus;
	struct cs_Zone_ *zp;

	double qxk;
	double del_lng;
	double west_lng;
	double east_lng;

	sinus = &csprm->proj_prms.sinus;

	/* Transfer the necessary arguments to the
	   "sinus" structure.  Notice, the conversion
	   from degrees to radians which is performed
	   in the process. */

	sinus->cent_lng = csprm->csdef.org_lng * cs_Degree;
	sinus->k = csprm->csdef.scale;
	sinus->x_off = csprm->csdef.x_off;
	sinus->y_off = csprm->csdef.y_off;
	sinus->ecent = csprm->datum.ecent;
	sinus->e_sq = sinus->ecent * sinus->ecent;
	sinus->e_rad = csprm->datum.e_rad;
	sinus->ka = sinus->k * sinus->e_rad;
	sinus->quad = cs_QuadMap [csprm->csdef.quad - cs_QuadMin];

	sinus->one_mm = 0.001 * sinus->k;
	sinus->max_xx = sinus->ka * cs_3Pi_o_2;
	sinus->max_yy = sinus->ka * cs_Pi_o_2;		/* For the sphere,
												   replaced below
												   for the
												   ellipsoid. */

	/* No special set up required for the sphere. */

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

		CSmmFsu (&sinus->mmcofF,sinus->ka,sinus->e_sq);
		CSmmIsu (&sinus->mmcofI,sinus->ka,sinus->e_sq);
		sinus->max_yy = CSmmFcal (&sinus->mmcofF,cs_Pi_o_2,cs_One,cs_Zero);
	}

	/* Set up the function pointers. */

	csprm->ll2cs    = (cs_LL2CS_CAST)CSsinusF;
	csprm->cs2ll    = (cs_CS2LL_CAST)CSsinusI;
	csprm->cs_scale = (cs_SCALE_CAST)CSsinusH;
	csprm->cs_sclk  = (cs_SCALK_CAST)CSsinusK;
	csprm->cs_sclh  = (cs_SCALH_CAST)CSsinusH;
	csprm->cs_cnvrg = (cs_CNVRG_CAST)CSsinusC;
	csprm->llchk    = (cs_LLCHK_CAST)CSsinusL;
	csprm->xychk    = (cs_XYCHK_CAST)CSsinusX;

	/* Setup the zones. */

	sinus->zone_cnt = (short)CS_zones (&csprm->csdef,sinus->zones);

	/* Set up the easting values.  Note, if the latitude is
	   zero, there is no difference between normal eastings
	   and zoned eastings.  The zone affects the easting
	   value only when the latitude is not zero.  Also,
	   the Y values are always independent of the zone.

	   Since the latitude is zero for all of these calculations,
	   we can easily do them here rather efficiently, and the
	   calculation is the same, regardless of sphere or
	   ellipsoid.

	   Note, we also accumulate the minimum and maximum longitude
	   values for use in setting up user limits below. */

	west_lng = cs_3Pi_o_2;
	east_lng = -cs_3Pi_o_2;

	/* We use qxk to adjust our zone definition numbers for
	   non-standard quadrants. */

	qxk = ((sinus->quad & cs_QUAD_INVX) == 0) ? cs_One : cs_Mone;
	for (ii = 0;ii < sinus->zone_cnt;ii++)
	{
		zp = &sinus->zones [ii];

		del_lng = (zp->west_lng - sinus->cent_lng);
		zp->west_xx = (sinus->ka * del_lng * qxk) + sinus->x_off;

		del_lng = (zp->cent_lng - sinus->cent_lng);
		zp->x_off = (sinus->ka * del_lng * qxk) + sinus->x_off;

		del_lng = (zp->east_lng - sinus->cent_lng);
		zp->east_xx = (sinus->ka * del_lng * qxk) + sinus->x_off;

		if (zp->west_lng < west_lng) west_lng = zp->west_lng;
		if (zp->east_lng > east_lng) east_lng = zp->east_lng;
	}

	/* Set up the coordinate checking information.  If the user has
	   specified a useful range, we use it without checking it.
	   Otherwise, we compute what I, the programmer, consider to
	   be the useful range of the projection.  Note, values are in
	   degrees and longitude values are relative to the central
	   meridian. */

	if (sinus->zone_cnt > 0)
	{
		csprm->cent_mer = cs_Half * (east_lng + west_lng) * cs_Radian;
	}
	else
	{
		csprm->cent_mer = sinus->cent_lng * cs_Radian;
		east_lng = cs_K180 * cs_Degree;
		west_lng = -east_lng;
	}
	if (csprm->csdef.ll_min [LNG] == 0.0 &&
		csprm->csdef.ll_max [LNG] == 0.0)
	{
		/* User hasn't specified any values.  We're to establish
		   the useful range.  We'll establish some pretty liberal
		   values. */
		csprm->min_ll [LNG] = west_lng;
		csprm->max_ll [LNG] = east_lng;
		csprm->min_ll [LAT] = cs_Km90;
		csprm->max_ll [LAT] = cs_K90;
	}
	else
	{
		/* The definition includes a useful range specification.
		   We use these values without checking.  We expect the
		   user to give us absolute values, and we convert
		   to values relative to the central meridian. */
		csprm->min_ll [LNG] = CS_adj180 (csprm->csdef.ll_min [LNG] - csprm->cent_mer);
		csprm->min_ll [LAT] = csprm->csdef.ll_min [LAT];
		csprm->max_ll [LNG] = CS_adj180 (csprm->csdef.ll_max [LNG] - csprm->cent_mer);
		csprm->max_ll [LAT] = csprm->csdef.ll_max [LAT];
	}

	/* Similarly with the X's and Y's.  If the coordinate system
	   definition carries some values, we use them.  If not, we
	   calculate some appropriate values. */
	if (csprm->csdef.xy_min [XX] == 0.0 &&
		csprm->csdef.xy_max [XX] == 0.0)
	{
		/* No specification in the coordinate system definition.
		   The setup is virtually complete, so we can use CSgnricF
		   to calculate some values as necessary. Unfortuneately
		   it is the rare case where we can just convert the
		   lat/long min/max. */

		csprm->min_xy [XX] = -sinus->max_xx;
		csprm->max_xy [XX] =  sinus->max_xx;

		csprm->min_xy [YY] = -sinus->max_yy;
		csprm->max_xy [YY] =  sinus->max_yy;

		CS_quadMM (csprm->min_xy,csprm->max_xy,sinus->x_off,
											   sinus->y_off,
											   sinus->quad);
	}
	else
	{
		/* Use what ever the user has given us.  No adjustment
		   necessary.  Note: we don't check anything. */

		csprm->min_xy [XX] = csprm->csdef.xy_min [XX];
		csprm->min_xy [YY] = csprm->csdef.xy_min [YY];
		csprm->max_xy [XX] = csprm->csdef.xy_max [XX];
		csprm->max_xy [YY] = csprm->csdef.xy_max [YY];
	}
	return;
}
Ejemplo n.º 6
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);
}
Ejemplo n.º 7
0
void EXP_LVL9 CStacylS (struct cs_Csprm_ *csprm)
{
    extern short cs_QuadMin;			/* -4 */
    extern short cs_QuadMap [];
    extern double cs_Radian;			/* 57.29577... */
    extern double cs_Degree;			/* 1.0 / 57.29577... */
    extern double cs_Pi_o_2;			/* Pi over 2 */
    extern double cs_Zero;				/* 0.0 */
    extern double cs_One;				/* 1.0 */
    extern double cs_Two;				/* 2.0 */
    extern double cs_Ten;				/* 2.0 */

    struct cs_Tacyl_ *tacyl;

    double tmp;

    double sin_org_lat;
    double cos_org_lat;

    double test_ll [3];
    double test_xy [3];

    tacyl = &csprm->proj_prms.tacyl;

    tacyl->org_lng = csprm->csdef.org_lng * cs_Degree;
    tacyl->org_lat = csprm->csdef.org_lat * cs_Degree;
    tacyl->h0 = csprm->csdef.scl_red;
    tacyl->x_off = csprm->csdef.x_off;
    tacyl->y_off = csprm->csdef.y_off;
    tacyl->e_rad = csprm->datum.e_rad;
    tacyl->ecent = csprm->datum.ecent;
    tacyl->k = csprm->csdef.scale * tacyl->h0;
    tacyl->quad = cs_QuadMap [csprm->csdef.quad - cs_QuadMin];

    /* Note that due to the authalic nature of this projection,
       the ka factor does not include the scale reduction
       factor as is common for conformal projections. */

    tacyl->ka = csprm->csdef.scale * tacyl->e_rad;
    tacyl->ka_o_h0 = tacyl->ka / tacyl->h0;
    tacyl->kah0    = tacyl->ka * tacyl->h0;
    tacyl->h0_o_ka = tacyl->h0 / tacyl->ka;

    if (tacyl->ecent == 0.0)
    {
        tacyl->max_xx = tacyl->ka_o_h0;
        tacyl->max_yy = tacyl->kah0;
    }
    else
    {
        /* For the ellipsoid. */

        tacyl->ecent = csprm->datum.ecent;
        tacyl->e_sq = tacyl->ecent * tacyl->ecent;
        tacyl->one_m_esq = cs_One - tacyl->e_sq;

        tacyl->one_o_2e = cs_One / (cs_Two * tacyl->ecent);

        tmp = (cs_One - tacyl->ecent) / (cs_One + tacyl->ecent);
        tacyl->qp = cs_One - (tacyl->one_m_esq * tacyl->one_o_2e) * log (tmp);

        CSbtIsu (&tacyl->btcofI,tacyl->e_sq);
        CSmmFsu (&tacyl->mmcofF,tacyl->ka,tacyl->e_sq);
        CSmmIsu (&tacyl->mmcofI,tacyl->ka,tacyl->e_sq);

        sin_org_lat = sin (tacyl->org_lat);
        cos_org_lat = cos (tacyl->org_lat);
        tacyl->M0 = CSmmFcal (&tacyl->mmcofF,tacyl->org_lat,sin_org_lat,cos_org_lat);

        tacyl->max_xx = tacyl->ka_o_h0 / tacyl->one_m_esq;
        tacyl->max_yy = tacyl->h0 * CSmmFcal (&tacyl->mmcofF,cs_Pi_o_2,cs_One,cs_Zero);
    }

    /* Set up the coordinate checking information.  If the user has
       specified a useful range, we use it without checking it.
       Otherwise, we compute what I, the programmer, consider to
       be the useful range of the projection.  Note, values are in
       degrees and longitude values are relative to the central
       meridian. */

    csprm->cent_mer = tacyl->org_lng * cs_Radian;
    if (csprm->csdef.ll_min [LNG] == 0.0 &&
            csprm->csdef.ll_max [LNG] == 0.0)
    {
        /* We're to calculate the useful range.  We'll assume a
           20 degree width, increased by an amount related to
           scale reduction.  We set the latitude range to that
           customarily used in the UTM system. */

        tmp = cs_Two * acos (tacyl->h0) * cs_Radian + cs_Ten;
        csprm->min_ll [LNG] = -tmp;
        csprm->max_ll [LNG] =  tmp;

        csprm->min_ll [LAT] = -84.0;
        csprm->max_ll [LAT] =  84.0;
    }
    else
    {
        /* The definition includes a useful range specification.
           We use these values without checking.  We expect the
           user to give us absolute values, and we convert
           to values relative to the central meridian. */

        csprm->min_ll [LNG] = CS_adj180 (csprm->csdef.ll_min [LNG] - csprm->cent_mer);
        csprm->min_ll [LAT] = csprm->csdef.ll_min [LAT];
        csprm->max_ll [LNG] = CS_adj180 (csprm->csdef.ll_max [LNG] - csprm->cent_mer);
        csprm->max_ll [LAT] = csprm->csdef.ll_max [LAT];
    }

    /* Similarly with the X's and Y's.  If the coordinate system
       definition carries some values, we use them.  If not, we
       calculate some appropriate values. */

    if (csprm->csdef.xy_min [XX] == 0.0 &&
            csprm->csdef.xy_max [XX] == 0.0)
    {
        /* No specification in the coordinate system definition.
           The setup is virtually complete, so we can use CStacylF
           to calculate some values, if necessary. The curved
           nature of the lat/long lines means we cannot just
           convert the lat/long min/max. */

        test_ll [LNG] = CS_adj180 (csprm->cent_mer + csprm->min_ll [LNG]);
        test_ll [LAT] = tacyl->org_lat * cs_Radian;
        CStacylF (tacyl,test_xy,test_ll);					/*lint !e534 */
        csprm->min_xy [XX] = test_xy [XX] - tacyl->x_off;
        csprm->max_xy [XX] = -csprm->min_xy [XX];

        test_ll [LNG] = csprm->cent_mer;
        test_ll [LAT] = -84.0;
        CStacylF (tacyl,test_xy,test_ll);					/*lint !e534 */
        csprm->min_xy [YY] = test_xy [YY] - tacyl->y_off;
        test_ll [LAT] = 84.0;
        CStacylF (tacyl,test_xy,test_ll);					/*lint !e534 */
        csprm->max_xy [YY] = test_xy [YY] - tacyl->y_off;

        CS_quadMM (csprm->min_xy,csprm->max_xy,tacyl->x_off,
                   tacyl->y_off,
                   tacyl->quad);
    }
    else
    {
        /* Use what ever the user has given us.  No adjustment
           necessary.  Note: we don't check anything. */

        csprm->min_xy [XX] = csprm->csdef.xy_min [XX];
        csprm->min_xy [YY] = csprm->csdef.xy_min [YY];
        csprm->max_xy [XX] = csprm->csdef.xy_max [XX];
        csprm->max_xy [YY] = csprm->csdef.xy_max [YY];
    }

    /* That's all the calculations we can do at this time.
       The projection is conformal, so ha nd k scale
       factors are the same. */

    csprm->ll2cs    = (cs_LL2CS_CAST)CStacylF;
    csprm->cs2ll    = (cs_CS2LL_CAST)CStacylI;
    csprm->cs_scale = (cs_SCALE_CAST)CStacylK;
    csprm->cs_sclk  = (cs_SCALK_CAST)CStacylK;
    csprm->cs_sclh  = (cs_SCALH_CAST)CStacylH;
    csprm->cs_cnvrg = (cs_CNVRG_CAST)CStacylC;
    csprm->llchk    = (cs_LLCHK_CAST)CStacylL;
    csprm->xychk    = (cs_XYCHK_CAST)CStacylX;

    return;
}
Ejemplo n.º 8
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);
}
Ejemplo n.º 9
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);
}
Ejemplo n.º 10
0
void EXP_LVL9 CScsiniS (struct cs_Csprm_ *csprm)
{
	extern short cs_QuadMin;			/* -4 */
	extern short cs_QuadMap [];
	extern double cs_Degree;			/* 1.0 / 57.29577... */
	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_Zero;				/* 0.0 */
	extern double cs_One;				/* 1.0 */
	extern double cs_Two;				/* 2.0 */
	extern double cs_Five;				/* 5.0 */
	extern double cs_K75;				/* 75.0 */

	struct cs_Csini_ *csini;

	double tmp1;
	double sin_org_lat;
	double cos_org_lat;

	double test_xy [3];
	double test_ll [3];

	csini = &csprm->proj_prms.csini;

	csini->cent_lng = csprm->csdef.prj_prm1 * cs_Degree;
	csini->org_lat = csprm->csdef.org_lat * cs_Degree;
	csini->x_off = csprm->csdef.x_off;
	csini->y_off = csprm->csdef.y_off;
	csini->k = csprm->csdef.scale;
	csini->ecent = csprm->datum.ecent;
	csini->e_sq = csini->ecent * csini->ecent;
	csini->e_rad = csprm->datum.e_rad;
	csini->quad = cs_QuadMap [csprm->csdef.quad - cs_QuadMin];

	/* Probably could add a scale reduction factor to the
	   following term. */

	csini->ka = csini->e_rad * csini->k;
	csini->max_xx = csini->ka * cs_Pi_o_2;
	csini->max_yy = csini->ka * (cs_Pi_o_2 - csini->org_lat);
	csini->min_yy = csini->ka * (cs_Mpi_o_2 - csini->org_lat);

	/* Nothing special required for the sphere. */

	if (csini->ecent != 0.0)
	{
		/* Here for a ellipsoid datum.  We compute
		   what we can once only. */

		tmp1 = cs_One - csini->e_sq;
		csini->C_term = csini->e_sq / tmp1;
		csini->R_term = csini->ka * tmp1;
		csini->s_term = cs_Two * csini->ka * csini->ka * tmp1;

		/* CSmuFsu and CSmuIsu do the rest. */

		CSmmFsu (&csini->mmcofF,csini->ka,csini->e_sq);
		CSmmIsu (&csini->mmcofI,csini->ka,csini->e_sq);

		/* Now we compute M0, the M associated with
		   the origin latiude. */

		sin_org_lat = sin (csini->org_lat);
		cos_org_lat = cos (csini->org_lat);
		csini->M0 = CSmmFcal (&csini->mmcofF,csini->org_lat,
										     sin_org_lat,
										     cos_org_lat);

		csini->max_yy = CSmmFcal (&csini->mmcofF,cs_Pi_o_2,
												 cs_One,
												 cs_Zero);
		csini->max_yy -= csini->M0;
		csini->min_yy = CSmmFcal (&csini->mmcofF,cs_Mpi_o_2,
												 cs_One,
												 cs_Zero);
		csini->min_yy -= csini->M0;
	}

	/* Set up the coordinate checking information.  If the user has
	   specified a useful range, we use it without checking it.
	   Otherwise, we compute what I, the programmer, consider to
	   be the useful range of the projection.  Note, values are in
	   degrees and longitude values are relative to the central
	   meridian. */

	csprm->cent_mer = csini->cent_lng * cs_Radian;
	if (csprm->csdef.ll_min [LNG] == 0.0 &&
	    csprm->csdef.ll_max [LNG] == 0.0)
	{
		/* User hasn't specified any values.  We're to establish
		   the useful range. */

		csprm->min_ll [LNG] = -cs_Five;
		csprm->max_ll [LNG] = cs_Five;
		csprm->min_ll [LAT] = -cs_K75;
		csprm->max_ll [LAT] = cs_K75;
	}
	else
	{
		/* The definition includes a useful range specification.
		   We use these values without checking.  We expect the
		   user to give us absolute values, and we convert
		   to values relative to the central meridian. */

		csprm->min_ll [LNG] = CS_adj180 (csprm->csdef.ll_min [LNG] - csprm->cent_mer);
		csprm->min_ll [LAT] = csprm->csdef.ll_min [LAT];
		csprm->max_ll [LNG] = CS_adj180 (csprm->csdef.ll_max [LNG] - csprm->cent_mer);
		csprm->max_ll [LAT] = csprm->csdef.ll_max [LAT];
	}

	/* Similarly with the X's and Y's.  If the coordinate system
	   definition carries some values, we use them.  If not, we
	   calculate some appropriate values. */

	if (csprm->csdef.xy_min [XX] == 0.0 &&
	    csprm->csdef.xy_max [XX] == 0.0)
	{
		/* No specification in the coordinate system definition.
		   The setup is virtually complete, so we can use CScsiniF
		   to calculate some values as necessary. Unfortuneately
		   it is the rare case where we can just convert the
		   lat/long min/max. */

		test_ll [LNG] = CS_adj180 (csprm->min_ll [LNG] + csprm->cent_mer);
		test_ll [LAT] = csini->org_lat * cs_Radian;
		CScsiniF (csini,test_xy,test_ll);
		csprm->min_xy [XX] = test_xy [XX] - csini->x_off;
		csprm->max_xy [XX] = -csprm->min_xy [XX];

		test_ll [LNG] = csini->cent_lng * cs_Radian;
		test_ll [LAT] = cs_K75;
		CScsiniF (csini,test_xy,test_ll);
		csprm->max_xy [YY] = test_xy [YY] - csini->y_off;

		test_ll [LAT] = -cs_K75;
		CScsiniF (csini,test_xy,test_ll);
		csprm->min_xy [YY] = test_xy [YY] - csini->y_off;

		CS_quadMM (csprm->min_xy,csprm->max_xy,csini->x_off,
						       csini->y_off,
						       csini->quad);
	}
	else
	{
		/* Use what ever the user has given us.  No adjustment
		   necessary.  Note: we don't check anything. */

		csprm->min_xy [XX] = csprm->csdef.xy_min [XX];
		csprm->min_xy [YY] = csprm->csdef.xy_min [YY];
		csprm->max_xy [XX] = csprm->csdef.xy_max [XX];
		csprm->max_xy [YY] = csprm->csdef.xy_max [YY];
	}

	/* That's all the calculations we can do at this time. Set
	   up the internal function calls.  Note, the Cassini is
	   not a conformal projection. */

	csprm->ll2cs    = (cs_LL2CS_CAST)CScsiniF;
	csprm->cs2ll    = (cs_CS2LL_CAST)CScsiniI;
	csprm->cs_scale = (cs_SCALE_CAST)CScsiniH;
	csprm->cs_sclk  = (cs_SCALK_CAST)CScsiniK;
	csprm->cs_sclh  = (cs_SCALH_CAST)CScsiniH;
	csprm->cs_cnvrg = (cs_CNVRG_CAST)CScsiniC;
	csprm->llchk    = (cs_LLCHK_CAST)CScsiniL;
	csprm->xychk    = (cs_XYCHK_CAST)CScsiniX;

	return;
}