Пример #1
0
double EXP_LVL9 CSnzlndK (Const struct cs_Nzlnd_ *nzlnd,Const double ll [2])
{
	extern double cs_Mone;			/* -1.0, the value we return
									   when presented with bogus
									   lat/long coordinates. */
	int status;

	double kk;
	double ll_dd;
	double xy_dd;
	double del_xx, del_yy;

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

	/* Establish two points along the parallel which are
	   about .5 seconds (about 15 meters) apart from each
	   other, with the point in question in the middle.
	   Then convert each point to the equivalent grid
	   coordinates. */

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

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

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

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

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

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

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

	kk = xy_dd / ll_dd;
	return (kk);
}
Пример #2
0
double EXP_LVL9 CSazmedK (Const struct cs_Azmed_ *azmed,Const double ll [2])
{
	extern double cs_Degree;			/* 1.0 / 57.29577... */
	extern double cs_Radian;			/* 57.29577... */
	extern double cs_Pi_o_2;			/* PI / 2.0 */
	extern double cs_One;				/* 1.0 */
	extern double cs_Mone;				/* -1.0 */
	extern double cs_NPTest;			/* 0.001 arc seconds short
										   of the north pole, in
										   radians. */
	extern double cs_SPTest;			/* 0.001 arc seconds short
										   of the south pole, in
										   radians. */
	extern double cs_AnglTest1;			/* 1 - sin of 0.001 seconds
										   of arc. */
	extern double cs_SclInf;			/* 9.9E+04, the value we
										   return for an infinite
										   scale factor. */

	int status;

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

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

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

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

		/* What aspect? */

		switch (azmed->aspect) {

		case cs_AZMED_NORTH:

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

		case cs_AZMED_SOUTH:

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

		default:
		case cs_AZMED_GUAM:
		case cs_AZMED_EQUATOR:
		case cs_AZMED_OBLIQUE:

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

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

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

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

		switch (azmed->aspect) {

		case cs_AZMED_NORTH:

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

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

		case cs_AZMED_SOUTH:

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

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

		default:
		case cs_AZMED_GUAM:
		case cs_AZMED_EQUATOR:
		case cs_AZMED_OBLIQUE:

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

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

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

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

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

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

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

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

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

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

			kk = xy_dd / ll_dd;
			break;
		}
	}
	return (kk);
}
Пример #3
0
double EXP_LVL9 CSsinusH (Const struct cs_Sinus_ *sinus,Const double ll [2])
{
	extern double cs_Degree;			/* 1.0 / RADIAN  */
	extern double cs_Pi_o_2;			/* Pi over 2 */
	extern double cs_One;				/* 1.0 */
	extern double cs_Mone;				/* -1.0 */
	extern double cs_SclInf;			/* 9.9E+04, the value we
										   return for an infinite
										   scale factor. */
	extern double cs_NPTest;			/* 0.001 arc seconds short
										   of the north pole, in
										   radians. */
	int status;

	Const struct cs_Zone_ *zp;

	double hh;
	double lng;
	double lat;

	double del_lng;
	double sin_lat;
	double cent_lng;

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

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

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

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

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

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

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

	/* Different algorithms for sphere or ellipsoid. */

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

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

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

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

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

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

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

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

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

		if (ll_dd > sinus->one_mm)
		{
			hh = xy_dd / ll_dd;
		}
		else
		{
			hh = cs_SclInf;
		}
	}
	return (hh);
}
Пример #4
0
double EXP_LVL9 CStacylH (Const struct cs_Tacyl_ *tacyl,Const double ll [2])
{
    extern double cs_HlfSecDeg;		/* One half second of arc in
									   degrees. */
    extern double cs_Sin1Sec;		/* Sine of one second of arc, used
									   here as one second of arc in
									   radians. */
    extern double cs_Mone;			/* -1, the value we return when
									   provided with a bogus point. */
    extern double cs_SclInf;		/* 9.9E+04, the value returned
									   to indicate an infinite
									   scale factor */
    int status;

    double hh;
    double ll_dd;
    double xy_dd;
    double del_xx, del_yy;

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

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

    ll1 [LNG] = ll [LNG];
    ll1 [LAT] = ll [LAT] - cs_HlfSecDeg;
    status = CStacylF (tacyl,xy1,ll1);
    if (status != cs_CNVRT_NRML)
    {
        return (cs_Mone);
    }

    ll2 [LNG] = ll [LNG];
    ll2 [LAT] = ll [LAT] + cs_HlfSecDeg;
    status = CStacylF (tacyl,xy2,ll2);
    if (status != cs_CNVRT_NRML)
    {
        return (cs_Mone);
    }

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

    if (tacyl->ecent == 0.0)
    {
        ll_dd = cs_Sin1Sec * tacyl->ka;
    }
    else
    {
        CS_llazdd (tacyl->ka,tacyl->e_sq,ll1,ll2,&ll_dd);
    }

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

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

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

    if (ll_dd > 0.0)
    {
        hh = xy_dd / ll_dd;
    }
    else
    {
        hh = cs_SclInf;
    }
    return (hh);
}
Пример #5
0
double EXP_LVL9 CStacylK (Const struct cs_Tacyl_ *tacyl,Const double ll [2])
{
    extern double cs_Degree;		/* pi / 180.0 */
    extern double cs_Sin1Sec;		/* Sine of one arc second. */
    extern double cs_SclInf;		/* 9.9E+04, the value which we
									   return for an infinite
									   scale factor. */
    extern double cs_Mone;			/* -1.0 */
    extern double cs_AnglTest;		/* 0.001 arc seconds, in radians. */
    extern double cs_HlfSecDeg;		/* 0.5 seconds of arc, in degrees. */

    int status;

    double kk;
    double xy_dd, ll_dd;
    double del_xx, del_yy;

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

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

    ll1 [LNG] = ll [LNG] - cs_HlfSecDeg;;
    ll1 [LAT] = ll [LAT];
    status = CStacylF (tacyl,xy1,ll1);
    if (status != cs_CNVRT_NRML)
    {
        return (cs_Mone);
    }

    ll2 [LNG] = ll [LNG] + cs_HlfSecDeg;
    ll2 [LAT] = ll [LAT];
    status = CStacylF (tacyl,xy2,ll2);
    if (status != cs_CNVRT_NRML)
    {
        return (cs_Mone);
    }

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

    del_xx = xy1 [XX] - xy2 [XX];
    del_yy = xy1 [YY] - xy2 [YY];
    xy_dd = sqrt (del_xx * del_xx + del_yy * del_yy);
    if (xy_dd == 0.0)
    {
        /* This can happen when very close to the singularity
           point for this projection. */

        return (cs_Mone);
    }

    if (tacyl->ecent == 0.0)
    {
        /* Here for a sphere.  cs_Sin1Sec is the sine of one
           arc second; which is essentially the same as
           one arc second in radians. */

        ll_dd = cs_Sin1Sec * tacyl->ka * cos (ll [LAT] * cs_Degree);
    }
    else
    {
        /* Calculate the geodetic distance between the two
           lat/long points. */

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

    /* Return the ration of the two distances as the grid
       scale factor at the point. */

    if (ll_dd > cs_AnglTest)
    {
        kk = xy_dd / ll_dd;
    }
    else
    {
        kk = cs_SclInf;
    }
    return (kk);
}
Пример #6
0
double EXP_LVL9 CSlmtanK (Const struct cs_Lmtan_ *lmtan,Const double ll [2])
{
	extern double cs_SclInf;		/* 9.9E+04, the value we return
									   for an infinite scale
									   factor. */
	extern double cs_HlfSecDeg;		/* One half arc second in
									   degrees. */

	double kk;
	double ll_dd;
	double xy_dd;
	double del_xx, del_yy;

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

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

	ll1 [LNG] = ll [LNG];
	ll1 [LAT] = ll [LAT] - cs_HlfSecDeg;
	CSlmtanF (lmtan,xy1,ll1);					/*lint !e534 */

	ll2 [LNG] = ll [LNG];
	ll2 [LAT] = ll [LAT] + cs_HlfSecDeg;
	CSlmtanF (lmtan,xy2,ll2);					/*lint !e534 */

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

	CS_llazdd (lmtan->kerad,lmtan->e_sq,ll1,ll2,&ll_dd);

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

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

	/* Return the ratio of the two distances as the parallel
	   scale factor at the indicated point.  I don't think
	   ll_dd can be zero since we know that ll1 id not the
	   same as ll0.  However, just to be safe: */

	if (fabs (ll_dd) > lmtan->one_mm)
	{
		kk = xy_dd / ll_dd;
	}
	else
	{
		kk = cs_SclInf;
	}
	return (kk);
}