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); }
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); }
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); }
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); }
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); }
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); }