Exemple #1
0
/*
baseMeridian,  relativeLongitude, deltaLongitude,  Case            
         0.0,              180.0,         +180.0, special case 1
       180.0,                0.0,         -180.0, special case 1
      -179.0,             +179.0,         +358.0, special case 2
      +179.0,             -179.0,         -358.0, special case 3
*/
double EXP_LVL7 CS_deltaLongitude (double baseMeridian,double relativeLongitude)
{
	extern double cs_K180;
	extern double cs_Km180;
	extern double cs_K360;
	
	double myBase;
	double myRelative;
	double deltaLongitude;
	
	myBase = CS_adj180 (baseMeridian);
	myRelative = CS_adj180 (relativeLongitude);
	deltaLongitude = relativeLongitude - baseMeridian;

	/* For 99.99% of the cases, we're done.  The whole purpose of having
	   this function is the 0.01% of the time where the relative longitude
	   is antiPodal or the simple calculation crosses over the +/- 180
	   degree crack.  Thus we have three special cases: */
	if (fabs (fabs (deltaLongitude) - cs_K180) < 1.0E-10)
	{
		/* 1.0E-10 ~ 0.01 millimeters at the equator of the earth. */
		/* Special case 1: the relative longitude is antiPodal to the
		   base meridian. */
		deltaLongitude = cs_K180;
	}
	else if (deltaLongitude > cs_K180)
	{
		/* Special case 2: crossing the +/- 180 degree crack going west */ 
		deltaLongitude -= cs_K360;
	}
	else if (deltaLongitude < cs_Km180)
	{
		/* Special case 3: crossing the =/- 180 degree crack going east. */
		deltaLongitude += cs_K360;
	}
	return deltaLongitude;
}
Exemple #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;
}
Exemple #3
0
void EXP_LVL9 CSwinklS (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 / 57.2957..  */
	extern double cs_Pi;				/*    3.14.159... */
	extern double cs_Mpi;				/*   -3.14.159... */
	extern double cs_Pi_o_2;			/* Pi over 2 */
	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. */
	extern double cs_SPTest;			/* 0.001 seconds of arc
										   short of the south
										   pole, in radians. */
	struct cs_Winkl_ *winkl;
	double tmp;

	winkl = &csprm->proj_prms.winkl;

	/* Transfer the necessary arguments to the "winkl" structure.
	   Notice, the conversion from degrees to radians which is
	   performed in the process. */
	winkl->org_lng = csprm->csdef.org_lng * cs_Degree;
	winkl->ref_lat = csprm->csdef.prj_prm1 * cs_Degree;
	winkl->k = csprm->csdef.scale;
	winkl->e_rad = csprm->datum.e_rad;
	winkl->ka = csprm->datum.e_rad * winkl->k;
	winkl->x_off = csprm->csdef.x_off;
	winkl->y_off = csprm->csdef.y_off;
	winkl->quad = cs_QuadMap [csprm->csdef.quad - cs_QuadMin];

	/* There isn't much to do for this one. */
	winkl->twoKa = winkl->ka + winkl->ka;
	winkl->cos_ref_lat = cos (winkl->ref_lat);
	winkl->Rcos_ref_lat = winkl->ka * winkl->cos_ref_lat;
	winkl->yy_max =  winkl->ka * cs_Pi_o_2;
   	winkl->one_mm = 0.001 * winkl->k;

	/* 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 = winkl->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. */
		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
	{
		/* 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] = cs_Mpi * winkl->Rcos_ref_lat;
		csprm->max_xy [XX] = cs_Pi  * winkl->Rcos_ref_lat;

		tmp = cs_SPTest;
		csprm->min_xy [YY] = tmp * winkl->ka;
		tmp = cs_NPTest;
		csprm->max_xy [YY] = tmp * winkl->ka;

		CS_quadMM (csprm->min_xy,csprm->max_xy,winkl->x_off,
											   winkl->y_off,
											   winkl->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)CSwinklF;
	csprm->cs2ll    = (cs_CS2LL_CAST)CSwinklI;
	csprm->cs_scale = (cs_SCALE_CAST)CSwinklK;
	csprm->cs_sclk  = (cs_SCALK_CAST)CSwinklK;
	csprm->cs_sclh  = (cs_SCALH_CAST)CSwinklH;
	csprm->cs_cnvrg = (cs_CNVRG_CAST)CSwinklC;
	csprm->llchk    = (cs_LLCHK_CAST)CSwinklL;
	csprm->xychk    = (cs_XYCHK_CAST)CSwinklX;

	return;
}
Exemple #4
0
void EXP_LVL9 CSvdgrnS (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.2..... */
	extern double cs_Pi;				/* 3.14159..... */
	extern double cs_Mpi;				/* -3.14159..... */
	extern double cs_Two;				/* 2.0 */
	extern double cs_Three;				/* 3.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 */

	struct cs_Vdgrn_ *vdgrn;

	vdgrn = &csprm->proj_prms.vdgrn;

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

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

	vdgrn->piR = vdgrn->ka * cs_Pi;
	vdgrn->two_ovr_pi = cs_Two / cs_Pi;
	vdgrn->one_mm = 0.001 * vdgrn->k;
	if (vdgrn->e_rad <= cs_Three) vdgrn->one_mm = 2.0E-10;

	/* 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 = vdgrn->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. */

		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
	{
		/* 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] = cs_Mpi * vdgrn->ka;
		csprm->max_xy [XX] = cs_Pi  * vdgrn->ka;
		csprm->min_xy [YY] = cs_Mpi * vdgrn->ka;
		csprm->max_xy [YY] = cs_Pi  * vdgrn->ka;

		CS_quadMM (csprm->min_xy,csprm->max_xy,vdgrn->x_off,
											   vdgrn->y_off,
											   vdgrn->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)CSvdgrnF;
	csprm->cs2ll    = (cs_CS2LL_CAST)CSvdgrnI;
	csprm->cs_scale = (cs_SCALE_CAST)CSvdgrnK;
	csprm->cs_sclk  = (cs_SCALK_CAST)CSvdgrnK;
	csprm->cs_sclh  = (cs_SCALH_CAST)CSvdgrnH;
	csprm->cs_cnvrg = (cs_CNVRG_CAST)CSvdgrnC;
	csprm->llchk    = (cs_LLCHK_CAST)CSvdgrnL;
	csprm->xychk    = (cs_XYCHK_CAST)CSvdgrnX;

	return;
}
Exemple #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;
}
Exemple #6
0
int CStestE (bool verbose,long32_t duration)
{
    bool special;

    int index;
    int status;
    int err_cnt;
    int isPseudo;

    long32_t il;

    struct cs_Grptbl_ *tp;
    struct cs_Csgrplst_ *gp;
    struct cs_Csgrplst_ *grp_list;
    struct cs_Csprm_ *csprm;

    double ll  [3];
    double xy  [3];
    double ll1 [3];

    double lat_del;
    double low_lng;
    double low_lat;
    double hi_lng;
    double hi_lat;
    double ll_tol;
    double del_lng;
    double del_lat;

    duration *= 100L;

    printf ("Checking reversibility of all projections, smaller region/tolerance.\n");

    /* Loop through the group table and fetch a linked list
       for each group.  Count the number in the group and
       add to the total in the group. */

    err_cnt = 0;
    csprm = NULL;
    for (tp = cs_CsGrptbl; tp->group [0] != 0; tp += 1)
    {
        if (csprm != NULL)
        {
            CS_free (csprm);
            csprm = NULL;
        }
        if (!CS_stricmp (tp->group,"LEGACY"))
        {
            continue;
        }
        CS_csgrp (tp->group,&grp_list);
        for (gp = grp_list; gp != NULL; gp = gp->next)
        {
            if (csprm != NULL)
            {
                CS_free (csprm);
                csprm = NULL;
            }
            if (verbose)
            {
                printf ("Testing %s for reversibility.\n",
                        gp->key_nm);
            }
            else
            {
                printf ("%s               \r",gp->key_nm);
            }

            csprm = CS_csloc (gp->key_nm);
            if (csprm == NULL)
            {
                printf ("Couldn't setup coordinate system named %s.\n",gp->key_nm);
                err_cnt += 1;
                continue;
            }
            strcpy (cs_MeKynm,csprm->csdef.key_nm);

            /* Is this one on the "special" list? */
            special = false;
            for (index = 0; KcsTestEspecialList [index][0] != '\0'; index += 1)
            {
                if (!CS_stricmp (csprm->csdef.key_nm,KcsTestEspecialList [index]))
                {
                    special = true;
                    break;
                }
            }

            isPseudo = FALSE;
            if (csprm->prj_code == cs_PRJCOD_MRCATPV)
            {
                isPseudo = TRUE;
            }

            /* Get the useful range of the coordinate system and reduce it
               by about one half. */
            if (special)
            {
                /* here to reduce by two thirds. */
                low_lng = csprm->cent_mer + csprm->min_ll [LNG] + fabs (csprm->min_ll [LNG] * 0.6666);
                hi_lng =  csprm->cent_mer + csprm->max_ll [LNG] - fabs (csprm->min_ll [LNG] * 0.6666);
                lat_del = csprm->max_ll [LAT] - csprm->min_ll [LAT];
                low_lat = csprm->min_ll [LAT] + lat_del * 0.333333;
                hi_lat  = csprm->max_ll [LAT] - lat_del * 0.333333;
            }
            else
            {
                /* Code that has been used for testE for many years before the "special fix", unedited. */
                low_lng = csprm->cent_mer + csprm->min_ll [LNG] + fabs (csprm->min_ll [LNG] * 0.5);
                hi_lng =  csprm->cent_mer + csprm->max_ll [LNG] - fabs (csprm->min_ll [LNG] * 0.5);
                lat_del = csprm->max_ll [LAT] - csprm->min_ll [LAT];
                low_lat = csprm->min_ll [LAT] + lat_del * 0.5;
                hi_lat  = csprm->max_ll [LAT] - lat_del * 0.5;
            }

            /* insure that there is a range of some sort. */
            if ((hi_lng - low_lng) < cs_One)
            {
                low_lng = csprm->cent_mer - cs_Half;
                hi_lng = csprm->cent_mer + cs_Half;
            }
            if ((hi_lat - low_lat) < cs_One)
            {
                low_lat = ((csprm->max_ll [LAT] + csprm->min_ll [LAT]) * cs_Half) - cs_Half;
                hi_lat = low_lat + cs_One;
            }

            for (il = 0; il < duration; il += 1)
            {
                ll [LNG] = CStestRN (low_lng,hi_lng);
                ll [LNG] = CS_adj180 (ll [LNG]);
                ll [LAT] = CStestRN (low_lat,hi_lat);

                /* The pseudo Mercator cannot convert any point with
                   latitude higher than 84. */
                if (isPseudo && fabs (ll [LAT]) > 83.0)
                {
                    continue;
                }

                /* For the two projections which account for 95% of
                   the mapping in the world, we use a very small
                   tolerance which approximates 5 millimeters on the
                   earth.  For the less important projections, we
                   use a tolerance which approximates 50 millimeters.

                   That is, for several projections, specifically the
                   whole world type, the mathemagics simply doesn't
                   produce the same level of accuracy as the two
                   biggies do.

                   As the Van der Grinten approaches the central
                   meridian, however, we need to relax the tolerance
                   to account for the mathematical discontinuity
                   encountered there. */

                if (csprm->prj_code == cs_PRJCOD_TRMER ||
                        csprm->prj_code == cs_PRJCOD_LM2SP)
                {
                    ll_tol = 4.5E-08;
                }
                else if (csprm->prj_code == cs_PRJCOD_CSINI)
                {
                    /* Cassini doesn't reverse very well.  This is well known
                       in the coordinate conversion community.  Someone needs
                       to figure out the math involved and improve the
                       projection formulas. */
                    ll_tol = 2.5E-06;
                }
                else
                {
                    ll_tol = 4.5E-07;
                }
                if (csprm->prj_code == cs_PRJCOD_VDGRN)
                {
                    if (fabs (ll [0] - csprm->cent_mer) < 0.1) ll_tol = 1.0E-05;
                }

                /* Due to the polynomials, the Danish stuff does not invert well
                   when you're not within the real domain of the polynomial; i.e.
                   actually in the region being converted.  Thus, randomly generated
                   numbers like this do not invert well.

                   The polynomial code uses the inverse to determine if a coordinate
                   pair is within the useful range of the polynomial.  The tolerance
                   check is set to 4 centimeters.  Adjusting for the latitude of
                   Denmark, we use the following tolerance. */
                if (csprm->prj_code == cs_PRJCOD_SYS34    ||
                        csprm->prj_code == cs_PRJCOD_SYS34_99 ||
                        csprm->prj_code == cs_PRJCOD_SYS34_01)
                {
                    ll_tol = 7.0E-06;
                }

                /* Convert to X and Y, then back again. */

                strcpy (cs_MeFunc,"CS_ll2cs");
                status = CS_ll2cs (csprm,xy,ll);
                if (status != cs_CNVRT_NRML) continue;
                strcpy (cs_MeFunc,"CS_cs2ll");
                status = CS_cs2ll (csprm,ll1,xy);
                if (status != cs_CNVRT_NRML) continue;

                /* Conversions were OK, see if we
                   ended up with what we started
                   with. */

                del_lng = CS_adj180 (ll [0] - ll1 [0]);
                del_lat = ll [1] - ll1 [1];
                if (fabs (del_lng) > ll_tol ||
                        fabs (del_lat) > ll_tol)
                {
                    printf ("%s:: Couldn't reverse %f:%f.\n",csprm->csdef.key_nm,ll[0],ll[1]);
                    printf ("\t\tdel_lng = %g,del_lat = %g.\n",del_lng,del_lat);
                    err_cnt += 1;

                    /* Uncomment the following for
                       easier debugging. */

                    status = CS_ll2cs (csprm,xy,ll);
                    status = CS_cs2ll (csprm,ll1,xy);
                }
            }

            CS_free (csprm);
            csprm = NULL;
        }
        CS_csgrpf (grp_list);
    }
    return (err_cnt);
}
Exemple #7
0
void EXP_LVL9 CSorthoS (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.27....  */
	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_Three;				/*  3.0 */
	extern double cs_Mone;				/* -1.0 */
	extern double cs_K90;				/*  90.0 */
	extern double cs_Km90;				/* -90.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_AnglTest;			/* 0.001 seconds of arc in
										   radians. */

	struct cs_Ortho_ *ortho;

	ortho = &csprm->proj_prms.ortho;

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

	ortho->org_lng = csprm->csdef.org_lng * cs_Degree;
	ortho->org_lat = csprm->csdef.org_lat * cs_Degree;
	ortho->k = csprm->csdef.scale;
	ortho->x_off = csprm->csdef.x_off;
	ortho->y_off = csprm->csdef.y_off;
	ortho->e_rad = csprm->datum.e_rad;
	ortho->ka = csprm->datum.e_rad * ortho->k;
	ortho->cos_org_lat = cos (ortho->org_lat);
	ortho->sin_org_lat = sin (ortho->org_lat);
	ortho->quad = cs_QuadMap [csprm->csdef.quad - cs_QuadMin];

	/* Force hard values for the polar and equatorial
	   aspects.  This should not be necessary.  However,
	   different run time libraries behave differently.
	   Since this is the set up function, I think we can
	   afford the following.  The numbers chosen for the
	   indicated aspect if the origin latitude is within
	   one minute of the approriate latitude location. */

	if (ortho->org_lat > cs_NPTest)
	{
		ortho->sin_org_lat = cs_One;
		ortho->cos_org_lat = cs_Zero;
		ortho->org_lat = cs_Pi_o_2;
	}
	else if (ortho->org_lat < cs_SPTest)
	{
		ortho->sin_org_lat = cs_Mone;
		ortho->cos_org_lat = cs_Zero;
		ortho->org_lat = cs_Mpi_o_2;
	}
	else if (fabs (ortho->org_lat) < cs_AnglTest)
	{
		ortho->sin_org_lat = cs_Zero;
		ortho->cos_org_lat = cs_One;
		ortho->org_lat = cs_Zero;
	}

	/* Set up a value in the units of the cartesian system
	   which represents one tenth of a millimeter.  If this is
	   a unit sphere test system, we simply provide out own value. */

	ortho->one_mm = 0.001 * ortho->k;
	if (ortho->e_rad <= cs_Three) ortho->one_mm = 2.0E-10;

	/* 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 = ortho->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.  The limit is really a cirlce of
		   angular distance of Pi/2 radians from the origin.
		   This is difficult to cram into a rectangular box. */

		csprm->min_ll [LNG] = cs_Km90;
		csprm->max_ll [LNG] = cs_K90;
		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 CSorthoF
		   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] = -ortho->ka;
		csprm->max_xy [XX] =  ortho->ka;
		csprm->min_xy [YY] = -ortho->ka;
		csprm->max_xy [YY] =  ortho->ka;

		CS_quadMM (csprm->min_xy,csprm->max_xy,ortho->x_off,
											   ortho->y_off,
											   ortho->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)CSorthoF;
	csprm->cs2ll    = (cs_CS2LL_CAST)CSorthoI;
	csprm->cs_scale = (cs_SCALE_CAST)CSorthoH;
	csprm->cs_sclk  = (cs_SCALK_CAST)CSorthoK;
	csprm->cs_sclh  = (cs_SCALH_CAST)CSorthoH;
	csprm->cs_cnvrg = (cs_CNVRG_CAST)CSorthoC;
	csprm->llchk    = (cs_LLCHK_CAST)CSorthoL;
	csprm->xychk    = (cs_XYCHK_CAST)CSorthoX;

	return;
}
Exemple #8
0
/* Now for the regular stuff.
   CSkrovkS -- The setup function (constructor). */
void EXP_LVL9 CSkrovkS (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.27....  */
	extern double cs_Pi;			/*  Pi (3.14159....) */
	extern double cs_Pi_o_2;		/*  Pi over 2 */
	extern double cs_Pi_o_4;		/*  Pi over 4 */
	extern double cs_Zero;			/*  0.0 */
	extern double cs_Half;			/*  0.5 */
	extern double cs_One;			/*  1.0 */
	extern double cs_Four;			/*  4.0 */
	extern double cs_AnglTest;		/* 0.001 seconds of arc in
									   radians. */

	struct cs_Krovk_ *krovk;

	double lat0;
	double sinLat0;
	double sinOrgLat, cosOrgLat;
	double one_esq;
	double tmp1, tmp2, tmp3, tmp4;

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

	krovk = &csprm->proj_prms.krovk;
	krovk->apply95 = (csprm->prj_code == cs_PRJCOD_KRVK95) ? 1 : 0;

	/* Extract the parameters from the definition. */
	krovk->orgLng  = csprm->csdef.org_lng * cs_Degree;
	krovk->orgLat  = csprm->csdef.org_lat * cs_Degree;
	krovk->poleLng = csprm->csdef.prj_prm1 * cs_Degree;
	krovk->poleLat = csprm->csdef.prj_prm2 * cs_Degree;
	krovk->stdLat  = csprm->csdef.prj_prm3 * cs_Degree;
	krovk->x_off = csprm->csdef.x_off;
	krovk->y_off = csprm->csdef.y_off;
	krovk->k0 = csprm->csdef.scl_red;
	krovk->k = csprm->csdef.scale * krovk->k0;

	/* Some basics calculated from the parameters. */
	sinOrgLat = sin (krovk->orgLat);
	cosOrgLat = cos (krovk->orgLat);
	krovk->kR = csprm->datum.e_rad * krovk->k;
	krovk->ecent = csprm->datum.ecent;
	krovk->e_sq = krovk->ecent * krovk->ecent;
	krovk->e_ovr_2 = krovk->ecent * cs_Half;
	one_esq = cs_One - krovk->e_sq;

	krovk->resolve = cs_AnglTest;
	krovk->one_mm = 0.001 * krovk->k;
	krovk->quad = cs_QuadMap [csprm->csdef.quad - cs_QuadMin];

	/* N0 is the radius of the Gaussian sphere.  The formulation hides this,
	   but it equivalent to the geometric mean of the meridional and first
	   vertical section radii of curvature at the specified origin latitude. */
	tmp1 = cs_One - krovk->e_sq * sinOrgLat * sinOrgLat;
	krovk->N0 = krovk->kR * sqrt (one_esq) / tmp1;
	krovk->rho0 = krovk->N0 / tan (krovk->stdLat);

	/* Handle the specific variations here. */
	if (krovk->ecent == 0.0)
	{
		/* Here for the spherical form of the Krovak variation.
		   Calculate the gaussian surface equivalent of some of
		   the ellipsoidal based parameters.  Since in this case,
		   we are starting with a sphere, this is pretty
		   superficial. */
		krovk->alpha = cs_One;
		krovk->alpha_eo2 = cs_One;
		krovk->K = cs_Zero;
		krovk->lngQ = krovk->poleLng;
		krovk->latQ = krovk->poleLat;
	}
	else
	{
		/* Here for the ellipsoid version of the projection.  Here we have
		   to compute aplha and K, which are used to convert ellipsoidal
		   lat/longs to Gaussian Surface (i.e. approximating sphere)
		   lat/longs.  Then, we use alpha and K to compute the location
		   of the oblique pole in terms of Gaussian Surface lat/longs. */
		tmp1 = cosOrgLat * cosOrgLat;
		tmp1 = tmp1 * tmp1;
		tmp1 = (krovk->e_sq * tmp1) / (one_esq);
		krovk->alpha = sqrt (cs_One + tmp1);
		krovk->alpha_eo2 = krovk->alpha * krovk->ecent * cs_Half;

		sinLat0 = sinOrgLat / krovk->alpha;
		/* This asin is OK.  alpha is always >= 1.0 and sinOrgLat should
		   always be a legimate sine, thus sinLat0 should always be
		   legitimate. */
		lat0 = asin (sinLat0);

		/* What we really want is log K.  Since this is a setup function,
		   we'll complute K per the documentation, then compute logK. */
		tmp1 = krovk->ecent * sinOrgLat;
		tmp2 = tan (cs_Pi_o_4 + lat0 * cs_Half);
		tmp3 = tan (cs_Pi_o_4 + krovk->orgLat  * cs_Half);
		tmp4 = (cs_One + tmp1) / (cs_One - tmp1);
		krovk->logK = log (tmp2) - krovk->alpha * log (tmp3) + krovk->alpha_eo2 * log (tmp4);
		krovk->K = exp (krovk->logK);

		krovk->alpha_eo2 = krovk->alpha * (krovk->ecent * cs_Half);
		krovk->lngQ = krovk->alpha * krovk->poleLng;
		krovk->latQ = CSkrovkB1 (krovk,krovk->poleLat);
	}

	/* The remainder is the same for all variations. */
	krovk->nn = sin (krovk->stdLat);
	krovk->one_o_nn = cs_One / krovk->nn;
	krovk->tanTermF = tan (cs_Pi_o_4 + krovk->stdLat * cs_Half);
	krovk->tanTermI = pow (krovk->tanTermF,krovk->nn) * krovk->rho0;
	krovk->theta_max = cs_Pi * fabs (krovk->nn);
	krovk->pole_test = krovk->rho0 * cs_AnglTest;
	krovk->infinity = krovk->rho0 * cs_Four;

	/* Compute the terms used to calculate lat/longs on the oblique
	   gaussian surface (i.e. conformal sphere). */
	krovk->sinLatQ = sin (krovk->latQ);
	krovk->cosLatQ = cos (krovk->latQ);

	/* Set up the coordinate checking information.  If the user has
	   specified a useful range, we use it without checking it.
	   Otherwise, since this is currently a parameter-less projection,
	   we just set some rather arbitrary, but reasonable, values.
	   Note, org_Lng is relative to Ferro, so the min/max longitude
	   is also relative to Ferro.  This is a strange beast. */
	csprm->cent_mer = krovk->orgLng * cs_Radian;
	if (csprm->csdef.ll_min [LNG] == 0.0 &&
		csprm->csdef.ll_max [LNG] == 0.0)
	{
		csprm->min_ll [LNG] = 17.0;
		csprm->max_ll [LNG] = 47.0;
		csprm->min_ll [LAT] = 42.0;
		csprm->max_ll [LAT] = 55.0;
	}
	else
	{
		/* User specified value will be relative to Greenwich. */
		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 [XX] == 0.0)
	{
		/* Use the forward function to compute the X/Y's that collerate
		   with the min/max lat/lng. */
		test_ll [LNG] = csprm->min_ll [LNG];
		test_ll [LAT] = csprm->min_ll [LAT];
		CSkrovkF (krovk,test_xy,test_ll);						/*lint !e534 */
		csprm->min_xy [XX] = test_xy [XX];
		csprm->min_xy [YY] = test_xy [YY];

		test_ll [LNG] = csprm->max_ll [LNG];
		test_ll [LAT] = csprm->max_ll [LAT];
		CSkrovkF (krovk,test_xy,test_ll);						/*lint !e534 */
		csprm->max_xy [XX] = test_xy [XX];
		csprm->max_xy [YY] = test_xy [YY];
	}
	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)CSkrovkF;
	csprm->cs2ll    = (cs_CS2LL_CAST)CSkrovkI;
	csprm->cs_scale = (cs_SCALE_CAST)CSkrovkK;
	csprm->cs_sclk  = (cs_SCALK_CAST)CSkrovkK;
	csprm->cs_sclh  = (cs_SCALH_CAST)CSkrovkK;
	csprm->cs_cnvrg = (cs_CNVRG_CAST)CSkrovkC;
	csprm->llchk    = (cs_LLCHK_CAST)CSkrovkL;
	csprm->xychk    = (cs_XYCHK_CAST)CSkrovkX;
	return;
}
Exemple #9
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;
}
Exemple #10
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;
}
Exemple #11
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);
}
Exemple #12
0
void EXP_LVL9 CSnzlndS (struct cs_Csprm_ *csprm)
{
	extern short cs_QuadMin;			/* -4 */
	extern short cs_QuadMap [];
	extern double cs_Radian;			/* 57.29....  */
	extern double cs_Eight;				/* 1.0 / 8.0 */
	extern double cs_K15;				/* 15.0 */

	struct cs_Nzlnd_ *nzlnd;

	nzlnd = &csprm->proj_prms.nzlnd;

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

	/* NOTE: in this system, we work with latitudes in
	   degrees, (actually, seconds times 1.0E-05).
	   Longitudes are in radians.  However, since there
	   is not a single trigonometric function call
	   in the whole thing, we will use degrees in this
	   setup function. */

	nzlnd->org_lng = csprm->csdef.org_lng;
	nzlnd->org_lat = csprm->csdef.org_lat;
	nzlnd->k = csprm->csdef.scale * csprm->csdef.scl_red;
	nzlnd->x_off = csprm->csdef.x_off;
	nzlnd->y_off = csprm->csdef.y_off;
	nzlnd->quad = cs_QuadMap [csprm->csdef.quad - cs_QuadMin];

	/* The ellipsoid is the International by default.  We
	   don't even use the eccentricity.  We keep these
	   around for the empirical scale and convergence
	   calculations. */

	nzlnd->ecent = csprm->datum.ecent;
	nzlnd->e_rad = csprm->datum.e_rad;
	nzlnd->e_sq = nzlnd->ecent * nzlnd->ecent;
	nzlnd->ka = csprm->datum.e_rad * nzlnd->k;

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

	nzlnd->one_mm = 0.0001 * nzlnd->k;

	/* The delta latitude normalization constant. */

	nzlnd->lat_kk = (3600.0 * 1.0E-05);

	/* The series which have been developed are hard coded
	   for the International ellipsoid.  Therefore there
	   is only one set of equations.

	   Stuff the series coefficients here.  This enables us
	   to use our complex Horner expansion code. */

	nzlnd->A_ary [0] =  0.6399175073;
	nzlnd->A_ary [1] = -0.1358797613;
	nzlnd->A_ary [2] =  0.063294409;
	nzlnd->A_ary [3] = -0.02526853;
	nzlnd->A_ary [4] =  0.0117879;
	nzlnd->A_ary [5] = -0.0055161;
	nzlnd->A_ary [6] =  0.0026906;
	nzlnd->A_ary [7] = -0.001333;
	nzlnd->A_ary [8] =  0.00067;
	nzlnd->A_ary [9] = -0.00034;

	nzlnd->B_ary [0].real =  0.0;		nzlnd->B_ary [0].img  =  0.0;
	nzlnd->B_ary [1].real =  0.7557853228;	nzlnd->B_ary [1].img  =  0.0;
	nzlnd->B_ary [2].real =  0.249204646;	nzlnd->B_ary [2].img  =  0.003371507;
	nzlnd->B_ary [3].real = -0.001541739;	nzlnd->B_ary [3].img  =  0.041058560;
	nzlnd->B_ary [4].real = -0.10162907;	nzlnd->B_ary [4].img  =  0.01727609;
	nzlnd->B_ary [5].real = -0.26623489;	nzlnd->B_ary [5].img  = -0.36249218;
	nzlnd->B_ary [6].real = -0.6870983;	nzlnd->B_ary [6].img  = -1.1651967;

	nzlnd->C_ary [0].real =  0.0;		nzlnd->C_ary [0].img  =  0.0;
	nzlnd->C_ary [1].real =  1.3231270439;	nzlnd->C_ary [1].img  =  0.0;
	nzlnd->C_ary [2].real = -0.577245789;	nzlnd->C_ary [2].img  = -0.007809598;
	nzlnd->C_ary [3].real =  0.508307513;	nzlnd->C_ary [3].img  = -0.112208952;
	nzlnd->C_ary [4].real = -0.15094762;	nzlnd->C_ary [4].img  =  0.18200602;
	nzlnd->C_ary [5].real =  1.01418179;	nzlnd->C_ary [5].img  =  1.64497696;
	nzlnd->C_ary [6].real =  1.9660549;	nzlnd->C_ary [6].img  =  2.5127645;

	nzlnd->D_ary [0] =  1.5627014243;
	nzlnd->D_ary [1] =  0.5185406398;
	nzlnd->D_ary [2] = -0.03333098;
	nzlnd->D_ary [3] = -0.1052906;
	nzlnd->D_ary [4] = -0.0368594;
	nzlnd->D_ary [5] =  0.007317;
	nzlnd->D_ary [6] =  0.01220;
	nzlnd->D_ary [7] =  0.00394;
	nzlnd->D_ary [8] = -0.0013;

	/* 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 = nzlnd->org_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] = -cs_K15;
		csprm->max_ll [LNG] = cs_K15;
		csprm->min_ll [LAT] = nzlnd->org_lat * cs_Radian - cs_K15;
		csprm->max_ll [LAT] = nzlnd->org_lat * cs_Radian + cs_K15;
	}
	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 CSnzlndF
		   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] = -cs_Eight * nzlnd->ka;
		csprm->max_xy [XX] =  cs_Eight * nzlnd->ka;
		csprm->min_xy [YY] = -cs_Eight * nzlnd->ka;
		csprm->max_xy [YY] =  cs_Eight * nzlnd->ka;

		CS_quadMM (csprm->min_xy,csprm->max_xy,nzlnd->x_off,
											   nzlnd->y_off,
											   nzlnd->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];
	}

	csprm->ll2cs    = (cs_LL2CS_CAST)CSnzlndF;
	csprm->cs2ll    = (cs_CS2LL_CAST)CSnzlndI;
	csprm->cs_scale = (cs_SCALE_CAST)CSnzlndK;
	csprm->cs_sclk  = (cs_SCALK_CAST)CSnzlndK;
	csprm->cs_sclh  = (cs_SCALH_CAST)CSnzlndK;
	csprm->cs_cnvrg = (cs_CNVRG_CAST)CSnzlndC;
	csprm->llchk    = (cs_LLCHK_CAST)CSnzlndL;
	csprm->xychk    = (cs_XYCHK_CAST)CSnzlndX;

	return;
}
Exemple #13
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;
}
Exemple #14
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;
}
Exemple #15
0
void EXP_LVL9 CSlmtanS (struct cs_Csprm_ *csprm)
{
	extern short cs_QuadMin;			/* -4 */
	extern short cs_QuadMap [];
	extern double cs_Pi;				/*  PI */
	extern double cs_Pi_o_4;			/*  PI / 4.0     */
	extern double cs_Radian;			/* 57.2..... */
	extern double cs_Degree;			/* 1.0 / 57.2...  */
	extern double cs_Half;				/* 0.5 */
	extern double cs_One;				/* 1.0 */
	extern double cs_K15;				/* 15.0 */
	extern double cs_K45;				/* 45.0 */
	extern double cs_Km45;				/* -45.0 */
	extern double cs_MinLatFz;			/* -89.999777 */
	extern double cs_MaxLatFz;			/*  89.999777 */

	extern double cs_NPTest;			/* 0.001 arc seconds short
										   of the north pole, in
										   radians. */

	struct cs_Lmtan_ *lmtan;

	double tmp1;
	double tmp2;
	double tmp3;

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

	lmtan = &csprm->proj_prms.lmtan;

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

	lmtan->org_lng = csprm->csdef.org_lng * cs_Degree;
	lmtan->org_lat = csprm->csdef.org_lat * cs_Degree;
	lmtan->kerad = csprm->datum.e_rad * csprm->csdef.scale;
	lmtan->k = csprm->csdef.scale * csprm->csdef.scl_red;
	lmtan->x_off = csprm->csdef.x_off;
	lmtan->y_off = csprm->csdef.y_off;
	lmtan->ecent = csprm->datum.ecent;
	lmtan->e_sq = lmtan->ecent * lmtan->ecent;
	lmtan->e_ovr_2 = lmtan->ecent * cs_Half;
	lmtan->ka = csprm->datum.e_rad * lmtan->k;
	lmtan->sin_org_lat = sin (lmtan->org_lat);
	lmtan->quad = cs_QuadMap [csprm->csdef.quad - cs_QuadMin];

	lmtan->N0 = lmtan->ka / sqrt (cs_One - lmtan->e_sq *
								  lmtan->sin_org_lat *
								  lmtan->sin_org_lat);

	/* R0 is the radius of the arc which represents the origin
	   latitude.

	   Origin latitude of zero is invalid, and should be (is)
	   caught in CSlmtanQ. */

	lmtan->R0 = lmtan->N0 / tan (lmtan->org_lat);

	tmp1 = cs_Pi_o_4 + (lmtan->org_lat * cs_Half);
	tmp1 = tan (tmp1);
	tmp2 = lmtan->ecent * lmtan->sin_org_lat;
	tmp3 = log ((cs_One + tmp2) / (cs_One - tmp2));

	lmtan->L0 = log (tmp1) - (lmtan->e_ovr_2 * tmp3);
	lmtan->c = lmtan->R0 * exp (lmtan->sin_org_lat * lmtan->L0);
	lmtan->abs_c = fabs (lmtan->c);

	/* Compute the mathematical limits of this projection. */

	lmtan->one_mm = csprm->csdef.scale * 0.001;
	lmtan->max_Gamma = fabs (lmtan->sin_org_lat) * cs_Pi;
	lmtan->max_R = lmtan->c * pow (tan (cs_NPTest),lmtan->sin_org_lat);

	/* 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 = lmtan->org_lng * cs_Radian;
	if (csprm->csdef.ll_min [LNG] == 0.0 &&
	    csprm->csdef.ll_max [LNG] == 0.0)
	{
		/* We're to calculate a useful range. */

		csprm->min_ll [LNG] = cs_Km45;
		csprm->max_ll [LNG] = cs_K45;
		csprm->min_ll [LAT] = lmtan->org_lat * cs_Radian - cs_K15;
		if (csprm->min_ll [LAT] < cs_MinLatFz) csprm->min_ll [LAT] = cs_MinLatFz;
		csprm->max_ll [LAT] = lmtan->org_lat * cs_Radian + cs_K15;
		if (csprm->min_ll [LAT] > cs_MaxLatFz) csprm->min_ll [LAT] = cs_MaxLatFz;
	}
	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 CStrmerF
		   to calculate some values. */

		test_ll [LNG] = CS_adj180 (csprm->cent_mer + csprm->min_ll [LNG]);
		test_ll [LAT] = csprm->min_ll [LAT];
		CSlmtanF (lmtan,test_xy,test_ll);				/*lint !e534 */
		csprm->min_xy [YY] = test_xy [YY] - lmtan->y_off;
		if (lmtan->sin_org_lat > 0.0)
		{
			/* North pole cone. */

			csprm->min_xy [XX] = test_xy [XX] - lmtan->x_off;
			csprm->max_xy [XX] = -csprm->min_xy [XX];
		}

		test_ll [LAT] = csprm->max_ll [LAT];
		CSlmtanF (lmtan,test_xy,test_ll);				/*lint !e534 */
		csprm->max_xy [YY] = test_xy [YY] - lmtan->y_off;
		if (lmtan->sin_org_lat < 0.0)
		{
			/* South pole cone. */

			csprm->min_xy [XX] = test_xy [XX] - lmtan->x_off;
			csprm->max_xy [XX] = -csprm->min_xy [XX];
		}

		CS_quadMM (csprm->min_xy,csprm->max_xy,lmtan->x_off,
											   lmtan->y_off,
											   lmtan->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.  We have no information
	   on the scale or convergence of this function. */

	csprm->ll2cs    = (cs_LL2CS_CAST)CSlmtanF;
	csprm->cs2ll    = (cs_CS2LL_CAST)CSlmtanI;
	csprm->cs_scale = (cs_SCALE_CAST)CSlmtanK;
	csprm->cs_sclk  = (cs_SCALK_CAST)CSlmtanK;
	csprm->cs_sclh  = (cs_SCALH_CAST)CSlmtanH;
	csprm->cs_cnvrg = (cs_CNVRG_CAST)CSlmtanC;
	csprm->llchk    = (cs_LLCHK_CAST)CSlmtanL;
	csprm->xychk    = (cs_XYCHK_CAST)CSlmtanX;

	return;
}