double EXP_LVL5 CSccsphrR (Const double ll0 [2],Const double ll1 [2]) { extern double cs_Zero; /* 0.0 */ extern double cs_Half; /* 0.5 */ extern double cs_Two; /* 2.0 */ double cc; double sin_del_lng; double sin_del_lat; double cos_lat0; double cos_lat1; double tmp3; sin_del_lng = sin (CS_adj2pi (ll1 [LNG] - ll0 [LNG]) * cs_Half); sin_del_lat = sin (CS_adj1pi (ll1 [LAT] - ll0 [LAT]) * cs_Half); cos_lat0 = cos (CS_adj1pi (ll0 [LAT])); cos_lat1 = cos (CS_adj1pi (ll1 [LAT])); tmp3 = (sin_del_lat * sin_del_lat) + (cos_lat0 * cos_lat1) * (sin_del_lng * sin_del_lng); if (tmp3 > 0.0) { cc = cs_Two * asin (sqrt (tmp3)); } else { cc = cs_Zero; } return (cc); }
int EXP_LVL9 CSwinklF (Const struct cs_Winkl_ *winkl,double xy [2],Const double ll [2]) { extern double cs_Degree; extern double cs_Pi; extern double cs_Pi_o_2; extern double cs_3Pi_o_2; extern double cs_Two_pi; int rtn_val; double del_lng; double lng; double lat; double xx; double yy; rtn_val = cs_CNVRT_NRML; /* For this projection, we only support the spherical form, therefore there is only one set of equations. These are pretty simple. */ lat = ll [LAT] * cs_Degree; if (fabs (lat) > cs_Pi_o_2) { rtn_val = cs_CNVRT_RNG; lat = CS_adj1pi (lat); } lng = ll [LNG] * cs_Degree; del_lng = lng - winkl->org_lng; /* For this projection, we assure that the central meridian is the center of the map; this implying that delta longitude is always less than or equal to pi, and greater than minus pi. */ if (fabs (del_lng) > cs_3Pi_o_2) { rtn_val = cs_CNVRT_RNG; } if (fabs (del_lng) > cs_Pi) { del_lng = CS_adj2pi (del_lng); } rtn_val = CSwinklB (winkl,&xx,&yy,del_lng,lat); if (winkl->quad == 0) { xy [XX] = xx + winkl->x_off; xy [YY] = yy + winkl->y_off; } else { CS_quadF (xy,xx,yy,winkl->x_off,winkl->y_off,winkl->quad); } return rtn_val; }
int EXP_LVL9 CSazmedF (Const struct cs_Azmed_ *azmed,double xy [2],Const double ll [2]) { extern char csErrnam [MAXPATH]; extern double cs_Degree; /* 1.0 / RADIAN */ extern double cs_Pi; /* 3.14159... */ extern double cs_Two_pi; /* 2 PI */ extern double cs_Mpi; /* -3.14159.... */ extern double cs_Pi_o_2; /* PI over 2 */ extern double cs_Mpi_o_2; /* Minus PI over 2 */ extern double cs_Zero; /* 0.0 */ extern double cs_One; /* 1.0 */ extern double cs_Mone; /*-1.0 */ extern double cs_Two; /* 2.0 */ extern double cs_Four; /* 4.0 */ extern double cs_Six; /* 6.0 */ extern double cs_Seven; /* 7.0 */ extern double cs_Eight; /* 8.0 */ extern double cs_NPTest; /* 0.001 seconds of arc short of the north pole in radians. */ extern double cs_AnglTest; /* 0.001 seconds of arc in radians. */ extern double cs_AnglTest1; /* 1.0 - 0.001 seconds of arc in radians. Could also be considered to be the cosine of cs_AnglTest. */ int rtn_val; double lng; /* The given longitude, after conversion to radians. */ double lat; /* The given latitude after conversion to radians. */ double x = 0.0; /* initialized to keep the gcc compiler happy */ double y = 0.0; /* initialized to keep the gcc compiler happy */ double M; double N; double H; double H_sq; double H_sq_7; double GH; double rho; double psi; double del_lng; double sin_del_lng; double cos_del_lng; double sin_lat; double cos_lat; double cos_c; double c; double Az; double sin_Az; double cos_Az; double s; double s_sq; double s_third; double s_fourth; double s_fifth; double tmp1; double tmp2; double tmp3; double tmp4; rtn_val = cs_CNVRT_NRML; /* There are two formulae, one for the sphere and one for the ellipsoid. If the ecentricity of the dataum in use is 0.0 exactly, we shall use the spherical formulae. There is a miminal amount of stuff which is common to both which we perform first. */ lng = cs_Degree * ll [LNG]; lat = cs_Degree * ll [LAT]; if (fabs (lat) > cs_NPTest) { rtn_val = cs_CNVRT_INDF; if (fabs (lat) > cs_Pi_o_2) { rtn_val = cs_CNVRT_RNG; lat = CS_adj1pi (lat); } } del_lng = lng - azmed->org_lng; if (del_lng > cs_Pi && azmed->org_lng < 0.0) del_lng -= cs_Two_pi; else if (del_lng < cs_Mpi && azmed->org_lng > 0.0) del_lng += cs_Two_pi; if (del_lng > cs_Pi || del_lng <= cs_Mpi) { /* Note, the inverse can't distinguish between -180 and +180; therefore we return a range status for -180. */ rtn_val = cs_CNVRT_RNG; del_lng = CS_adj2pi (del_lng); } sin_del_lng = sin (del_lng); cos_del_lng = cos (del_lng); sin_lat = sin (lat); cos_lat = cos (lat); /* See if the datum is a sphere or an ellipsoid. */ if (azmed->ecent == 0.0) { /* Here for the sphere. */ switch (azmed->aspect) { case cs_AZMED_NORTH: tmp1 = (cs_Pi_o_2 - lat) * azmed->ka; x = tmp1 * sin_del_lng; y = -tmp1 * cos_del_lng; break; case cs_AZMED_SOUTH: tmp1 = (cs_Pi_o_2 + lat) * azmed->ka; x = tmp1 * sin_del_lng; y = tmp1 * cos_del_lng; break; case cs_AZMED_EQUATOR: cos_c = cos_lat * cos_del_lng; c = acos (cos_c); if (fabs (c) < cs_AnglTest) { /* At the origin. */ tmp1 = cs_Zero; } else if (cos_c < -cs_AnglTest1) { /* AntiPodal */ rtn_val = cs_CNVRT_RNG; tmp1 = azmed->ka * cs_Pi; } else { /* Normal */ tmp1 = azmed->ka * c / sin (c); } x = tmp1 * cos_lat * sin_del_lng; y = tmp1 * sin_lat; break; case cs_AZMED_GUAM: x = azmed->ka * del_lng * cos_lat; tmp1 = x * x * tan (lat) / azmed->two_ka; y = azmed->ka * (lat - azmed->org_lat) + tmp1; break; case cs_AZMED_OBLIQUE: cos_c = azmed->sin_org_lat * sin_lat + azmed->cos_org_lat * cos_lat * cos_del_lng; c = acos (cos_c); /* C is the angular distance from the origin. A zero value indicates the orgin which would cause a division by sin (0); but otherwise is a perfectly normal value for this projection. As c approaches PI, however, we approach the point opposite the origin, and this point is not well defined. */ if (fabs (c) <= cs_AnglTest) { /* The origin. */ tmp1 = cs_Zero; } else if (cos_c < -cs_AnglTest1) { /* Antipodal to the origin. */ rtn_val = cs_CNVRT_RNG; tmp1 = azmed->ka * cs_Pi; } else { /* Normal, We can divide by sin (c). */ tmp1 = azmed->ka * (c / sin (c)); } x = tmp1 * cos_lat * sin_del_lng; y = tmp1 * (azmed->cos_org_lat * sin_lat - azmed->sin_org_lat * cos_lat * cos_del_lng); break; default: CS_stncp (csErrnam,"CS_azmed:1",MAXPATH); CS_erpt (cs_ISER); rtn_val = -1; break; } } else { switch (azmed->aspect) { case cs_AZMED_NORTH: M = CSmmFcal (&azmed->mmcofF,lat,sin_lat,cos_lat); rho = azmed->Mp - M; x = rho * sin_del_lng; y = -rho * cos_del_lng; break; case cs_AZMED_SOUTH: M = CSmmFcal (&azmed->mmcofF,lat,sin_lat,cos_lat); rho = azmed->Mp + M; x = rho * sin_del_lng; y = rho * cos_del_lng; break; case cs_AZMED_GUAM: M = CSmmFcal (&azmed->mmcofF,lat,sin_lat,cos_lat); tmp1 = sqrt (azmed->e_sq * sin_lat * sin_lat); x = azmed->ka * del_lng * cos_lat / tmp1; tmp2 = tan (lat) * x * x * tmp1 / azmed->two_ka; y = M - azmed->M1 + tmp2; /*lint !e834 */ break; case cs_AZMED_EQUATOR: case cs_AZMED_OBLIQUE: /* Compute Az, the azimuth of the point with respect to the origin on the ellipsoid. Psi is the latitude of the point, adjusted for the ellipsoid. This is zero or cs_Pi_o_2 if the latitude is a pole (don't want to divide by cos (lat) in this case. */ if (fabs (lat) > cs_NPTest) { /* Point is a pole. */ psi = (lat > 0.0) ? cs_Pi_o_2 : cs_Mpi_o_2; } else { /* Cosine (lat) will not be zero, we can compute psi safely. */ tmp1 = azmed->e_sq * sin_lat * sin_lat; N = azmed->ka / sqrt (cs_One - tmp1); tmp2 = (azmed->one_esq * tan (lat)) + azmed->psi_t1 / (N * cos_lat); psi = atan (tmp2); } tmp3 = (azmed->cos_org_lat * tan (psi)) - (azmed->sin_org_lat * cos_del_lng); /* Tmp3 and sin_del_lng will both be zero if the point is the origin. Most atan2's (not all) will bomb if both args are zero. */ if (fabs (sin_del_lng) > cs_AnglTest) { Az = atan2 (sin_del_lng,tmp3); sin_Az = sin (Az); cos_Az = cos (Az); } else { /* del_lng is zero, we do a quick and dirty atan2. */ sin_Az = cs_Zero; if (tmp3 >= 0.0) { Az = cs_Zero; cos_Az = cs_One; } else { Az = cs_Mpi; cos_Az = cs_Mone; } } /* Ok, we have the azimuth. Need to compute the angular distance to the point on the ellipsoid. In the case of small angles, the sine and the angle are equivalent. */ if (fabs (sin_Az) < cs_AnglTest) { /* Here to avoid a divide by sin (Az). */ tmp4 = azmed->cos_org_lat * sin (psi) - azmed->sin_org_lat * cos (psi); s = asin (tmp4); if (cos_Az < 0.0) { s = -s; } } else { s = asin (sin_del_lng * cos (psi) / sin_Az); } /* S is essentially the angular distance over a sphere. Convert to c, the linear distance over the ellipsoid, via a power series calculation. */ s_sq = s * s; s_third = s_sq * s; s_fourth = s_sq * s_sq; s_fifth = s_fourth * s; H = azmed->e_cos_p1 * cos_Az / azmed->rt_one_esq; H_sq = H * H; H_sq_7 = cs_Seven * H_sq; GH = azmed->G * H; tmp2 = H_sq * (cs_Four - H_sq_7); tmp2 -= azmed->G_sq_3 * (cs_One - H_sq_7); tmp1 = cs_One; tmp1 -= s_sq * H_sq * (cs_One - H_sq) / cs_Six; tmp1 += (s_third / cs_Eight) * GH * (cs_One - cs_Two * H_sq); tmp1 += (s_fourth / 120.0) * tmp2; tmp1 -= (s_fifth / 48.0) * GH; c = azmed->N1 * s * tmp1; x = c * sin_Az; y = c * cos_Az; break; default: CS_stncp (csErrnam,"CS_azmed:2",MAXPATH); CS_erpt (cs_ISER); rtn_val = -1; break; } } /* Add the rotation, quad effect, and offset. */ if (rtn_val >= 0) { xy [XX] = azmed->cos_Az * x - azmed->sin_Az * y; xy [YY] = azmed->cos_Az * y + azmed->sin_Az * x; if (azmed->quad == 0) { xy [XX] += azmed->x_off; xy [YY] += azmed->y_off; } else { CS_quadF (xy,xy [XX],xy [YY],azmed->x_off,azmed->y_off, azmed->quad); } } return (rtn_val); }
int EXP_LVL9 CSvdgrnF (Const struct cs_Vdgrn_ *vdgrn,double xy [2],Const double ll [2]) { extern double cs_Degree; /* 1.0 / RADIAN */ extern double cs_Pi; /* 3.14159..... */ extern double cs_Two_pi; /* 2 pi */ extern double cs_Mpi; /* -3.14159..... */ extern double cs_Pi_o_2; /* Pi over 2 */ extern double cs_Zero; /* 0.0 */ extern double cs_Half; /* 0.5 */ extern double cs_One; /* 1.0 */ extern double cs_Two; /* 2.0 */ extern double cs_NPTest; /* 0.001 seconds of arc short of the north pole, in radians. */ extern double cs_AnglTest; /* 0.001 seconds of arc, in radians. */ int rtn_val; double lng; /* The given longitude, after conversion to radians. */ double lat; /* The given latitude after conversion to radians. */ double del_lng; double abs_lat; double xx; double yy; double theta; double sin_theta, cos_theta; double A, A_sq; double P, P_sq; double G; double Q; double tmp1, tmp2, tmp3; rtn_val = cs_CNVRT_NRML; /* For this projection, we only support the spherical form, therefore there is only one set of equations. */ lng = ll [LNG] * cs_Degree; del_lng = lng - vdgrn->org_lng; if (del_lng > cs_Pi && vdgrn->org_lng < 0.0) del_lng -= cs_Two_pi; else if (del_lng < cs_Mpi && vdgrn->org_lng > 0.0) del_lng += cs_Two_pi; if (fabs (del_lng) > cs_Pi) { rtn_val = cs_CNVRT_RNG; del_lng = CS_adj2piI (del_lng); } lat = ll [LAT] * cs_Degree; abs_lat = fabs (lat); if (abs_lat > cs_NPTest) { rtn_val = cs_CNVRT_INDF; if (abs_lat > cs_Pi_o_2) { rtn_val = cs_CNVRT_RNG; lat = CS_adj1pi (lat); abs_lat = fabs (lat); } } if (abs_lat > cs_NPTest) { /* The sign of yy gets reversed below, we can simply use cs_Pi here. */ xx = cs_Zero; yy = cs_Pi * vdgrn->ka; } else if (abs_lat <= cs_AnglTest) { /* This is the calculation for the equator. The sign of X gets reversed below, we need to use the absolute value here. */ xx = vdgrn->ka * fabs (del_lng); yy = cs_Zero; } else if (fabs (del_lng) < cs_AnglTest) { /* We're on the central meridian, BUT NOT on the equator, and not at either pole. Npte, sign of result is dealt with below. */ xx = cs_Zero; theta = asin (abs_lat / cs_Pi_o_2); yy = cs_Pi * vdgrn->ka * tan (theta * cs_Half); } else { /* OK, we're not at either pole, or the equator. The rest of this should be pretty safe. */ sin_theta = fabs (lat) * vdgrn->two_ovr_pi; cos_theta = sqrt (cs_One - sin_theta * sin_theta); tmp1 = (cs_Pi / del_lng) - (del_lng / cs_Pi); A = cs_Half * fabs (tmp1); A_sq = A * A; G = cos_theta / (sin_theta + cos_theta - cs_One); P = G * ((cs_Two / sin_theta) - cs_One); P_sq = P * P; Q = A_sq + G; tmp1 = P_sq + A_sq; tmp2 = G - P_sq; tmp3 = tmp1 * ((G * G) - P_sq); tmp3 = (A_sq * tmp2 * tmp2) - tmp3; if (tmp3 < 0.0) tmp3 = cs_Zero; tmp3 = (A * tmp2) + sqrt (tmp3); xx = vdgrn->piR * tmp3 / tmp1; tmp3 = ((A_sq + cs_One) * tmp1) - (Q * Q); if (tmp3 < 0.0) tmp3 = cs_Zero; tmp3 = (P * Q) - (A * sqrt (tmp3)); yy = vdgrn->piR * tmp3 / tmp1; } /* Apply the appropriate sign and false origin. */ xy [XX] = (del_lng >= 0.0) ? xx : -xx; xy [YY] = (lat >= 0.0) ? yy : -yy; if (vdgrn->quad == 0) { xy [XX] += vdgrn->x_off; xy [YY] += vdgrn->y_off; } else { CS_quadF (xy,xy [XX],xy [YY],vdgrn->x_off,vdgrn->y_off,vdgrn->quad); } return (rtn_val); }
int EXP_LVL9 CSsinusF (Const struct cs_Sinus_ *sinus,double xy [2],Const double ll [2]) { extern double cs_Degree; /* 1.0 / RADIAN */ extern double cs_Pi_o_2; /* Pi over 2 */ extern double cs_3Pi_o_2; /* 3 Pi over 2 */ extern double cs_Two_pi; /* 2 Pi */ extern double cs_One; /* 1.0 */ extern double cs_NPTest; /* 0.001 seconds of arc short of the north pole, in radians. */ int rtn_val; Const struct cs_Zone_ *zp; double lng; /* The given longitude, after conversion to radians. */ double lat; /* The given latitude after conversion to radians. */ double cent_lng; /* Local central meridian after adjust- ment for appropriate zones. */ double x_off; /* Local false easting after adjustment for the appropriate zone. */ double del_lng; double sin_lat; double cos_lat; double tmp1; rtn_val = cs_CNVRT_NRML; /* Convert the latitude and longitude to radians. */ lat = cs_Degree * ll [LAT]; if (fabs (lat) > cs_NPTest) { rtn_val = cs_CNVRT_INDF; if (fabs (lat) > cs_Pi_o_2) { rtn_val = cs_CNVRT_RNG; lat = CS_adj1pi (lat); } } lng = cs_Degree * ll [LNG]; /* If there are any interrupted zones for this coordinate system, select the proper zone for this longitude and latitude. Once selected, we use the zone to establish the origin longitude and the appropriate false easting for the zone. */ if (sinus->zone_cnt > 0) { zp = CS_znlocF (sinus->zones,sinus->zone_cnt,lng,lat); if (zp != NULL) { cent_lng = zp->cent_lng; x_off = zp->x_off; } else { rtn_val = cs_CNVRT_RNG; cent_lng = sinus->cent_lng; x_off = sinus->x_off; } } else { zp = NULL; cent_lng = sinus->cent_lng; x_off = sinus->x_off; } /* Perform the conversion. */ del_lng = lng - cent_lng; if (del_lng > cs_3Pi_o_2 && cent_lng < 0.0) del_lng -= cs_Two_pi; else if (del_lng < -cs_3Pi_o_2 && cent_lng > 0.0) del_lng += cs_Two_pi; if (fabs (del_lng) >= cs_3Pi_o_2) { rtn_val = cs_CNVRT_RNG; del_lng = CS_adj2pi (del_lng); } if (sinus->ecent == 0.0) { /* Here for the sphere. */ xy [XX] = sinus->ka * del_lng * cos (lat); xy [YY] = sinus->ka * lat; } else { /* Here for the ellipsoid. Tmp1 should never be zero. */ sin_lat = sin (lat); cos_lat = cos (lat); tmp1 = cs_One - (sinus->e_sq * sin_lat * sin_lat); xy [XX] = sinus->ka * del_lng * cos_lat / sqrt (tmp1); xy [YY] = CSmmFcal (&sinus->mmcofF,lat,sin_lat,cos_lat); } /* Apply the false easting and northing. Notice that the X is now relative to the zone origin, thus we must use the zone False Easting. */ if (sinus->quad == 0) { xy [XX] += x_off; xy [YY] += sinus->y_off; } else { CS_quadF (xy,xy [XX],xy [YY],x_off,sinus->y_off,sinus->quad); } /* That's it. */ return (rtn_val); }
double EXP_LVL1 CS_llazdd ( double e_rad, double e_sq, Const double ll_from [2], Const double ll_to [2], double *dist) { extern double cs_Pi; /* 3.14159.... */ extern double cs_Mpi; /* -3.14159.... */ extern double cs_Pi_o_2; /* 1.570796.... */ extern double cs_Degree; /* 1.0 / 57.29577... */ extern double cs_Radian; /* 57.29577... */ extern double cs_Zero; /* 0.0 */ extern double cs_Half; /* 0.5 */ extern double cs_One; /* 1.0 */ extern double cs_Two; /* 2.0 */ extern double cs_AnglTest; /* 0.001 arc seconds, in radians */ extern double cs_NPTest; /* 0.001 seconds of arc short of the north pole, in radians. */ extern double cs_SPTest; /* 0.001 seconds of arc short of the south pole, in radians. */ double az; double mm, mp; double del_lng; double del_lat; double cc; /* Angular distance between the two points on a sphere, in radians of course. */ double sin_co2; /* sine of one half of the angular distance, i.e. c over 2 */ double tmp1; double tmp2; double from [2]; double to [2]; struct cs_MmcofF_ mm_cof; /* Convert the degrees we have been provided with to radians for our computations. */ from [LNG] = CS_adj2pi (ll_from [LNG] * cs_Degree); from [LAT] = CS_adj1pi (ll_from [LAT] * cs_Degree); to [LNG] = CS_adj2pi (ll_to [LNG] * cs_Degree); to [LAT] = CS_adj1pi (ll_to [LAT] * cs_Degree); del_lng = CS_adj2pi (to [LNG] - from [LNG]); del_lat = CS_adj1pi (to [LAT] - from [LAT]); /* Deal with the zero length arc. */ if (fabs (del_lng) <= cs_AnglTest && fabs (del_lat) <= cs_AnglTest) { *dist = cs_Zero; return (cs_Zero); } /* Deal with the antipodal case. Another situation which can cause floating point exceptions. */ if (fabs (del_lng) > (cs_Pi - cs_AnglTest)) { /* Here only when it makes sense to check the latitude for the anti-posal case. This is not trivial. */ tmp1 = CS_adj1pi (from [LAT]); tmp2 = CS_adj1pi (to [LAT]); if (fabs (tmp1 + tmp2) < cs_AnglTest) { /* Antipodal. The distance is tricky. */ if (e_sq == 0.0) { /* Sphere. */ *dist = cs_Pi * e_rad; } else { /* Ellipsoid. */ CSmmFsu (&mm_cof,e_rad,e_sq); *dist = cs_Two * CSmmFcal (&mm_cof,cs_Pi_o_2, cs_One, cs_Zero); } /* The shortest distance is over a pole. We could choose either pole. By always using the north pole, the returned results are the same for any antipodal points. */ return (cs_Zero); } } /* Now, we deal with the case where one of the two points is at a pole. This is a bit easier now that we know that only one points can be at a pole. */ if (fabs (from [LAT]) > cs_NPTest || fabs (to [LAT]) < cs_SPTest) { /* One of the two points is a pole. Compute the distance to the pole from the equator for this ellipsoid. */ if (e_sq == 0.0) { mp = cs_Pi_o_2 * e_rad; } else { CSmmFsu (&mm_cof,e_rad,e_sq); mp = CSmmFcal (&mm_cof,cs_Pi_o_2,cs_One,cs_Zero); } if (fabs (to [LAT]) > cs_NPTest) { /* The TO point is a pole. The forward azimuth is zero if its the north pole, -180 if its the south pole. */ if (to [LAT] > 0.0) az = cs_Zero; else az = cs_Mpi; /* Compute the distance of the from point from the equator. */ if (e_sq == 0.0) { mm = cs_Pi_o_2 * e_rad * sin (from [LAT]); } else { mm = CSmmFcal (&mm_cof,from [LAT], sin (from [LAT]), cos (from [LAT])); /*lint !e645 */ } } else { /* The FROM point is a pole. The azimuth is -180 if its the north pole, zero if it is the south pole. */ if (from [LAT] > 0.0) az = cs_Mpi; else az = cs_Zero; /* Distance of the TO point from the equator. */ if (e_sq == 0.0) { mm = cs_Pi_o_2 * e_rad * sin (to [LAT]); } else { mm = CSmmFcal (&mm_cof,to [LAT], sin (to [LAT]), cos (to [LAT])); } } /* Compute the distance. */ if ((to [LAT] * from [LAT]) > 0.0) *dist = mp - fabs (mm); else *dist = mp + fabs (mm); return (az * cs_Radian); } /* Now, we calculate the angular length of the arc. If the arc length exceeds a specific value, we use the geodetic function, CSllazdd to compute the necessary information. Otherwise, we use the spherical trigonometry given here. */ tmp1 = sin (del_lng * cs_Half); tmp1 = cos (from [LAT]) * cos (to [LAT]) * tmp1 * tmp1; tmp2 = sin (del_lat * cs_Half); tmp2 *= tmp2; sin_co2 = sqrt (tmp2 + tmp1); if (e_sq != 0.0) { return (CSllazdd (e_rad,e_sq,from,to,dist)); } cc = cs_Two * asin (sin_co2); *dist = cc * e_rad; az = asin (sin (del_lng) * cos (to [LAT]) / sin (cc)); return (az * cs_Radian); }
int EXP_LVL1 CS_azddll (double e_rad, double e_sq, Const double ll_from [2], double az, double dist, double ll_to [2]) { extern double cs_Pi; /* 3.14159.... */ extern double cs_Degree; /* 1.0 / 57.29577... */ extern double cs_Radian; /* 57.29577... */ extern double cs_Zero; /* 0.0 */ extern double cs_Fourth; /* 0.25*/ extern double cs_One; /* 1.0 */ extern double cs_Two; /* 2.0 */ extern double cs_Three; /* 3.0 */ extern double cs_Four; /* 4.0 */ int status; int itr_cnt; double rr, rr2; double sf, cf; double sy, cy; double tu, cu, su; double sa, cz; double c2a; double xx, yy; double cc, dd, ee; double tmp; double faz, baz; double flat; double from [2]; status = 0; /* Convert to radians. */ from [LNG] = CS_adj2pi (ll_from [LNG] * cs_Degree); from [LAT] = CS_adj1pi (ll_from [LAT] * cs_Degree); faz = az * cs_Degree; /* CS-MAP is driven by eccentricity, this guy works off flattening */ flat = cs_One - sqrt (cs_One - e_sq); /* The following is a conversion from FORTRAN of the Subroutine named DIRCT1 in the FOWARD program. I really have no idea as to what is going on here, ither then there is what appears to be a Newton Rhapson iteration. We have followed the variable nomenclature used in the FORWARD program with two exceptions: 1) we have used lower case, 2) we have doubled up all single letter variable names. */ rr = cs_One - flat; rr2 = rr * rr; tu = rr * sin (from [LAT]) / cos (from [LAT]); sf = sin (faz); cf = cos (faz); if (fabs (tu) >= 1.0E-13 || fabs (cf) >= 1.0E-13) { baz = cs_Two * atan2 (tu,cf); } else { baz = cs_Zero; } cu = cs_One / sqrt (cs_One + tu * tu); su = tu * cu; sa = cu * sf; c2a = cs_One - sa * sa; tmp = c2a * (cs_One / rr2 - cs_One) + cs_One; xx = sqrt (tmp) + cs_One; xx = (xx - cs_Two) / xx; cc = cs_One - xx; cc = (cs_Fourth * xx * xx + cs_One) / cc; dd = (0.375 * xx * xx - cs_One) * xx; tu = dist / rr / e_rad / cc; yy = tu; itr_cnt = 20; do { sy = sin (yy); cy = cos (yy); cz = cos (baz + yy); ee = cz * cz * cs_Two - cs_One; cc = yy; xx = ee * cy; yy = ee + ee - cs_One; tmp = cs_Four * sy * sy - cs_Three; tmp *= yy * cz * dd * (1.0 / 6.0); tmp += xx; tmp *= dd * cs_Fourth; tmp -= cz; tmp *= sy * dd; yy = tmp + tu; } while (fabs (yy - cc) > 0.5E-13 && itr_cnt-- > 0); if (itr_cnt <= 0) status = -1; baz = (cu * cy * cf) - (su * sy); cc = rr * sqrt ((sa * sa) + (baz * baz)); dd = (su * cy) + (cu * sy * cf); ll_to [LAT] = atan2 (dd,cc); cc = (cu * cy) - (su * sy * cf); xx = atan2 (sy * sf,cc); tmp = (cs_Four - cs_Three * c2a) * flat + cs_Four; cc = tmp * c2a * flat / 16.0; tmp = (ee * cy * cc) + cz; tmp *= sy * cc; dd = (tmp + yy) * sa; tmp = (cs_One - cc) * dd * flat; ll_to [LNG] = from [LNG] + xx - tmp; baz = atan2 (sa,baz) + cs_Pi; /* Convert back to degrees. */ ll_to [LNG] = CS_adj2pi (ll_to [LNG]) * cs_Radian; ll_to [LAT] *= cs_Radian; return (status); }
int EXP_LVL9 CSorthoF (Const struct cs_Ortho_ *ortho,double xy [2],Const double ll [2]) { extern double cs_Degree; /* 1.0 / RADIAN */ extern double cs_Pi; /* 3.14159... */ extern double cs_Mpi; /* -3.14159... */ extern double cs_Two_pi; /* 2 Pi */ extern double cs_Pi_o_2; /* Pi over 2 */ extern double cs_NPTest; /* 0.001 seconds of arc short of the north pole, in radians. */ int rtn_val; double lng; /* The given longitude, after conversion to radians. */ double lat; /* The given latitude after conversion to radians. */ double cos_c; /* cosine of the angular distance from the origin to the point. */ double del_lng; double sin_del_lng; double cos_del_lng; double sin_lat; double cos_lat; double tmp; rtn_val = cs_CNVRT_NRML; /* For this projection, we only support the spherical form, therefore there is only one set of equations. These are pretty simple. */ lng = cs_Degree * ll [0]; lat = cs_Degree * ll [1]; if (fabs (lat) > cs_NPTest) { rtn_val = cs_CNVRT_INDF; if (fabs (lat) > cs_Pi_o_2) { rtn_val = cs_CNVRT_RNG; lat = CS_adj1pi (lat); } } del_lng = lng - ortho->org_lng; if (del_lng > cs_Pi && ortho->org_lng < 0.0) del_lng -= cs_Two_pi; else if (del_lng < cs_Mpi && ortho->org_lng > 0.0) del_lng += cs_Two_pi; if (fabs (del_lng) > cs_Pi) { rtn_val = cs_CNVRT_RNG; del_lng = CS_adj2pi (del_lng); } sin_del_lng = sin (del_lng); cos_del_lng = cos (del_lng); sin_lat = sin (lat); cos_lat = cos (lat); /* Is this point in range? */ cos_c = (ortho->sin_org_lat * sin_lat) + (ortho->cos_org_lat * cos_lat * cos_del_lng); if (cos_c <= 0.0) { rtn_val = cs_CNVRT_RNG; } /* Certain computation efficiencies could be obtained by handling the various aspects separately. However, these efficiences amount to two multiplies at most. Therefore, we would not save very much after we decide which aspect to compute. No divides, no atan2's, no square roots, no logs. The programmer's paradise. */ xy [XX] = ortho->ka * cos_lat * sin_del_lng; tmp = (ortho->cos_org_lat * sin_lat) - (ortho->sin_org_lat * cos_lat * cos_del_lng); xy [YY] = ortho->ka * tmp; if (ortho->quad == 0) { xy [XX] += ortho->x_off; xy [YY] += ortho->y_off; } else { CS_quadF (xy,xy [XX],xy [YY],ortho->x_off,ortho->y_off, ortho->quad); } return (rtn_val); }
/* We'll have need of the following function in several places. It is, basically, the forward function, but its results are also required for the grid scale factor and the convergence angle. Thus, to eliminate duplicate code, we suffer this little hit on performance. */ int EXP_LVL9 CSkrovkB2 (Const struct cs_Krovk_ *krovk,Const double lnglat [2], double llS [2], double llO [2], double *theta, double *rho) { /* read llS as latlng on the gaussian surface (i.e. conformal sphere) and llO and latlng on the oblique sphere. */ extern double cs_Degree; /* 1.0 / RADIAN */ extern double cs_Pi_o_4; /* Pi over 4 */ extern double cs_Half; /* 0.5 */ extern double cs_One; /* 1.0 */ extern double cs_Mone; /* -1.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. */ int rtn_val; double lngE; /* The given longitude, after conversion to radians. */ double latE; /* The given latitude after conversion to radians. */ double sinLatS, cosLatS; double sinLatO, cosLatO; double sinLngO; double tmp1; rtn_val = cs_CNVRT_NRML; lngE = (lnglat [LNG] * cs_Degree) - krovk->orgLng; latE = lnglat [LAT] * cs_Degree; /* Assure that eLat is rational. This we need to assure we don't take the log of zero or a negative number. We just truncate to the appropriate pole. */ if (fabs (latE) > cs_NPTest) { rtn_val = cs_CNVRT_RNG; latE = CS_adj1pi (latE); if (latE > cs_NPTest) latE = cs_NPTest; else if (latE < cs_SPTest) latE = cs_SPTest; } /* We don't really have a problem with longitude, as we only take sin and cos of the longitude. */ /* Map the resulting lat/long to the gaussian surface. */ if (krovk->ecent == 0.0) { llS [LNG] = lngE; llS [LAT] = latE; } else { llS [LNG] = krovk->alpha * lngE; llS [LAT] = CSkrovkB1 (krovk,latE); } /* We're now on the conformal sphere. */ sinLatS = sin (llS [LAT]); cosLatS = cos (llS [LAT]); /* Convert the spherical geographic lat/long to the equivalent lat/long on the oblique sphere. */ sinLatO = krovk->sinLatQ * sinLatS + krovk->cosLatQ * cosLatS * cos (krovk->lngQ - llS [LNG]); cosLatO = sqrt (cs_One - sinLatO * sinLatO); llO [LAT] = atan (sinLatO / cosLatO); sinLngO = (cosLatS / cosLatO) * sin (krovk->lngQ - llS [LNG]); /* The asin should be OK here, but just to be sure. */ if (sinLngO > cs_One) sinLngO = cs_One; else if (sinLngO < cs_Mone) sinLngO = cs_Mone; llO [LNG] = asin (sinLngO); /* From the Czech document test case: lngO =? 21.8191895277777; latO =? 77.7249551388888 */ /* Convert to polar coordinates. */ *theta = krovk->nn * llO [LNG]; tmp1 = krovk->tanTermF / tan (cs_Pi_o_4 + llO [LAT] * cs_Half); *rho = krovk->rho0 * pow (tmp1,krovk->nn); return (rtn_val); }
int EXP_LVL9 CSmrcatF (Const struct cs_Mrcat_ *mrcat,double xy [2],Const double ll [2]) { extern double cs_One; /* 1.0 */ extern double cs_Degree; /* 1.0 / 57.29577... */ extern double cs_Two_pi; /* 2 pi */ extern double cs_Pi; /* Pi, i.e. 3.14159 */ 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. */ int rtn_val; double lng; double lat; double del_lng; double sin_lat; double esin_lat; double tmp1; double tmp2; rtn_val = cs_CNVRT_NRML; lng = ll [0] * cs_Degree; lat = ll [1] * cs_Degree; /* Deal with X, it's easy. */ lng = cs_Degree * ll [LNG]; del_lng = lng - mrcat->cent_lng; if (del_lng > cs_Pi) del_lng -= cs_Two_pi; else if (del_lng < -cs_Pi) del_lng += cs_Two_pi; if (fabs (del_lng) >= cs_Pi) { rtn_val = cs_CNVRT_RNG; del_lng = CS_adj2pi (del_lng); } xy [XX] = mrcat->Rfact * del_lng; /* Bogus values of latitude can cause big problems. */ if (fabs (lat) > cs_NPTest) { rtn_val = cs_CNVRT_RNG; lat = CS_adj1pi (lat); if (lat > cs_NPTest) { lat = cs_NPTest; } if (lat < cs_SPTest) { lat = cs_SPTest; } } /* We should be OK now. */ sin_lat = sin (lat); tmp1 = (cs_One + sin_lat) / (cs_One - sin_lat); if (mrcat->ecent == 0.0) { /* Here for a sphere. */ xy [YY] = mrcat->Rfact_2 * log (tmp1); } else { /* Here for an ellipsoid. */ esin_lat = mrcat->ecent * sin_lat; tmp2 = (cs_One - esin_lat) / (cs_One + esin_lat); tmp2 = tmp1 * pow (tmp2,mrcat->ecent); xy [YY] = mrcat->Rfact_2 * log (tmp2); } if (mrcat->quad == 0) { xy [XX] += mrcat->x_off; xy [YY] += mrcat->y_off; } else { CS_quadF (xy,xy [XX],xy [YY],mrcat->x_off,mrcat->y_off,mrcat->quad); } return (rtn_val); }
int EXP_LVL9 CSpstroF (Const struct cs_Pstro_ *pstro,double xy [2],Const double ll [2]) { extern char csErrnam [MAXPATH]; extern double cs_Degree; /* 1.0 / RADIAN */ extern double cs_Half; /* 0.5 */ extern double cs_One; /* 1.0 */ extern double cs_Pi; /* 3.14159... */ extern double cs_Pi_o_2; /* PI over 2 */ extern double cs_Pi_o_4; /* PI over 4 */ extern double cs_NPTest; /* 0.001 seconds of arc short of the north pole, in radians. */ extern double cs_Huge; /* Huge value, but not too huge. */ int rtn_val; double lng; /* The given longitude, after conversion to radians. */ double lat; /* The given latitude after conversion to radians. */ double x; double y; double del_lng; double sin_del_lng; double cos_del_lng; double sin_lat; double t; double rho; double tmp1; double tmp2; double tmp3; rtn_val = cs_CNVRT_NRML; /* There are two formulae, one for the sphere and one for the ellipsoid. If the ecentricity of the dataum in use is 0.0 exactly, we shall use the spherical formulae. */ lat = cs_Degree * ll [LAT]; if (fabs (lat) > cs_NPTest) { rtn_val = cs_CNVRT_INDF; if (fabs (lat) > cs_Pi_o_2) { rtn_val = cs_CNVRT_RNG; lat = CS_adj1pi (lat); } } lng = cs_Degree * ll [LNG]; /* We first adjust the following so that we can use much of the code below for the southern polar aspect without duplicating it with minor sign changes. */ if (pstro->aspect == cs_STERO_SOUTH && pstro->ecent != 0.0) { lat = -lat; del_lng = pstro->org_lng - lng; } else { del_lng = lng - pstro->org_lng; } if (fabs (del_lng) > cs_Pi) del_lng = CS_adj2pi (del_lng); sin_del_lng = sin (del_lng); cos_del_lng = cos (del_lng); sin_lat = sin (lat); /* See if the datum is a sphere or an ellipsoid. */ if (pstro->ecent == 0.0) { /* Here for the sphere. */ switch (pstro->aspect) { case cs_STERO_NORTH: tmp1 = cs_Pi_o_4 - (lat * cs_Half); tmp1 = pstro->two_ka * tan (tmp1); x = tmp1 * sin_del_lng; y = -tmp1 * cos_del_lng; break; case cs_STERO_SOUTH: tmp1 = cs_Pi_o_4 + (lat * cs_Half); tmp1 = pstro->two_ka * tan (tmp1); x = tmp1 * sin_del_lng; y = tmp1 * cos_del_lng; break; default: x = y = -cs_Huge; CS_stncp (csErrnam,"CS_pstro:1",MAXPATH); CS_erpt (cs_ISER); rtn_val = -1; break; } /*lint !e744 */ } else { /* Here for an ellipsoid model of the earth. */ tmp1 = pstro->ecent * sin_lat; tmp2 = (cs_One - tmp1) / (cs_One + tmp1); tmp2 = pow (tmp2,pstro->e_o_2); tmp3 = lat * cs_Half; t = tan (cs_Pi_o_4 - tmp3) / tmp2; switch (pstro->aspect) { case cs_STERO_NORTH: rho = pstro->two_ka * t / pstro->e_term; x = rho * sin_del_lng; y = -rho * cos_del_lng; break; case cs_STERO_SOUTH: rho = pstro->two_ka * t / pstro->e_term; x = -rho * sin_del_lng; y = rho * cos_del_lng; break; default: x = y = -cs_Huge; CS_stncp (csErrnam,"CS_pstro:1",MAXPATH); CS_erpt (cs_ISER); rtn_val = -1; break; } /*lint !e744 */ } /* Adjust for the selected quadrant, and, finally, add false easting and false northing. */ xy [XX] = x; /*lint !e644 */ xy [YY] = y; /*lint !e644 */ if (pstro->quad == 0) { xy [XX] = x + pstro->x_off; xy [YY] = y + pstro->y_off; } else { CS_quadF (xy,x,y,pstro->x_off,pstro->y_off,pstro->quad); } return (rtn_val); }
int EXP_LVL9 CStacylI (Const struct cs_Tacyl_ *tacyl,double ll [2],Const double xy [2]) { extern double cs_Zero; extern double cs_One; /* 1.0 */ extern double cs_Mone; /* -1.0 */ extern double cs_Radian; /* 57.29577... */ extern double cs_Pi; /* 3.14159... */ extern double cs_Pi_o_2; /* PI / 2.0 */ extern double cs_AnglTest; /* 0.001 arc seconds, in radians. */ int rtn_val; double xx; double yy; double del_lng; double lat; double qq; double Mc; double DD; double beta; double sin_DD; double cos_DD; double latc; double sin_lat; double sin_latc; double cos_latc; double esin_latc; double betac; double sin_betac; double cos_betac; double betap; double cos_betap; double tmp1; double tmp2; double tmp3; double tmp4; rtn_val = cs_CNVRT_NRML; /* Remove the false origin. */ if (tacyl->quad == 0) { xx = xy [XX] - tacyl->x_off; yy = xy [YY] - tacyl->y_off; } else { CS_quadI (&xx,&yy,xy,tacyl->x_off,tacyl->y_off,tacyl->quad); } lat = cs_Zero; del_lng = cs_Zero; if (tacyl->ecent == 0.0) { /* Here for the sphere. There are two special cases to deal with. If X is out of range, we will end up taking the square root of a negative number. In this case, assuming we are not at a pole (cos_DD != 0.0), we set the longitude to be equal to org_lng +- _PI/2 taking the sign of X. If X is in range, but we are at either pole, there is no longitude and we can pick any value, like org_lng. */ DD = yy / tacyl->kah0 + tacyl->org_lat; sin_DD = sin (DD); cos_DD = cos (DD); if (fabs (cos_DD) < cs_AnglTest) { /* Opps!!! We're at a pole. Can't divide by cos_DD. Pick the right pole and leave longitude ar org_lng. */ rtn_val = cs_CNVRT_INDF; if (sin_DD > 0.0) lat = cs_Pi_o_2; else lat = cs_Pi_o_2; } else { /* Not at either pole. Make sure we don't take the square root of a negative number. */ tmp1 = xx * tacyl->h0_o_ka; tmp2 = cs_One - tmp1 * tmp1; if (tmp2 < cs_AnglTest) { if (tmp2 < 0.0) rtn_val = cs_CNVRT_RNG; tmp2 = cs_Zero; } else { tmp2 = sqrt (tmp2); } sin_lat = tmp2 * sin_DD; if (fabs (sin_lat) >= cs_One) { sin_lat = (sin_lat >= 0.0) ? cs_One : cs_Mone; } lat = asin (sin_lat); tmp2 *= cos_DD; /* tmp2 may be zero here, but tmp1 and tmp2 cannot both be zero. Therefore, atan2 should work OK in all cases. */ del_lng = atan2 (tmp1,tmp2); } } else { /* Here for the ellipsoid. The standard equations are indeterminate at the poles. At the current time, the handling of |X| values greater than R/h0 produces different results between the spherical and ellipsoid cases. X isn't supposed to get bigger than this, so it might not make any difference to anyone. */ Mc = tacyl->M0 + yy / tacyl->h0; latc = CSmmIcal (&tacyl->mmcofI,Mc); sin_latc = sin (latc); cos_latc = cos (latc); if (fabs (cos_latc) > cs_AnglTest) { /* Not at a pole. */ esin_latc = tacyl->ecent * sin_latc; tmp1 = (cs_One - esin_latc) / (cs_One + esin_latc); tmp1 = tacyl->one_o_2e * log (tmp1); tmp2 = cs_One - esin_latc * esin_latc; qq = tacyl->one_m_esq * (sin_latc / tmp2 - tmp1); /* Seems a bit inefficient, but we need the normalizing affect of the asin function here. sin_betac should never be more than one, but noise in the low order bits during the calculations require that we check to prevent asin from generating a floating point exception. */ sin_betac = qq / tacyl->qp; if (fabs (sin_betac) >= cs_One) { sin_betac = (sin_betac >= 0.0) ? cs_One : cs_Mone; } betac = asin (sin_betac); sin_betac = sin (betac); cos_betac = cos (betac); /* Note what the following does when |X| is greater than R/h0: Betap, and hence beta, simply wraps back on themselves to computable values. I.e. an X value of R/h0+p is treated the same as the value R/h0-p. */ tmp3 = cos_betac * sqrt (tmp2) / cos_latc; tmp4 = xx * tacyl->h0_o_ka * tmp3; if (fabs (tmp4) > cs_One) { rtn_val = cs_CNVRT_RNG; tmp4 = (tmp4 >= 0.0) ? cs_One : cs_Mone; } betap = -asin (tmp4); cos_betap = cos (betap); beta = asin (cos_betap * sin_betac); /* We don't get here if we are at a pole. Therefore, tan (betap) should be OK, and cos_betac should never be zero. Since cos_betac is always positive, we can use atan just as well as atan2. */ del_lng = -atan (tan (betap) / cos_betac); lat = CSbtIcalPrec (&tacyl->btcofI,beta); } else { /* At a pole, any longitude will do. We'll use the origin longitude by leaving lng set to zero. */ rtn_val = cs_CNVRT_INDF; if (latc > 0.0) lat = cs_Pi_o_2; else lat = cs_Pi_o_2; } } if (fabs (del_lng) > cs_Pi) { del_lng = CS_adj2pi (del_lng); rtn_val = cs_CNVRT_RNG; } ll [LNG] = (del_lng + tacyl->org_lng) * cs_Radian; if (fabs (lat) > cs_Pi_o_2) rtn_val = cs_CNVRT_RNG; ll [LAT] = CS_adj1pi (lat) * cs_Radian; return (rtn_val); }
int EXP_LVL9 CStacylF (Const struct cs_Tacyl_ *tacyl,double xy [2],Const double ll [2]) { extern double cs_Zero; /* 0.0 */ extern double cs_One; /* 1.0 */ extern double cs_Mone; /* -1.0 */ extern double cs_Degree; /* 1.0 / 57.29577... */ extern double cs_Pi; /* 3.14159... */ extern double cs_Pi_o_2; /* PI/2 */ extern double cs_AnglTest; /* 0.001 arc seconds, in radians. */ extern double cs_NPTest; /* 0.001 seconds of arc short of the north pole, in radians. */ int rtn_val; double lng; double lat; double del_lng; double sin_lat; double esin_lat; double sin_beta; double beta, beta_c; double lat_c, sin_lat_c, cos_lat_c; double sin_del_lng; double cos_del_lng; double qq; double Mc; double tmp1; double tmp2; rtn_val = cs_CNVRT_NRML; /* The following is required by both the sperical and ellipsoidal forms. */ lng = ll [LNG] * cs_Degree; del_lng = lng - tacyl->org_lng; /* The following statement is used to deal with the 180 degree crack. */ if (fabs (del_lng) > cs_Pi) del_lng = CS_adj2pi (del_lng); sin_del_lng = sin (del_lng); cos_del_lng = cos (del_lng); lat = ll [LAT] * cs_Degree; if (fabs (lat) > cs_NPTest) { rtn_val = cs_CNVRT_INDF; if (fabs (lat) > cs_Pi_o_2) { rtn_val = cs_CNVRT_RNG; lat = CS_adj1pi (lat); } } if (tacyl->ecent == 0.0) { /* Here for the sphere. */ xy [XX] = tacyl->ka_o_h0 * cos (lat) * sin_del_lng; if (fabs (cos_del_lng) > cs_AnglTest) { tmp1 = atan (tan (lat) / cos_del_lng); } else { /* We are 90 degrees or so away from the central meridian. There is a singularity at del_lng == 90 and lat == 0.0 However, there is a very rational result for this singularity point. */ rtn_val = cs_CNVRT_RNG; if (lat > cs_AnglTest) tmp1 = cs_Pi_o_2; else if (lat < cs_AnglTest) tmp1 = -cs_Pi_o_2; else tmp1 = cs_Zero; } xy [YY] = tacyl->kah0 * (tmp1 - tacyl->org_lat); } else { /* Here for the ellipsoid. If we are at 90 degrees of longitude from the central meridian, the normal equations are indeterminate. However, the result is well defined. */ sin_lat = sin (lat); esin_lat = tacyl->ecent * sin_lat; tmp1 = (cs_One - esin_lat) / (cs_One + esin_lat); tmp1 = tacyl->one_o_2e * log (tmp1); tmp2 = sin_lat / (cs_One - esin_lat * esin_lat); qq = tacyl->one_m_esq * (tmp2 - tmp1); sin_beta = qq / tacyl->qp; if (fabs (sin_beta) >= cs_One) { sin_beta = (sin_beta >= 0.0) ? cs_One : cs_Mone; } beta = asin (sin_beta); if (fabs (cos_del_lng) > cs_AnglTest) { beta_c = atan (tan (beta) / cos_del_lng); } else { rtn_val = cs_CNVRT_RNG; if (beta > cs_AnglTest) beta_c = cs_Pi_o_2; else if (beta < cs_AnglTest) beta_c = -cs_Pi_o_2; else beta_c = cs_Zero; } lat_c = CSbtIcalPrec (&tacyl->btcofI,beta_c); sin_lat_c = sin (lat_c); cos_lat_c = cos (lat_c); Mc = CSmmFcal (&tacyl->mmcofF,lat_c,sin_lat_c,cos_lat_c); xy [YY] = tacyl->h0 * (Mc - tacyl->M0); if (fabs (cos_del_lng) > cs_AnglTest) { tmp1 = cs_One - tacyl->e_sq * sin_lat_c * sin_lat_c; tmp1 = cos (beta_c) * sqrt (tmp1); tmp2 = cos (beta) * cos_lat_c * sin_del_lng; xy [XX] = tacyl->ka_o_h0 * (tmp2 / tmp1); } else { if (sin_del_lng >= 0.0) xy [XX] = tacyl->ka_o_h0; else xy [XX] = -tacyl->ka_o_h0; } } if (tacyl->quad == 0) { xy [XX] += tacyl->x_off; xy [YY] += tacyl->y_off; } else { CS_quadF (xy,xy [XX],xy [YY],tacyl->x_off,tacyl->y_off,tacyl->quad); } return (rtn_val); }
int EXP_LVL9 CScsiniI (Const struct cs_Csini_ *csini,double ll [2],Const double xy [2]) { extern double cs_Radian; /* 57.29577... */ extern double cs_Pi; /* 3.14159... */ extern double cs_Pi_o_2; /* pi over 2 */ extern double cs_Zero; /* 0.0 */ extern double cs_Third; /* 0.3333... */ extern double cs_Half; /* 0.5 */ extern double cs_One; /* 1.0 */ extern double cs_Three; /* 3.0 */ extern double cs_AnglTest; /* 0.001 arc seconds, in radians. */ extern double cs_Huge; /* an approximation of infinity, not so large that it can't be used in normal calculations without problems. */ int rtn_val; double x; double y; double lat; double del_lng; double D; double D_2; double D_3; double D_4; double D_5; double N1; double R1; double T1; double phi1; double sin_phi1; double cos_phi1; double tan_phi1; double tmp1; double tmp2; rtn_val = cs_CNVRT_NRML; if (csini->quad == 0) { x = xy [XX] - csini->x_off; y = xy [YY] - csini->y_off; } else { CS_quadI (&x,&y,xy,csini->x_off,csini->y_off,csini->quad); } if (fabs (x) > csini->max_xx) { rtn_val = cs_CNVRT_RNG; x = (x >= 0.0) ? csini->max_xx : -csini->max_xx; } if (y < csini->min_yy || y > csini->max_yy) { rtn_val = cs_CNVRT_RNG; } if (csini->ecent == 0.0) { /* Here for a spherical datum. Cos D is zero at the poles. Tan (tmp1) is also zero when x is zero. */ D = (y / csini->ka) + csini->org_lat; tmp1 = x / csini->ka; tmp2 = sin (D) * cos (tmp1); lat = asin (tmp2); if (fabs (tmp1) > cs_AnglTest) { /* This blows up when both arguments are zero, which will happen only at the poles. At the poles, all values of longitudes are equivalent. */ del_lng = atan2 (tan (tmp1),cos (D)); } else { if (rtn_val == cs_CNVRT_NRML) { rtn_val = cs_CNVRT_INDF; } del_lng = cs_Zero; } } else { /* Here for an ellipsoid. */ phi1 = CSmmIcal (&csini->mmcofI,csini->M0 + y); sin_phi1 = sin (phi1); cos_phi1 = cos (phi1); if (fabs (cos_phi1) > cs_AnglTest) { /* Blows up at the poles, but not really out the useful range of this projection. */ tan_phi1 = sin_phi1/cos_phi1; } else { tan_phi1 = cs_Huge; } T1 = tan_phi1 * tan_phi1; tmp1 = cs_One - (csini->e_sq * (sin_phi1 * sin_phi1)); tmp2 = sqrt (tmp1); N1 = csini->ka / tmp2; R1 = csini->R_term / (tmp1 * tmp2); D = x / N1; D_5 = D * (D_4 = D * (D_3 = D * (D_2 = D * D))); /* Compute the latitude. */ tmp1 = (cs_Half * D_2); tmp1 -= (cs_One + cs_Three * T1) * D_4 * (1.0 / 24.0); tmp1 *= N1 * tan_phi1 / R1; lat = phi1 - tmp1; /* Now we can compute a longitude. */ if (fabs (cos_phi1) > cs_AnglTest) { tmp1 = D - (T1 * (cs_Third * D_3)); tmp1 += (cs_One + cs_Three * T1) * T1 * D_5 * (1.0 / 15.0); del_lng = tmp1 / cos_phi1; /* Blows up at the poles. */ } else { /* Any longitude, like cent_lng, will do just fine. */ if (rtn_val == cs_CNVRT_NRML) { rtn_val = cs_CNVRT_INDF; } del_lng = cs_Zero; } } if (fabs (del_lng) > cs_Pi) { del_lng = CS_adj2pi (del_lng); rtn_val = cs_CNVRT_RNG; } if (fabs (lat) > cs_Pi_o_2) { lat = CS_adj1pi (lat); rtn_val = cs_CNVRT_RNG; } ll [LNG] = (del_lng + csini->cent_lng) * cs_Radian; ll [LAT] = lat * cs_Radian; return (rtn_val); }
int EXP_LVL9 CScsiniF (Const struct cs_Csini_ *csini,double xy [2],Const double ll [2]) { extern double cs_Degree; /* 1.0 / 57.29577... */ extern double cs_Pi; /* 3.14159... */ extern double cs_Half; /* 0.5 */ extern double cs_One; /* 1.0 */ extern double cs_Five; /* 5.0 */ extern double cs_Six; /* 6.0 */ extern double cs_Eight; /* 8.0 */ extern double cs_Pi_o_2; /* Pi over 2 */ extern double cs_NPTest; /* 0.001 seconds of arc short of the north pole, in radians. */ extern double cs_EETest; /* 0.001 arc seconds short of 90 degrees, in readians. */ extern double cs_WETest; /* 0.001 arc seconds short of -90 degrees, in readians. */ int rtn_val; double lng; double lat; double del_lng; double A; double A_2; double A_3; double A_4; double A_5; double B; double C; double M; double N; double T; double sin_lat; double cos_lat; double tan_lat; double tmp1; double tmp2; rtn_val = cs_CNVRT_NRML; lng = ll [0] * cs_Degree; lat = ll [1] * cs_Degree; if (fabs (lat) > cs_NPTest) { rtn_val = cs_CNVRT_INDF; if (fabs (lat) > cs_Pi_o_2) { rtn_val = cs_CNVRT_RNG; lat = CS_adj1pi (lat); } } del_lng = lng - csini->cent_lng; /* The following statement is required to handle the case where the central meridian is -179, and the provided longitude is +179, for example. */ if (fabs (del_lng) > cs_Pi) del_lng = CS_adj2pi (del_lng); /* Del_lng of 90 degrees is a problem for this projection. */ if (fabs (del_lng) > cs_EETest) { rtn_val = cs_CNVRT_RNG; del_lng = (del_lng >= 0.0) ? cs_EETest : cs_WETest; } cos_lat = cos (lat); tan_lat = tan (lat); if (csini->ecent == 0.0) { /* Here for a sphere. */ B = cos_lat * sin (del_lng); xy [XX] = csini->ka * asin (B); /* We've dealt with a del_lng of 90 degree above. */ tmp1 = tan_lat / cos (del_lng); xy [YY] = csini->ka * (atan (tmp1) - csini->org_lat); } else { /* Here for an ellipsoid. */ A = cos_lat * del_lng; A_2 = A * A; A_3 = A_2 * A; A_4 = A_2 * A_2; A_5 = A_3 * A_2; C = csini->C_term * cos_lat * cos_lat; sin_lat = sin (lat); tmp1 = csini->e_sq * sin_lat * sin_lat; N = csini->ka / sqrt (cs_One - tmp1); T = tan_lat * tan_lat; M = CSmmFcal (&csini->mmcofF,lat,sin_lat,cos_lat); /* Now for the x value. */ tmp1 = A - (T * A_3 * (1.0 / 6.0)); tmp2 = cs_Eight - T + cs_Eight * C; tmp1 = tmp1 + (tmp2 * T * A_5 * (1.0 / 120.0)); xy [XX] = N * tmp1; /* Now the y. */ tmp1 = cs_Five - T + (cs_Six * C); tmp1 = tmp1 * A_4 * (1.0 / 24.0); tmp1 += A_2 * cs_Half; xy [YY] = M - csini->M0 + (N * tan_lat * tmp1); } if (csini->quad == 0) { xy [XX] += csini->x_off; xy [YY] += csini->y_off; } else { CS_quadF (xy,xy [XX],xy [YY],csini->x_off,csini->y_off, csini->quad); } return (rtn_val); }
int EXP_LVL9 CSlmtanF (Const struct cs_Lmtan_ *lmtan,double xy [2],Const double ll [2]) { extern double cs_Degree; /* 1.0 / RADIAN */ extern double cs_Pi; /* 3.14159... */ extern double cs_Mpi; /* -3.14159... */ extern double cs_Two_pi; /* 2 PI */ extern double cs_Pi_o_2; /* PI / 2.0 */ extern double cs_Pi_o_4; /* PI / 4.0 */ extern double cs_Zero; /* 0.0 */ extern double cs_One; /* 1.0 */ extern double cs_Half; /* 0.5 */ extern double cs_NPTest; /* 0.001 arc seconds short of the north pole, in in radians. */ extern double cs_SPTest; /* 0.001 arc seconds short of the south pole, in in radians. */ int rtn_val; double lng; /* The given longitude, after conversion to radians. */ double lat; /* The given latitude after conversion to radians. */ double del_lng; double L0; double Gamma; double R; double tmp1; double tmp2; rtn_val = cs_CNVRT_NRML; lng = cs_Degree * ll [LNG]; lat = cs_Degree * ll [LAT]; /* Compute the polar angle, Gamma, also known as the convergence angle. */ del_lng = lng - lmtan->org_lng; if (del_lng > cs_Pi && lmtan->org_lng < 0.0) del_lng -= cs_Two_pi; else if (del_lng < cs_Mpi && lmtan->org_lng > 0.0) del_lng += cs_Two_pi; if (fabs (del_lng) > cs_Pi) { rtn_val = cs_CNVRT_RNG; del_lng = CS_adj2piI (del_lng); } Gamma = lmtan->sin_org_lat * del_lng; /* Now, we compute the radius of the polar arc. R will be negative (lmtan->c is negative) if the south pole is the focus pole of the coordinate system. */ if (fabs (lat) > cs_NPTest) { if ((lat > 0.0) == (lmtan->sin_org_lat > 0.0)) /*lint !e731 !e777 */ { rtn_val = cs_CNVRT_INDF; } if (fabs (lat) > cs_Pi_o_2) { rtn_val = cs_CNVRT_RNG; lat = CS_adj1pi (lat); } } if (lat > cs_NPTest) { R = (lmtan->sin_org_lat > 0.0) ? cs_Zero : lmtan->max_R; } else if (lat < cs_SPTest) { R = (lmtan->sin_org_lat < 0.0) ? cs_Zero : lmtan->max_R; } else { tmp1 = lmtan->ecent * sin (lat); tmp1 = (cs_One + tmp1) / (cs_One - tmp1); tmp1 = lmtan->e_ovr_2 * log (tmp1); tmp2 = cs_Pi_o_4 + (lat * cs_Half); /* Tmp2 can be zero (and thus tan(tmp2) can be zero) at the south pole, but we've already dealt with that. */ tmp2 = log (tan (tmp2)); L0 = tmp2 - tmp1; R = lmtan->c * exp (-lmtan->sin_org_lat * L0); } /* Convert to cartesian coordinates. Note, ys has the false northing and the radius of the origin latitude built into it by the setup function. */ xy [XX] = R * sin (Gamma); xy [YY] = lmtan->R0 - (R * cos (Gamma)); if (lmtan->quad == 0) { xy [XX] += lmtan->x_off; xy [YY] += lmtan->y_off; } else { CS_quadF (xy,xy [XX],xy [YY],lmtan->x_off,lmtan->y_off, lmtan->quad); } return (rtn_val); }