Example #1
0
void EXP_LVL9 CSpstroS (struct cs_Csprm_ *csprm)
{
	extern short cs_QuadMin;			/* -4 */
	extern short cs_QuadMap [];
	extern double cs_Degree;			/* 1.0 / RADIAN  */
	extern double cs_Radian;			/*   57.29....  */
	extern double cs_Pi_o_2;			/*  PI / 2.0     */
	extern double cs_Pi_o_4;			/*  PI / 4.0     */
	extern double cs_Mpi_o_2;			/* -PI / 2.0     */
	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_Two;				/*    2.0 */
	extern double cs_K180;				/*  180.0 */
	extern double cs_Km180;				/* -180.0 */
	extern double cs_K90;				/*   90.0 */
	extern double cs_Km90;				/*  -90.0 */
	extern double cs_NPTest;			/* 0.001 seconds of arc
										   short of the north pole
										   in radians. */

	struct cs_Pstro_ *pstro;

	double latc;
	double sinlatc,	coslatc, esinlatc;
	double onePlusE, oneMinusE;
	double mc, tc, eTerm;
	double scaleFactor;
	double tmp1, tmp2;

	pstro = &csprm->proj_prms.pstro;

	/* Transfer the necessary arguments to the "pstro" structure. */

	pstro->org_lng = csprm->csdef.org_lng * cs_Degree;
	pstro->org_lat = csprm->csdef.org_lat * cs_Degree;
	pstro->x_off = csprm->csdef.x_off;
	pstro->y_off = csprm->csdef.y_off;
	pstro->ecent = csprm->datum.ecent;
	pstro->e_rad = csprm->datum.e_rad;

	// There are two variations of this projection.  In the traditional form,
	// the scale factor is specified explicitly.  In the other, a "Standard
	// Circle" is supplied, and the scale factor is computed from this.
	if (csprm->prj_code == cs_PRJCOD_PSTRO)
	{
		scaleFactor = csprm->csdef.scl_red;
	}
	else if (csprm->prj_code == cs_PRJCOD_PSTROSL)
	{
		latc = csprm->csdef.prj_prm1 * cs_Degree;
		if (pstro->org_lat < 0)
		{
			// South pole variant. The formulas below compute the scale from the
			// north pole perspective. The latc variable is not used after that.
			// So we reverse the sign here.
			latc = -latc;
		}

		if (pstro->ecent == 0.0)
		{
			// Here for a sphere.
			sinlatc = sin (latc);
			scaleFactor = cs_Half * (cs_One + sinlatc);
		}
		else
		{
			// Here for an ellipsoid.
			sinlatc = sin (latc);
			coslatc = cos (latc);
			esinlatc = pstro->ecent * sinlatc;
			mc = coslatc / sqrt (cs_One - esinlatc * esinlatc);
			tmp1 = (cs_One - esinlatc) / (cs_One + esinlatc);
			tmp1 = pow (tmp1,pstro->ecent * cs_Half);
			tc = tan (cs_Pi_o_4 - latc * cs_Half) / tmp1;

			// The 1+e and 1-e terms.
			onePlusE = cs_One + pstro->ecent;
			oneMinusE = cs_One - pstro->ecent;
			eTerm = sqrt (pow (onePlusE,onePlusE) * pow (oneMinusE,oneMinusE));

			// The scale factor at the pole.
			scaleFactor = cs_Half * (mc / tc) * eTerm;
		}
	}
	else
	{
		scaleFactor = cs_One;
	}

	// The rest is common to both variations.
	pstro->k = csprm->csdef.scale * scaleFactor;
	pstro->ka = csprm->datum.e_rad * pstro->k;
	pstro->two_ka = pstro->ka * cs_Two;
	pstro->cos_org_lat = cos (pstro->org_lat);
	pstro->sin_org_lat = sin (pstro->org_lat);
	pstro->quad = cs_QuadMap [csprm->csdef.quad - cs_QuadMin];

	/* Determine which pole. */

	if (fabs (pstro->org_lat) > cs_NPTest)
	{
		pstro->cos_org_lat = cs_Zero;
		if (pstro->org_lat < 0.0)
		{
			/* South polar aspect. */

			pstro->aspect = cs_STERO_SOUTH;
			pstro->sin_org_lat = cs_Mone;
			pstro->org_lat = cs_Mpi_o_2;
		}
		else
		{
			/* North polar aspect. */

			pstro->aspect = cs_STERO_NORTH;
			pstro->sin_org_lat = cs_One;
			pstro->org_lat = cs_Pi_o_2;
		}
	}

	/* Set up a value in the units of the cartesian system
	   which represents one millimeter. */

	pstro->one_mm = 0.001 * csprm->csdef.scale;

	/* If the ecentricity is zero, we have a sphere.  The
	   set up is a bit different in this case. */

	if (pstro->ecent == 0.0)
	{
		/* Not much we can do here. */

		pstro->two_k0 = cs_Two * csprm->csdef.scl_red;
	}
	else
	{
		/* Here for the ellipsoidal calculations. */

		pstro->e_o_2 = csprm->datum.ecent * cs_Half;
		pstro->e_sq = pstro->ecent * pstro->ecent;

		tmp1 = cs_One + pstro->ecent;
		tmp1 = pow (tmp1,tmp1);
		tmp2 = cs_One - pstro->ecent;
		tmp2 = pow (tmp2,tmp2);
		pstro->e_term = sqrt (tmp1 * tmp2);

		CSchiIsu (&pstro->chicofI,pstro->e_sq);
	}

	/* 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 = pstro->org_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.  We'll establish some
		   pretty liberal values. */

		switch (pstro->aspect) {

		case cs_STERO_NORTH:

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

		case cs_STERO_SOUTH:

			csprm->min_ll [LNG] = cs_Km180;
			csprm->max_ll [LNG] = cs_K180;
			csprm->min_ll [LAT] = cs_Km90;
			csprm->max_ll [LAT] = cs_Mone;
			break;
		}							/*lint !e744 */
	}
	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. */

		csprm->min_xy [XX] = -pstro->ka;
		csprm->max_xy [XX] =  pstro->ka;
		csprm->min_xy [YY] = -pstro->ka;
		csprm->max_xy [YY] =  pstro->ka;

		CS_quadMM (csprm->min_xy,csprm->max_xy,pstro->x_off,
											   pstro->y_off,
											   pstro->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)CSpstroF;
	csprm->cs2ll    = (cs_CS2LL_CAST)CSpstroI;
	csprm->cs_scale = (cs_SCALE_CAST)CSpstroK;
	csprm->cs_sclk  = (cs_SCALK_CAST)CSpstroK;
	csprm->cs_sclh  = (cs_SCALH_CAST)CSpstroK;	/* Conformal */
	csprm->cs_cnvrg = (cs_CNVRG_CAST)CSpstroC;
	csprm->llchk    = (cs_LLCHK_CAST)CSpstroL;
	csprm->xychk    = (cs_XYCHK_CAST)CSpstroX;

	return;
}
Example #2
0
void EXP_LVL9 CSmrcatS (struct cs_Csprm_ *csprm)
{
	extern short cs_QuadMin;			/* -4 */
	extern short cs_QuadMap [];
	extern double cs_Zero;
	extern double cs_Half;				/* 0.5 */
	extern double cs_One;				/* 1.0 */
	extern double cs_Degree;			/* 1.0 / 57.29577... */
	extern double cs_Radian;			/* 57.29577... */
	extern double cs_NPTest;			/* .001 seconds of arc
										   short of the north 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  */

	struct cs_Mrcat_ *mrcat;

	double sin_sp;
	double tmp1;

	double ll_test [3];
	double xy_test [3];

	mrcat = &csprm->proj_prms.mrcat;

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

	/* Handle the two (currently) variations to this projection. */

	switch (csprm->prj_code) {

	default:
	case cs_PRJCOD_MRCAT:
		/* Here for the normal case, a standard parallel, usually zero. */
		mrcat->std_lat = csprm->csdef.prj_prm2 * cs_Degree;
		mrcat->cos_sp = cos (mrcat->std_lat);
		if (mrcat->ecent != 0.0)
		{
			sin_sp = sin (mrcat->std_lat);
			tmp1 = cs_One - (mrcat->e_sq * sin_sp * sin_sp);
			mrcat->cos_sp /= sqrt (tmp1);
		}
		break;

	case cs_PRJCOD_MRCATK:
		/* Here for the scale reduction case. */
		mrcat->cos_sp = csprm->csdef.scl_red;
		break;
	}

	/* Compute the maximum Y value, i.e. the value we will use
	   for the poles rather than the technically correct
	   infinite value. */

	/* We need to do a little extra for the ellipsoidal case. */

	if (mrcat->ecent != 0.0)
	{
		/* Set up the latitude power series coefficients. */
		CSchiIsu (&mrcat->chicofI,mrcat->e_sq);
	}

	/* The following apply for either form. */

	mrcat->Rk = csprm->datum.e_rad * mrcat->k;
	mrcat->Rk_ovr_2 = mrcat->Rk * cs_Half;
	mrcat->Rfact = mrcat->Rk * mrcat->cos_sp;
	mrcat->Rfact_2 = mrcat->Rfact * cs_Half;

	/* Compute the maximum Y value, i.e. the value we will use
	   for the poles rather than the technically correct
	   infinite value.  Since the setup is just about complete,
	   we can use the CSmrcatF function to do this. */

	ll_test [LNG] = mrcat->cent_lng;
	ll_test [LAT] = cs_NPTest * cs_Radian;
	CSmrcatF (mrcat,xy_test,ll_test);			/*lint !e534 */
	mrcat->yy_max = xy_test [YY];

	/* Setup the range checking.  Note, these values are considered
	   to be useful range values. */

	csprm->cent_mer = mrcat->cent_lng * cs_Radian;
	if (csprm->csdef.ll_min [LNG] == 0.0 &&
	    csprm->csdef.ll_min [LNG] == 0.0)
	{
		/* Here if the definition does not specify; we calculate
		   some reasonable values. */
		csprm->cent_mer = cs_Zero;
		csprm->min_ll [LNG] = cs_Km180;
		csprm->max_ll [LNG] = cs_K180;
		csprm->min_ll [LAT] = cs_Km90;
		csprm->max_ll [LAT] = cs_K90;
	}
	else
	{
		/* Use whatever the user provides, without checking.
		   The user specifies values in absolute terms. */
		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 (csprm->csdef.xy_min [XX] == 0.0 &&
	    csprm->csdef.xy_max [YY] == 0.0)
	{
		/* Here if the definition does not specify; we calculate
		   some reasonable values.  This is one of the few
		   projections where the following works; i.e. both
		   meridians and parallels ae straight lines. */

		ll_test [LNG] = csprm->min_ll [LNG];
		ll_test [LAT] = csprm->min_ll [LAT];
		CSmrcatF (mrcat,xy_test,ll_test);			/*lint !e534 */
		csprm->min_xy [XX] = xy_test [XX] - mrcat->x_off;
		csprm->min_xy [YY] = xy_test [YY] - mrcat->y_off;

		ll_test [LNG] = csprm->max_ll [LNG];
		ll_test [LAT] = csprm->max_ll [LAT];
		CSmrcatF (mrcat,xy_test,ll_test);			/*lint !e534 */
		csprm->max_xy [XX] = xy_test [XX] - mrcat->x_off;
		csprm->max_xy [YY] = xy_test [YY] - mrcat->y_off;

		CS_quadMM (csprm->min_xy,csprm->max_xy,mrcat->x_off,
											   mrcat->y_off,
											   mrcat->quad);
	}
	else
	{
		/* Use whatever the user provides, without checking. */

		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)CSmrcatF;
	csprm->cs2ll    = (cs_CS2LL_CAST)CSmrcatI;
	csprm->cs_scale = (cs_SCALE_CAST)CSmrcatK;
	csprm->cs_sclk  = (cs_SCALK_CAST)CSmrcatK;
	csprm->cs_sclh  = (cs_SCALH_CAST)CSmrcatK;
	csprm->cs_cnvrg = (cs_CNVRG_CAST)CSmrcatC;
	csprm->llchk    = (cs_LLCHK_CAST)CSmrcatL;
	csprm->xychk    = (cs_XYCHK_CAST)CSmrcatX;

	return;
}