00001 /* 00002 * cartography.c ~rick/src/util 00003 * 00004 * Functions for mapping between plate, heliographic, and various map 00005 * coordinate systems, including scaling. 00006 * 00007 * Contents: 00008 * img2sphere Map from plate location to heliographic 00009 * coordinates 00010 * plane2sphere Map from map location to heliographic or 00011 * geographical coordinates 00012 * sphere2img Map from heliographic coordinates to plate 00013 * location 00014 * sphere2plane Map from heliographic/geographic coordinates 00015 * to map location 00016 * name2proj Convert name to key value of projection 00017 * proj2name Convert projection key value to name 00018 * 00019 * Responsible: Rick Bogart RBogart@solar.Stanford.EDU 00020 * 00021 * Usage: 00022 * int img2sphere (double x, double y, double ang_r, double latc, 00023 * double lonc, double pa, double *rho, double *lat, double *lon, 00024 * double *sinlat, double *coslat, double *sig, double *mu, double *chi); 00025 * int plane2sphere (double x, double y, double latc, double lonc, 00026 * double *lat, double *lon, int projection); 00027 * int sphere2img (double lat, double lon, double latc, double lonc, 00028 * double *x, double *y, double xcenter, double ycenter, 00029 * double rsun, double peff, double ecc, double chi, 00030 * int xinvrt, int yinvrt); 00031 * int sphere2plane (double lat, double lon, double latc, double lonc, 00032 * double *x, double *y, int projection); 00033 * int name2proj (char *proj_name); 00034 * char *proj2name (int projection); 00035 * 00036 * Bugs: 00037 * It is assumed that the function atan2() returns the correct value 00038 * for the quadrant; not all libraries may support this feature. 00039 * sphere2img uses a constant for the correction due to the finite 00040 * distance to the sun. 00041 * sphere2plane and plane2sphere are not true inverses for the following 00042 * projections: (Lambert) cylindrical equal area, sinusoidal equal area 00043 * (Sanson-Flamsteed), and Mercator; for these projections, sphere2plane is 00044 * implemented as the normal projection, while plane2sphere is implemented 00045 * as the oblique projection tangent at the normal to the central meridian 00046 * plane2sphere doesn't return 1 if the x coordinate would map to a point 00047 * off the surface. 00048 * 00049 * Planned updates: 00050 * Provide appropriate oblique versions for cylindrical and 00051 * pseudo-cylindrical projections in sphere2plane 00052 * 00053 * Revision history is at end of file. 00054 */ 00055 #include <math.h> 00056 #include <stdlib.h> 00057 #include "drms.h" 00058 00059 #define RECTANGULAR (0) 00060 #define CASSINI (1) 00061 #define MERCATOR (2) 00062 #define CYLEQA (3) 00063 #define SINEQA (4) 00064 #define GNOMONIC (5) 00065 #define POSTEL (6) 00066 #define STEREOGRAPHIC (7) 00067 #define ORTHOGRAPHIC (8) 00068 #define LAMBERT (9) 00069 00070 static double arc_distance (double lat, double lon, double latc, double lonc) { 00071 double cosa = sin (lat) * sin (latc) + 00072 cos (lat) * cos (latc) * cos (lon - lonc); 00073 return acos (cosa); 00074 } 00075 00076 int img2sphere (double x, double y, double ang_r, double latc, double lonc, 00077 double pa, double *rho, double *lat, double *lon, double *sinlat, 00078 double *coslat, double *sig, double *mu, double *chi) { 00079 /* 00080 * Map projected coordinates (x, y) to (lon, lat) and (rho | sig, chi) 00081 * 00082 * Arguments: 00083 * x } Plate locations, in units of the image radius, relative 00084 * y } to the image center 00085 * ang_r Apparent semi-diameter of sun (angular radius of sun at 00086 * the observer's tangent line) 00087 * latc Latitude of disc center, uncorrected for light travel time 00088 * lonc Longitude of disc center 00089 * pa Position angle of solar north on image, measured eastward 00090 * from north (sky coordinates) 00091 * Return values: 00092 * rho Angle point:sun_center:observer 00093 * lon Heliographic longitude 00094 * lat Heliographic latitude 00095 * sinlat sine of heliographic latitude 00096 * coslat cosine of heliographic latitude 00097 * sig Angle point:observer:sun_center 00098 * mu cosine of angle between the point:observer line and the 00099 * local normal 00100 * chi Position angle on image measured westward from solar 00101 * north 00102 * 00103 * All angles are in radians. 00104 * Return value is 1 if point is outside solar radius (in which case the 00105 * heliographic coordinates and mu are meaningless), 0 otherwise. 00106 * It is assumed that the image is direct; the x or y coordinates require a 00107 * sign change if the image is inverted. 00108 * 00109 */ 00110 static double ang_r0 = 0.0, sinang_r = 0.0, tanang_r = 0.0; 00111 static double latc0 = 0.0, coslatc = 1.0, sinlatc = 0.0; 00112 double cosr, sinr, sinlon, sinsig; 00113 00114 if (ang_r != ang_r0) { 00115 sinang_r = sin (ang_r); 00116 tanang_r = tan (ang_r); 00117 ang_r0 = ang_r; 00118 } 00119 if (latc != latc0) { 00120 sinlatc = sin (latc); 00121 coslatc = cos (latc); 00122 latc0 = latc; 00123 } 00124 *chi = atan2 (x, y) + pa; 00125 while (*chi > 2 * M_PI) *chi -= 2 * M_PI; 00126 while (*chi < 0.0) *chi += 2 * M_PI; 00127 /* Camera curvature correction, no small angle approximations */ 00128 *sig = atan (hypot (x, y) * tanang_r); 00129 sinsig = sin (*sig); 00130 *rho = asin (sinsig / sinang_r) - *sig; 00131 if (*sig > ang_r) return (-1); 00132 *mu = cos (*rho + *sig); 00133 sinr = sin (*rho); 00134 cosr = cos (*rho); 00135 00136 *sinlat = sinlatc * cos (*rho) + coslatc * sinr * cos (*chi); 00137 *coslat = sqrt (1.0 - *sinlat * *sinlat); 00138 *lat = asin (*sinlat); 00139 sinlon = sinr * sin (*chi) / *coslat; 00140 *lon = asin (sinlon); 00141 if (cosr < (*sinlat * sinlatc)) *lon = M_PI - *lon; 00142 *lon += lonc; 00143 while (*lon < 0.0) *lon += 2 * M_PI; 00144 while (*lon >= 2 * M_PI) *lon -= 2 * M_PI; 00145 return (0); 00146 } 00147 00148 int plane2sphere (double x, double y, double latc, double lonc, 00149 double *lat, double *lon, int projection) { 00150 /* 00151 * Perform the inverse mapping from rectangular coordinates x, y on a map 00152 * in a particular projection to heliographic (or geographic) coordinates 00153 * latitude and longitude (in radians). 00154 * The map coordinates are first transformed into arc and azimuth coordinates 00155 * relative to the center of the map according to the appropriate inverse 00156 * transformation for the projection, and thence to latitude and longitude 00157 * from the known heliographic coordinates of the map center (in radians). 00158 * The scale of the map coordinates is assumed to be in units of radians at 00159 * the map center (or other appropriate location of minimum distortion). 00160 * 00161 * Arguments: 00162 * x } Map coordinates, in units of radians at the scale 00163 * y } appropriate to the map center 00164 * latc Latitude of the map center (in radians) 00165 * lonc Longitude of the map center (in radians) 00166 * *lat Returned latitude (in radians) 00167 * *lon Returned longitude (in radians) 00168 * projection A code specifying the map projection to be used: see below 00169 * 00170 * The following projections are supported: 00171 * RECTANGULAR A "rectangular" mapping of x and y directly to 00172 * longitude and latitude, respectively; it is the 00173 * normal cylindrical equidistant projection (plate 00174 * carrée) tangent at the equator and equidistant 00175 * along meridians. Central latitudes off the equator 00176 * merely result in displacement of the map in y 00177 * Also known as CYLEQD 00178 * CASSINI The transverse cylindrical equidistant projection 00179 * (Cassini-Soldner) equidistant along great circles 00180 * perpendicular to the central meridian 00181 * MERCATOR Mercator's conformal projection, in which paths of 00182 * constant bearing are straight lines 00183 * CYLEQA Lambert's normal equal cylindrical (equal-area) 00184 * projection, in which evenly-spaced meridians are 00185 * evenly spaced in x and evenly-spaced parallels are 00186 * separated by the cosine of the latitude 00187 * SINEQA The Sanson-Flamsteed sinusoidal equal-area projection, 00188 * in which evenly-spaced parallels are evenly spaced in 00189 * y and meridians are sinusoidal curves 00190 * GNOMONIC The gnomonic, or central, projection, in which all 00191 * straight lines correspond to geodesics; projection 00192 * from the center of the sphere onto a tangent plane 00193 * POSTEL Postel's azimuthal equidistant projection, in which 00194 * straight lines through the center of the map are 00195 * geodesics with a uniform scale 00196 * STEREOGRAPHIC The stereographic projection, mapping from the 00197 * antipode of the map center onto a tangent plane 00198 * ORTHOGRAPHIC The orthographic projection, mapping from infinity 00199 * onto a tangent plane 00200 * LAMBERT Lambert's azimuthal equivalent projection 00201 * 00202 * The function returns -1 if the requested point on the map does not project 00203 * back to the sphere or is not a principal value, 1 if it projects to a 00204 * point on a hidden hemisphere (if that makes sense), 0 otherwise 00205 */ 00206 static double latc0 = 0.0, sinlatc = 0.0, coslatc = 1.0 ; 00207 double r, rm, test; 00208 double cosr, sinr, cosp, sinp, coslat, sinlat, sinlon; 00209 double sinphi, cosphi, phicom; 00210 int status = 0; 00211 00212 if (latc != latc0) { 00213 coslatc = cos (latc); 00214 sinlatc = sin (latc); 00215 } 00216 latc0 = latc; 00217 00218 switch (projection) { 00219 case (RECTANGULAR): 00220 *lon = lonc + x; 00221 *lat = latc + y; 00222 if (arc_distance (*lat, *lon, latc, lonc) > M_PI_2) status = 1; 00223 if (fabs (x) > M_PI || fabs (y) > M_PI_2) status = -1; 00224 return status; 00225 case (CASSINI): { 00226 double sinx = sin (x); 00227 double cosy = cos (y + latc); 00228 double siny = sin (y + latc); 00229 *lat = acos (sqrt (cosy * cosy + siny * siny * sinx * sinx)); 00230 if (y < -latc) *lat *= -1; 00231 *lon = (fabs (*lat) < M_PI_2) ? lonc + asin (sinx / cos (*lat)) : lonc; 00232 if (y > (M_PI_2 - latc) || y < (-M_PI_2 - latc)) 00233 *lon = 2 * lonc + M_PI - *lon; 00234 if (*lon < -M_PI) *lon += 2* M_PI; 00235 if (*lon > M_PI) *lon -= 2 * M_PI; 00236 if (arc_distance (*lat, *lon, latc, lonc) > M_PI_2) status = 1; 00237 if (fabs (x) > M_PI || fabs (y) > M_PI_2) status = -1; 00238 return status; 00239 } 00240 case (CYLEQA): 00241 if (fabs (y) > 1.0) { 00242 y = copysign (1.0, y); 00243 status = -1; 00244 } 00245 cosphi = sqrt (1.0 - y*y); 00246 *lat = asin ((y * coslatc) + (cosphi * cos (x) * sinlatc)); 00247 test = (cos (*lat) == 0.0) ? 0.0 : cosphi * sin (x) / cos (*lat); 00248 *lon = asin (test) + lonc; 00249 if (fabs (x) > M_PI_2) { 00250 status = 1; 00251 while (x > M_PI_2) { 00252 *lon = M_PI - *lon; 00253 x -= M_PI; 00254 } 00255 while (x < -M_PI_2) { 00256 *lon = -M_PI - *lon; 00257 x += M_PI; 00258 } 00259 } 00260 if (arc_distance (*lat, *lon, latc, lonc) > M_PI_2) status = 1; 00261 return status; 00262 case (SINEQA): 00263 cosphi = cos (y); 00264 if (cosphi <= 0.0) { 00265 *lat = y; 00266 *lon = lonc; 00267 if (cosphi < 0.0) status = -1; 00268 return status; 00269 } 00270 *lat = asin ((sin (y) * coslatc) + (cosphi * cos (x/cosphi) * sinlatc)); 00271 coslat = cos (*lat); 00272 if (coslat <= 0.0) { 00273 *lon = lonc; 00274 if (coslat < 0.0) status = 1; 00275 return status; 00276 } 00277 test = cosphi * sin (x/cosphi) / coslat; 00278 *lon = asin (test) + lonc; 00279 if (fabs (x) > M_PI * cosphi) return (-1); 00280 /* 00281 if (fabs (x) > M_PI_2) { 00282 status = 1; 00283 while (x > M_PI_2) { 00284 *lon = M_PI - *lon; 00285 x -= M_PI; 00286 } 00287 while (x < -M_PI_2) { 00288 *lon = -M_PI - *lon; 00289 x += M_PI; 00290 } 00291 */ 00292 if (fabs (x) > M_PI_2 * cosphi) { 00293 status = 1; 00294 while (x > M_PI_2 * cosphi) { 00295 *lon = M_PI - *lon; 00296 x -= M_PI * cosphi; 00297 } 00298 while (x < -M_PI_2 * cosphi) { 00299 *lon = -M_PI - *lon; 00300 x += M_PI * cosphi; 00301 } 00302 } 00303 /* 00304 if (arc_distance (*lat, *lon, latc, lonc) > M_PI_2) status = 1; 00305 */ 00306 return status; 00307 case (MERCATOR): 00308 phicom = 2.0 * atan (exp (y)); 00309 sinphi = -cos (phicom); 00310 cosphi = sin (phicom); 00311 *lat = asin ((sinphi * coslatc) + (cosphi * cos (x) * sinlatc)); 00312 *lon = asin (cosphi * sin (x) / cos (*lat)) + lonc; 00313 if (arc_distance (*lat, *lon, latc, lonc) > M_PI_2) status = 1; 00314 if (fabs (x) > M_PI_2) status = -1; 00315 return status; 00316 } 00317 /* Convert to polar coordinates */ 00318 r = hypot (x, y); 00319 cosp = (r == 0.0) ? 1.0 : x / r; 00320 sinp = (r == 0.0) ? 0.0 : y / r; 00321 /* Convert to arc */ 00322 switch (projection) { 00323 case (POSTEL): 00324 rm = r; 00325 if (rm > M_PI_2) status = 1; 00326 break; 00327 case (GNOMONIC): 00328 rm = atan (r); 00329 break; 00330 case (STEREOGRAPHIC): 00331 rm = 2 * atan (0.5 * r); 00332 if (rm > M_PI_2) status = 1; 00333 break; 00334 case (ORTHOGRAPHIC): 00335 if ( r > 1.0 ) { 00336 r = 1.0; 00337 status = -1; 00338 } 00339 rm = asin (r); 00340 break; 00341 case (LAMBERT): 00342 if ( r > 2.0 ) { 00343 r = 2.0; 00344 status = -1; 00345 } 00346 rm = 2 * asin (0.5 * r); 00347 if (rm > M_PI_2 && status == 0) status = 1; 00348 break; 00349 } 00350 cosr = cos (rm); 00351 sinr = sin (rm); 00352 /* Convert to latitude-longitude */ 00353 sinlat = sinlatc * cosr + coslatc * sinr * sinp; 00354 *lat = asin (sinlat); 00355 coslat = cos (*lat); 00356 sinlon = (coslat == 0.0) ? 0.0 : sinr * cosp / coslat; 00357 /* This should never happen except for roundoff errors, but just in case: */ 00358 /* 00359 if (sinlon + 1.0 <= 0.0) *lon = -M_PI_2; 00360 else if (sinlon - 1.0 >= 0.0) *lon = M_PI_2; 00361 else 00362 */ 00363 *lon = asin (sinlon); 00364 /* Correction suggested by Dick Shine */ 00365 if (cosr < (sinlat * sinlatc)) *lon = M_PI - *lon; 00366 *lon += lonc; 00367 return status; 00368 } 00369 00370 int sphere2img (double lat, double lon, double latc, double lonc, 00371 double *x, double *y, double xcenter, double ycenter, 00372 double rsun, double peff, double ecc, double chi, 00373 int xinvrt, int yinvrt) { 00374 /* 00375 * Perform a mapping from heliographic coordinates latitude and longitude 00376 * (in radians) to plate location on an image of the sun. The plate 00377 * location is in units of the image radius and is given relative to 00378 * the image center. The function returns 1 if the requested point is 00379 * on the far side (>90 deg from disc center), 0 otherwise. 00380 * 00381 * Arguments: 00382 * lat Latitude (in radians) 00383 * lon Longitude (in radians) 00384 * latc Heliographic latitude of the disc center (in radians) 00385 * lonc Heliographic longitude of the disc center (in radians) 00386 * *x } Plate locations, in units of the image radius, relative 00387 * *y } to the image center 00388 * xcenter } Plate locations of the image center, in units of the 00389 * ycenter } image radius, and measured from an arbitrary origin 00390 * (presumably the plate center or a corner) 00391 * rsun Apparent semi-diameter of the solar disc, in plate 00392 * coordinates 00393 * peff Position angle of the heliographic pole, measured 00394 * eastward from north, relative to the north direction 00395 * on the plate, in radians 00396 * ecc Eccentricity of the fit ellipse presumed due to image 00397 * distortion (no distortion in direction of major axis) 00398 * chi Position angle of the major axis of the fit ellipse, 00399 * measure eastward from north, relative to the north 00400 * direction on the plate, in radians (ignored if ecc = 0) 00401 * xinvrt} Flag parameters: if not equal to 0, the respective 00402 * yinvrt} coordinates on the image x and y are inverted 00403 * 00404 * The heliographic coordinates are first mapped into the polar coordinates 00405 * in an orthographic projection centered at the appropriate location and 00406 * oriented with north in direction of increasing y and west in direction 00407 * of increasing x. The radial coordinate is corrected for foreshortening 00408 * due to the finite distance to the Sun. If the eccentricity of the fit 00409 * ellipse is non-zero the coordinate of the mapped point is proportionately 00410 * reduced in the direction parallel to the minor axis. 00411 * 00412 * Bugs: 00413 * The finite distance correction uses a fixed apparent semi-diameter 00414 * of 16'01'' appropriate to 1.0 AU. In principle the plate radius could 00415 * be used, but this would require the plate scale to be supplied and the 00416 * correction would probably be erroneous and in any case negligible. 00417 * 00418 * The ellipsoidal correction has not been tested very thoroughly. 00419 * 00420 * The return value is based on a test which does not take foreshortening 00421 * into account. 00422 */ 00423 static double sin_asd = 0.004660, cos_asd = 0.99998914; 00424 /* appropriate to 1 AU */ 00425 static double last_latc = 0.0, cos_latc = 1.0, sin_latc = 0.0; 00426 double r, cos_cang, xr, yr; 00427 double sin_lat, cos_lat, cos_lat_lon, cospa, sinpa; 00428 double squash, cchi, schi, c2chi, s2chi, xp, yp; 00429 int hemisphere; 00430 00431 if (latc != last_latc) { 00432 sin_latc = sin (latc); 00433 cos_latc = cos (latc); 00434 last_latc = latc; 00435 } 00436 sin_lat = sin (lat); 00437 cos_lat = cos (lat); 00438 cos_lat_lon = cos_lat * cos (lon - lonc); 00439 00440 cos_cang = sin_lat * sin_latc + cos_latc * cos_lat_lon; 00441 hemisphere = (cos_cang < 0.0) ? 1 : 0; 00442 r = rsun * cos_asd / (1.0 - cos_cang * sin_asd); 00443 xr = r * cos_lat * sin (lon - lonc); 00444 yr = r * (sin_lat * cos_latc - sin_latc * cos_lat_lon); 00445 /* Change sign for inverted images */ 00446 if (xinvrt) xr *= -1.0; 00447 if (yinvrt) yr *= -1.0; 00448 /* Correction for ellipsoidal squashing of image */ 00449 if (ecc > 0.0 && ecc < 1.0) { 00450 squash = sqrt (1.0 - ecc * ecc); 00451 cchi = cos (chi); 00452 schi = sin (chi); 00453 s2chi = schi * schi; 00454 c2chi = 1.0 - s2chi; 00455 xp = xr * (s2chi + squash * c2chi) - yr * (1.0 - squash) * schi * cchi; 00456 yp = yr * (c2chi + squash * s2chi) - xr * (1.0 - squash) * schi * cchi; 00457 xr = xp; 00458 yr = yp; 00459 } 00460 00461 cospa = cos (peff); 00462 sinpa = sin (peff); 00463 *x = xr * cospa - yr * sinpa; 00464 *y = xr * sinpa + yr * cospa; 00465 00466 *y += ycenter; 00467 *x += xcenter; 00468 00469 return (hemisphere); 00470 } 00471 00472 int sphere2plane (double lat, double lon, double latc, double lonc, 00473 double *x, double *y, int projection) { 00474 /* 00475 * Perform a mapping from heliographic (or geographic or celestial) 00476 * coordinates latitude and longitude (in radians) to map location in 00477 * the given projection. The function returns 1 if the requested point is 00478 * on the far side (>90 deg from disc center), 0 otherwise. 00479 * 00480 * Arguments: 00481 * lat Latitude (in radians) 00482 * lon Longitude (in radians) 00483 * latc Heliographic latitude of the disc center (in radians) 00484 * lonc Heliographic longitude of the disc center (in radians) 00485 * *x } Plate locations, in units of the image radius, relative 00486 * *y } to the image center 00487 * projection code specifying the map projection to be used: 00488 * see plane2sphere 00489 */ 00490 static double last_latc = 0.0, cos_latc = 1.0, sin_latc = 0.0, yc_merc; 00491 double r, rm, cos_cang; 00492 double sin_lat, cos_lat, cos_lat_lon; 00493 int hemisphere; 00494 00495 if (latc != last_latc) { 00496 sin_latc = sin (latc); 00497 cos_latc = cos (latc); 00498 last_latc = latc; 00499 yc_merc = log (tan (M_PI_4 + 0.5 * latc)); 00500 } 00501 sin_lat = sin (lat); 00502 cos_lat = cos (lat); 00503 cos_lat_lon = cos_lat * cos (lon - lonc); 00504 cos_cang = sin_lat * sin_latc + cos_latc * cos_lat_lon; 00505 hemisphere = (cos_cang < 0.0) ? 1 : 0; 00506 /* Cylindrical projections */ 00507 switch (projection) { 00508 /* Normal cylindrical equidistant */ 00509 case (RECTANGULAR): 00510 *x = lon - lonc; 00511 *y = lat - latc; 00512 return hemisphere; 00513 /* Transverse cylindrical equidistant */ 00514 case (CASSINI): 00515 *x = asin (cos_lat * sin (lon - lonc)); 00516 *y = atan2 (tan (lat), cos (lon - lonc)) - latc; 00517 return hemisphere; 00518 /* Normal cylindrical equivalent - differs from sphere2plane */ 00519 case (CYLEQA): 00520 *x = lon - lonc; 00521 *y = sin_lat - sin_latc; 00522 return hemisphere; 00523 /* Normal sinusoidal equivalent - differs from sphere2plane */ 00524 case (SINEQA): 00525 *x = cos_lat * (lon - lonc); 00526 *y = lat - latc; 00527 return hemisphere; 00528 /* Normal Mercator - differs from sphere2plane */ 00529 case (MERCATOR): 00530 *x = lon - lonc; 00531 *y = log (tan (M_PI_4 + 0.5 * lat)) - yc_merc; 00532 return hemisphere; 00533 } 00534 /* Azimuthal projections */ 00535 rm = acos (cos_cang); 00536 00537 switch (projection) { 00538 case (POSTEL): 00539 r = rm; 00540 break; 00541 case (GNOMONIC): 00542 r = tan (rm); 00543 break; 00544 case (STEREOGRAPHIC): 00545 r = 2.0 * tan (0.5 * rm); 00546 break; 00547 case (ORTHOGRAPHIC): 00548 r = sin (rm); 00549 break; 00550 case (LAMBERT): 00551 r = 2.0 * sin (0.5 * rm); 00552 break; 00553 default: 00554 return -1; 00555 } 00556 if (rm != 0.) { 00557 *x = r * cos_lat * sin (lon - lonc) / sin (rm); 00558 *y = r * (sin_lat * cos_latc - sin_latc * cos_lat_lon) / sin(rm); 00559 } else { 00560 *x = 0.; 00561 *y = 0.; 00562 } 00563 return hemisphere; 00564 } 00565 00566 /********************************************************************** 00567 * Projection names package -- contains a structure 00568 * with the conversion between names and numeric constants 00569 * for the different projections. Also two subroutines to walk back and 00570 * forth. The projection names are case inseNSiTIVe. 00571 * 00572 * The first table entry is the default value for the projection 00573 * if an unknown string is entered. 00574 */ 00575 static struct projnames { 00576 int projection; 00577 char *name; 00578 char *lowname; 00579 int uniq; 00580 } projnames[]= { 00581 {ORTHOGRAPHIC, "orthographic", "orthographic"}, 00582 {STEREOGRAPHIC, "stereographic", "stereographic"}, 00583 {POSTEL, "Postel\'s", "postels"}, 00584 {GNOMONIC, "Gnomonic", "gnomonic"}, 00585 {LAMBERT, "Lambert", "lambert"}, 00586 {CYLEQA, "cyleqa", "cyleqa"}, 00587 {SINEQA, "sineqa", "sineqa"}, 00588 {MERCATOR, "Mercator", "mercator"}, 00589 {RECTANGULAR, "plate carree", "plate carree"}, 00590 {CASSINI, "Cassini\'s", "cassinis"}, 00591 {-1, "", ""} 00592 }; 00593 00594 int name2proj (char *map_name) { 00595 char *s0, *s, *t; 00596 struct projnames *proj; 00597 00598 if (!map_name) return -1; 00599 00600 s0 = s = (char *)(malloc (strlen (map_name) + 1)); /* sic */ 00601 strcpy (s, map_name); 00602 for (t = s; *t; t++) *t = tolower (*t); 00603 /* trim leading and trailing whitespace */ 00604 for(; isspace (*s); s++); 00605 for (t = s; *t && !isspace (*t); t++); 00606 *t = '\0'; 00607 /* check for name */ 00608 for (proj=projnames; *(proj->name); proj++) { 00609 if (!strcmp (proj->lowname, s)) { 00610 free (s0); 00611 return proj->projection; 00612 } 00613 } 00614 00615 free (s0); 00616 return projnames->projection; 00617 } 00618 00619 00620 char *proj2name(int proj_in) { 00621 struct projnames *proj; 00622 for (proj=projnames; *(proj->name); proj++) { 00623 if (proj->projection == proj_in) return proj->name; 00624 } 00625 return "UNKNOWN"; 00626 } 00627 00628 00629 /* 00630 * Revision History 00631 * v 0.9 94.08.03 Rick Bogart created this file 00632 * 94.10.27 R Bogart reorganized for inclusion in libM 00633 * 94.11.24 R Bogart fixed bug in sinusoidal equal-area 00634 * mapping and minor bug in cylindrical equal-area mapoing 00635 * (latc != 0); added Mercator projection; more comments 00636 * 94.12.12 R Bogart & Luiz Sa fixed non-azimuthal projections 00637 * in plane2sphere to support center of map at other than L0L0; 00638 * removed unnecessary (and incorrect) scaling in azimuthal 00639 * mappings 00640 * v 1.0 95.08.18 R Bogart & L Sa implemented optimum_scale(); 00641 * added arguments and code to sphere2img() to deal with elliptic 00642 * images and image inversion; additional comments; 00643 * minor fix in SINEQA option of plane2sphere(); changed sign on 00644 * on position angle used in sphere2img() to conform with standard 00645 * usage (positive eastward from north in sky) 00646 * 96.05.17 R Bogart fixed bug in longitude calculation of 00647 * points "over the pole" for azimuthal projections in plane2sphere() 00648 * and corrected bug in sphere2img(). 00649 * 96.06.07 R Bogart return status of sphere2img indicates 00650 * whether mapped point is on far side of globe. 00651 * 96.12.18 R Bogart removed debugging prints from function 00652 * optimum_scale() 00653 * 97.01.21 R Bogart plane2sphere now returns status 00654 * 98.09.02 R Bogart added img2sphere 00655 * 99.02.25 R Bogart fixed calculated chi in img2sphere to 00656 * conform to man page description; plane2sphere now returns 1 if 00657 * requested point is not principal value in rectangular, cylindrical 00658 * equal-area, sinusoidal equal-area, and Mercator projections 00659 * 99.12.13 R Bogart added sphere2plane 00660 * 00.04.24 R Bogart modifications to plane2sphere to avoid 00661 * occasional roundoff errors leading to undefined results at the 00662 * limb 00663 * 05.01.07 R Bogart fixed bug in longitude calculation in 00664 * plane2sphere() for points more than 90deg from target longitude 00665 * of map center 00666 * 06.11.10 R Bogart fixed return value of sphere2plane for 00667 * cylindrical projection(s); added support for Cassini's projection 00668 * (transverse cylindrical equidistant); added support for normal 00669 * cylindrical and pseudocylindrical projections to sphere2plane 00670 * 09.07.02 R Bogart copied to private location for inclusion in 00671 * DRMS modules and standalone code; removed optimum_scale(), pow2scale(), 00672 * name2proj(), proj2name() 00673 * 09.12.02 R Bogart fixed two icc11 compiler warnings 00674 * 14.02.06 " fixed over-limb sinusoidal equal-area mapping 00675 * bug for plane2sphere (not thoroughly tested) 00676 * 14.08.01 " restored name2proj(), proj2name() from original 00677 * source (but removing "Aerial") 00678 */