ocssw  1.0
/disk01/web/ocssw/build/src/l3bindump/l3bindump.c (r8102/r7836)
Go to the documentation of this file.
00001 /*
00002 This program extracts data from level-3 HDF bin files and 
00003 writes them out as an ASCII table.
00004 
00005 Regions of interest can be specified by latitude and longitude
00006 boundaries or by a central coordinate and a radius in kilometers.
00007 
00008 Norman Kuring       14-Feb-2003 Original development
00009 Norman Kuring       11-Dec-2007 Fix memory-overrun bug and add a
00010                     couple of calls to free().
00011 Norman Kuring       21-Dec-2011 Give a precision when printing out
00012                     bit strings to avoid unwanted printing
00013                     of uninitialized memory.
00014 Norman Kuring       21-Mar-2013 Change the latbin array from 32-bit
00015                     floats to 64-bit to reduce rounding-
00016                     error effects on bin numbers at smaller
00017                     bin sizes.  Thanks to George White for
00018                     pointing this one out.
00019 */
00020 
00021 #include <stdio.h>
00022 #include <stdlib.h>
00023 #include <string.h>
00024 #include <math.h>
00025 #include "hdf.h"
00026 
00027 #define PI  3.1415926535897932384626433832795029L
00028 
00029 double sqrt(double x);
00030 double asin(double x);
00031 double sin(double x);
00032 double cos(double x);
00033 double fabs(double x);
00034 
00035 #define INFILE  argv[1]
00036 #define PARAM   argv[2]
00037 
00038 #define USAGE(prog) fprintf(stderr,"\
00039 Usage:\n\
00040 %s main_file_path parameter bin_number\n\
00041 or\n\
00042 %s main_file_path parameter lat lon radius\n\
00043 or\n\
00044 %s main_file_path parameter north south west east\n\
00045 ",prog,prog,prog)
00046 
00047 #define NUMROWS     2160
00048 #define EARTH_RADIUS    6371.229
00049 
00050 static int32    basebin[NUMROWS];
00051 static int16    numbin[NUMROWS];
00052 static float64  latbin[NUMROWS];
00053 static int32    totbins;
00054 
00055 #define BLIST_FIELDS "bin_num,nobs,nscenes,time_rec,weights,sel_cat,flags_set"
00056 #define BLIST_SIZE  19
00057 static uint8    blistrec[BLIST_SIZE];
00058 static int32    bin_num,flags_set;
00059 static int16    nobs,nscenes,time_rec;
00060 static float32  weights;
00061 static uint8    sel_cat;
00062 static VOIDP    bufptrs[] = {
00063         &bin_num,&nobs,&nscenes,&time_rec,&weights,&sel_cat,&flags_set
00064         };
00065 
00066 #define PREC_SIZE   8
00067 static uint8    paramrec[PREC_SIZE];
00068 static char *param_fields;
00069 static float32  sum,sum_sq;
00070 static VOIDP    paramptrs[] = {&sum,&sum_sq};
00071 
00072 void    initbin(void);
00073 int32   latlon2bin(double lat, double lon);
00074 void    bin2latlon(int32 bin, double *clat, double *clon);
00075 void    bin2bounds(int32 bin, double *n, double *s, double *w, double *e);
00076 int16   lat2row(double lat);
00077 int32   rowlon2bin(int16 row, double lon);
00078 int32   binsearch(int32 bin, int32 vdata_id, int32 numrecs);
00079 double  constrain_lat(double lat);
00080 double  constrain_lon(double lon);
00081 char    *bitstr16(int16 n);
00082 char    *bitstr32(int32 n);
00083 
00084 int main(int argc, char *argv[]){
00085 
00086   int32     numbins = 0, *binnums = NULL;
00087   int32     i;
00088   int32     file_id,vdata_ref,vdata_id,numrecs,pvd_id;
00089 
00090   initbin();
00091 
00092   if(argc == 4){
00093     /* Input arguments are: main_file_path parameter bin_number. */
00094     int32   bin_number;
00095     bin_number = atol(argv[3]);
00096     numbins = 1;
00097     binnums = (int32 *)malloc(sizeof(int32));
00098     if(binnums == NULL){
00099       fprintf(stderr,"-E- %s line %d: Memory allocation failed.\n",
00100       __FILE__,__LINE__);
00101       return(EXIT_FAILURE);
00102     }
00103     binnums[0] = bin_number;
00104   }
00105 
00106   else if(argc == 6){
00107     /* Input arguments are: main_file_path parameter lat lon radius. */
00108     double  clat, clon, radius, radius_degrees;
00109 
00110     clat    = constrain_lat(atof(argv[3]));
00111     clon    = constrain_lon(atof(argv[4]));
00112     radius = atof(argv[5]);
00113 
00114     radius_degrees = (radius/EARTH_RADIUS) * (180.0/PI);
00115     if(radius_degrees > 180){
00116       int32 b;
00117 
00118       /* The entire globe has been selected. */
00119       binnums = (int32 *)realloc(binnums,totbins*sizeof(int32));
00120       if(binnums == NULL){
00121         fprintf(stderr,"-E- %s line %d: Memory allocation failed.\n",
00122     __FILE__,__LINE__);
00123     return(EXIT_FAILURE);
00124       }
00125       for(b = 1; b <= totbins; b++){
00126     binnums[numbins++] = b;
00127       }
00128     }
00129     else{
00130       double    north, south;
00131       double    sin_c_over_2;
00132       int16 n_row, s_row, row;
00133 
00134       sin_c_over_2 = sin((radius/EARTH_RADIUS)/2);
00135 
00136       north  = clat + radius_degrees;
00137       south  = clat - radius_degrees;
00138 
00139       if(north > 90){
00140     /*
00141         Chosen radius extends north to pole and over the other side to some
00142     latitude south of the north pole.  Set the new north to this new
00143         latitude.  All bins north of this latitude get selected.
00144     */
00145         int32   n, b;
00146 
00147     north = 180 - north;
00148     n_row = lat2row(north);
00149         n = totbins - basebin[n_row] + 1;
00150         binnums = (int32 *)realloc(binnums,(numbins + n)*sizeof(int32));
00151         if(binnums == NULL){
00152           fprintf(stderr,"-E- %s line %d: Memory allocation failed.\n",
00153           __FILE__,__LINE__);
00154           return(EXIT_FAILURE);
00155         }
00156         for(b = basebin[n_row]; b <= totbins; b++){
00157           binnums[numbins++] = b;
00158         }
00159       }
00160       else{
00161         n_row = lat2row(north) + 1;
00162       }
00163 
00164       if(south < -90){
00165     /*
00166     Chosen radius extends south to pole and over the other side to some
00167     latitude north of the south pole.  Set the new south to this new
00168         latitude.  All bins south of this latitude get selected.
00169     */
00170         int32   n, b;
00171 
00172         south = -180 - south;
00173     s_row = lat2row(south);
00174         n = basebin[s_row] + numbin[s_row];
00175         binnums = (int32 *)realloc(binnums,(numbins + n)*sizeof(int32));
00176         if(binnums == NULL){
00177           fprintf(stderr,"-E- %s line %d: Memory allocation failed.\n",
00178           __FILE__,__LINE__);
00179           return(EXIT_FAILURE);
00180         }
00181         for(b = 1; b <= n; b++){
00182           binnums[numbins++] = b;
00183         }
00184       }
00185       else{
00186     s_row = lat2row(south) - 1;
00187       }
00188 
00189       for(row = s_row + 1; row < n_row; row++){
00190     double  deltalon;
00191     double  sin_deltalat_over_2;
00192         double  west, east;
00193 
00194     sin_deltalat_over_2 = sin((latbin[row] - clat)*(PI/180.0) / 2);
00195 
00196         /*
00197         The following equation is a rearranged version of
00198         Equation 5-3a on page 30 of
00199         Map Projections -- A Working Manual
00200         by John P. Snyder
00201         U.S. Geological Survey Professional Paper 1395
00202         1987
00203         (Fourth printing 1997)
00204         */
00205     deltalon = 2 * asin( sqrt( fabs(
00206         (sin_c_over_2*sin_c_over_2 - sin_deltalat_over_2*sin_deltalat_over_2)
00207         /( cos(latbin[row]*(PI/180.0)) * cos(clat*(PI/180.0)) )
00208         )));
00209 
00210         deltalon *= 180.0/PI;
00211 
00212         west = constrain_lon(clon - deltalon);
00213         east = constrain_lon(clon + deltalon);
00214 
00215     if(east < west){
00216           /* User's region of interest spans the 180-degree meridian. */
00217           int32   b,b1,b2,b3,b4,n1,n2;
00218           b1 = rowlon2bin(row,west);
00219           b2 = rowlon2bin(row, 180);
00220           b3 = rowlon2bin(row,-180);
00221           b4 = rowlon2bin(row,east);
00222           n1 = b2 - b1 + 1;
00223           n2 = b4 - b3 + 1;
00224           binnums = (int32 *)realloc(binnums,(numbins + n1 + n2)*sizeof(int32));
00225           if(binnums == NULL){
00226             fprintf(stderr,"-E- %s line %d: Memory allocation failed.\n",
00227             __FILE__,__LINE__);
00228             return(EXIT_FAILURE);
00229           }
00230           for(b = b1; b <= b2; b++){
00231             binnums[numbins++] = b;
00232           }
00233           for(b = b3; b <= b4; b++){
00234             binnums[numbins++] = b;
00235           }
00236         }
00237         else{
00238           /* User's region of interest does not span the 180-degree meridian. */
00239           int32   b,b1,bn,n;
00240   
00241           b1 = rowlon2bin(row,west);
00242           bn = rowlon2bin(row,east);
00243           n = bn - b1 + 1;
00244           binnums = (int32 *)realloc(binnums,(numbins + n)*sizeof(int32));
00245           if(binnums == NULL){
00246             fprintf(stderr,"-E- %s line %d: Memory allocation failed.\n",
00247             __FILE__,__LINE__);
00248             return(EXIT_FAILURE);
00249           }
00250           for(b = b1; b <= bn; b++){
00251             binnums[numbins++] = b;
00252           }
00253         }
00254       }
00255     }
00256   }
00257 
00258   else if(argc == 7){
00259     /* Input arguments are: main_file_path parameter north south west east. */
00260     double  north, south, west, east;
00261     int16   n_row, s_row, row;
00262 
00263     north = constrain_lat(atof(argv[3]));
00264     south = constrain_lat(atof(argv[4]));
00265     west  = constrain_lon(atof(argv[5]));
00266     east  = constrain_lon(atof(argv[6]));
00267 
00268     if(south > north){
00269       double    tmp;
00270 
00271       fprintf(stderr,"-W- %s line %d: ",__FILE__,__LINE__);
00272       fprintf(stderr,
00273       "Specified south latitude is greater than specified north latitude.\n");
00274       fprintf(stderr,"I will swap the two.\n");
00275       tmp = north;
00276       north = south;
00277       south = tmp;
00278     }
00279 
00280     n_row = lat2row(north);
00281     s_row = lat2row(south);
00282 
00283     for(row = s_row; row <= n_row; row++){
00284 
00285       if(east < west){
00286         /* User's region of interest spans the 180-degree meridian. */
00287         int32   b,b1,b2,b3,b4,n1,n2;
00288         b1 = rowlon2bin(row,west);
00289     b2 = rowlon2bin(row, 180);
00290     b3 = rowlon2bin(row,-180);
00291     b4 = rowlon2bin(row,east);
00292     n1 = b2 - b1 + 1;
00293     n2 = b4 - b3 + 1;
00294     binnums = (int32 *)realloc(binnums,(numbins + n1 + n2)*sizeof(int32));
00295     if(binnums == NULL){
00296           fprintf(stderr,"-E- %s line %d: Memory allocation failed.\n",
00297           __FILE__,__LINE__);
00298       return(EXIT_FAILURE);
00299     }
00300         for(b = b1; b <= b2; b++){
00301           binnums[numbins++] = b;
00302     }
00303     for(b = b3; b <= b4; b++){
00304           binnums[numbins++] = b;
00305     }
00306       }
00307       else{
00308         /* User's region of interest does not span the 180-degree meridian. */
00309         int32   b,b1,bn,n;
00310 
00311         b1 = rowlon2bin(row,west);
00312         bn = rowlon2bin(row,east);
00313         n = bn - b1 + 1;
00314         binnums = (int32 *)realloc(binnums,(numbins + n)*sizeof(int32));
00315         if(binnums == NULL){
00316           fprintf(stderr,"-E- %s line %d: Memory allocation failed.\n",
00317           __FILE__,__LINE__);
00318           return(EXIT_FAILURE);
00319         }
00320         for(b = b1; b <= bn; b++){
00321           binnums[numbins++] = b;
00322         }
00323       }
00324     }
00325   }
00326 
00327   else{
00328     USAGE(argv[0]);
00329     return(EXIT_FAILURE);
00330   }
00331 
00332   /*
00333   Now that I have a list of desired bins, I can extract the
00334   corresponding data from the level-3 bin files.
00335   */
00336 
00337   /* Open the HDF file. */
00338   file_id = Hopen(INFILE, DFACC_READ, 0);
00339   if(file_id == FAIL){
00340     fprintf(stderr,"-E- %s line %d: Hopen(%s,DFACC_READ,0) failed.\n",
00341     __FILE__,__LINE__,INFILE);
00342     return(EXIT_FAILURE);
00343   }
00344   /* Initialize the Vdata interface. */
00345   if(Vstart(file_id) == FAIL){
00346     fprintf(stderr,"-E- %s line %d: Vstart(%d) failed.\n",
00347     __FILE__,__LINE__,file_id);
00348     return(EXIT_FAILURE);
00349   }
00350 
00351   /* Open the "BinList" Vdata. */
00352   vdata_ref = VSfind(file_id,"BinList");
00353   if(vdata_ref == FAIL){
00354     fprintf(stderr,"-E- %s line %d: VSfind(%d,\"BinList\") failed.\n",
00355     __FILE__,__LINE__,file_id);
00356     return(EXIT_FAILURE);
00357   }
00358   vdata_id = VSattach(file_id, vdata_ref, "r");
00359   if(vdata_id == FAIL){
00360     fprintf(stderr,"-E- %s line %d: VSattach(%d,%d,\"r\") failed.\n",
00361     __FILE__,__LINE__,file_id,vdata_ref);
00362     return(EXIT_FAILURE);
00363   }
00364   /* Find out how many bins are stored in this file. */
00365   numrecs = VSelts(vdata_id);
00366   if(numrecs == FAIL){
00367     fprintf(stderr,"-E- %s line %d: VSelts(%d) failed.\n",
00368     __FILE__,__LINE__,vdata_id);
00369     return(EXIT_FAILURE);
00370   }
00371   /* Set up to read the fields in the BinList Vdata records. */
00372   if(VSsetfields(vdata_id,BLIST_FIELDS) == FAIL){
00373     fprintf(stderr,"-E- %s line %d: VSsetfields(%d,%s) failed.\n",
00374     __FILE__,__LINE__,vdata_id,BLIST_FIELDS);
00375     return(EXIT_FAILURE);
00376   }
00377 
00378   /* Open the parameter-specific Vdata. */
00379   vdata_ref = VSfind(file_id,PARAM);
00380   if(vdata_ref == 0){
00381     fprintf(stderr,"-E- %s line %d: VSfind(%d,\"%s\") failed.\n",
00382     __FILE__,__LINE__,file_id,PARAM);
00383     return(EXIT_FAILURE);
00384   }
00385   pvd_id = VSattach(file_id, vdata_ref, "r");
00386   if(pvd_id == FAIL){
00387     fprintf(stderr,"-E- %s line %d: VSattach(%d,%d,\"r\") failed.\n",
00388     __FILE__,__LINE__,file_id,vdata_ref);
00389     return(EXIT_FAILURE);
00390   }
00391   /* Set up to read the fields in the parameter-specific Vdata records. */
00392   {
00393     int len;
00394     len = 2*strlen(PARAM) + strlen("_sum,") + strlen("_sum_sq") + 1;
00395     param_fields = (char *)malloc(len);
00396     if(param_fields == NULL){
00397       fprintf(stderr,"-E- %s line %d: Memory allocation failed.\n",
00398       __FILE__,__LINE__);
00399       return(EXIT_FAILURE);
00400     }
00401     strcpy(param_fields,PARAM);
00402     strcat(param_fields,"_sum,");
00403     strcat(param_fields,PARAM);
00404     strcat(param_fields,"_sum_sq");
00405   }
00406   if(VSsetfields(pvd_id,param_fields) == FAIL){
00407     fprintf(stderr,"-E- %s line %d: VSsetfields(%d,%s) failed.\n",
00408     __FILE__,__LINE__,pvd_id,param_fields);
00409     return(EXIT_FAILURE);
00410   }
00411 
00412   /* Output a header record to identify the fields written out below. */
00413   printf("%80s%15.15s %15.15s\n"," ",PARAM,PARAM);
00414   printf("    bin centerlat  centerlon");
00415   printf("     north     south       west       east");
00416   printf("    n   N         sum_obs sum_squared_obs          weight");
00417   printf("  time_trend_bits                     l2_flag_bits sel\n");
00418   printf("------- --------- ----------");
00419   printf(" --------- --------- ---------- ----------");
00420   printf(" ---- --- --------------- --------------- ---------------");
00421   printf(" ---------------- -------------------------------- ---\n");
00422 
00423   for(i = 0; i < numbins; i++){
00424     int32   recno;
00425 
00426     recno = binsearch(binnums[i],vdata_id,numrecs);
00427     if(recno >= 0){
00428       double    n,s,w,e,clat,clon;
00429 
00430       /*
00431       Read the sum and sum-of-squares for the
00432       the specified parameter for this bin.
00433       */
00434       if(VSseek(pvd_id,recno) == FAIL){
00435         fprintf(stderr,"-E- %s line %d: VSseek(%d,%d) failed.\n",
00436         __FILE__,__LINE__,pvd_id,recno);
00437     return(EXIT_FAILURE);
00438       }
00439       if(VSread(pvd_id,paramrec,1,FULL_INTERLACE) != 1){
00440         fprintf(stderr,"-E- %s line %d: ",__FILE__,__LINE__);
00441     fprintf(stderr,"VSread(%d,paramrec,1,FULL_INTERLACE) failed.\n",
00442     pvd_id);
00443         return(EXIT_FAILURE);
00444       }
00445       /*
00446       VSfpack() sets the global sum and sum_sq variables
00447       via the paramptrs pointer array.
00448       */
00449       if(
00450       VSfpack(
00451       pvd_id,_HDF_VSUNPACK,param_fields,paramrec,PREC_SIZE,1,NULL,paramptrs
00452       )
00453       == FAIL){
00454         fprintf(stderr,"-E- %s line %d: ",__FILE__,__LINE__);
00455     fprintf(stderr,"VSfpack(%d, ...) failed.\n", pvd_id);
00456     return(EXIT_FAILURE);
00457       }
00458 
00459       /* Get the geographical coordinates associated with this bin. */
00460       bin2latlon(binnums[i],&clat,&clon);
00461       bin2bounds(binnums[i],&n,&s,&w,&e);
00462 
00463       /* Output the results. */
00464       printf("%7d %9.5f %10.5f %9.5f %9.5f %10.5f %10.5f ",
00465       binnums[i],clat,clon,n,s,w,e);
00466       printf("%4d %3d ",nobs,nscenes);
00467       printf("% .8e % .8e % .8e ",sum,sum_sq,weights);
00468       printf("%.16s %.32s ",bitstr16(time_rec),bitstr32(flags_set));
00469       printf("%3d",sel_cat);
00470       printf("\n");
00471     }
00472 
00473   }
00474 
00475   if(VSdetach(pvd_id) == FAIL){
00476     fprintf(stderr,"-E- %s line %d: VSdetach(%d) failed.\n",
00477     __FILE__,__LINE__,pvd_id);
00478     return(EXIT_FAILURE);
00479   }
00480   if(VSdetach(vdata_id) == FAIL){
00481     fprintf(stderr,"-E- %s line %d: VSdetach(%d) failed.\n",
00482     __FILE__,__LINE__,vdata_id);
00483     return(EXIT_FAILURE);
00484   }
00485   if(Vend(file_id) == FAIL){
00486     fprintf(stderr,"-E- %s line %d: Vend(%d) failed.\n",
00487     __FILE__,__LINE__,file_id);
00488     return(EXIT_FAILURE);
00489   }
00490   if(Hclose(file_id) == FAIL){
00491     fprintf(stderr,"-E- %s line %d: Hclose(%d) failed.\n",
00492     __FILE__,__LINE__,file_id);
00493     return(EXIT_FAILURE);
00494   }
00495 
00496   free(param_fields);
00497   free(binnums);
00498 
00499   return(EXIT_SUCCESS);
00500 } /* End of main() function */
00501 
00502 int32 binsearch(int32 bin, int32 vdata_id, int32 numrecs){
00503   int32 lo, hi, mid;
00504 
00505   lo = 0;
00506   hi = numrecs - 1;
00507   while(lo <= hi){
00508     mid = (lo + hi)/2;
00509     if(VSseek(vdata_id,mid) == FAIL){
00510       fprintf(stderr,"-E- %s line %d: VSseek(%d,%d) failed.\n",
00511       __FILE__,__LINE__,vdata_id,mid);
00512       exit(EXIT_FAILURE);
00513     }
00514     if(VSread(vdata_id,blistrec,1,FULL_INTERLACE) != 1){
00515       fprintf(stderr,"-E- %s line %d: ",__FILE__,__LINE__);
00516       fprintf(stderr,"VSread(%d,blistrec,1,FULL_INTERLACE) failed.\n",
00517       vdata_id);
00518       exit(EXIT_FAILURE);
00519     }
00520     /*
00521     VSfpack() sets the global bin_num variable (and others)
00522     via the bufptrs pointer array.
00523     */
00524     if(
00525     VSfpack(
00526     vdata_id,_HDF_VSUNPACK,BLIST_FIELDS,blistrec,BLIST_SIZE,1,NULL,bufptrs
00527     )
00528     == FAIL){
00529       fprintf(stderr,"-E- %s line %d: ",__FILE__,__LINE__);
00530       fprintf(stderr,"VSfpack(%d, ...) failed.\n", vdata_id);
00531       exit(EXIT_FAILURE);
00532     }
00533     if     (bin < bin_num) hi = mid - 1;
00534     else if(bin > bin_num) lo = mid + 1;
00535     else                   return(mid);
00536   }
00537   return(-1);
00538 }
00539 
00540 char *bitstr16(int16 n){
00541   static char   str[17];
00542   int       i;
00543 
00544   str[16]=0;
00545   for(i = 0; i < 16; i++){
00546     if(n & (1 << i)) str[i] = '1';
00547     else             str[i] = '0';
00548   }
00549   return(str);
00550 }
00551 
00552 char *bitstr32(int32 n){
00553   static char   str[33];
00554   int       i;
00555 
00556   str[32] = 0;
00557   for(i = 0; i < 32; i++){
00558     if(n & (1 << i)) str[i] = '1';
00559     else             str[i] = '0';
00560   } 
00561   return(str);
00562 }
00563 
00564 /*
00565 The following functions are based on the pseudocode found in Appendix A of:
00566 
00567 Campbell, J.W., J.M. Blaisdell, and M. Darzi, 1995:
00568 Level-3 SeaWiFS Data Products: Spatial and Temporal Binning Algorithms.
00569 NASA Tech. Memo. 104566, Vol. 32,
00570 S.B. Hooker, E.R. Firestone, and J.G. Acker, Eds.,
00571 NASA Goddard Space Flight Center, Greenbelt, Maryland
00572 */
00573 
00574 void initbin(void){
00575   int   row;
00576 
00577   basebin[0] = 1;
00578   for(row=0; row<NUMROWS; row++){
00579     latbin[row] = ((row + 0.5)*180.0/NUMROWS) - 90.0;
00580     numbin[row] = (int16)(2*NUMROWS*cos(latbin[row]*PI/180.0) + 0.5);
00581     if(row > 0){
00582       basebin[row] = basebin[row - 1] + numbin[row - 1];
00583     }
00584   }
00585   totbins = basebin[NUMROWS - 1] + numbin[NUMROWS - 1] - 1;
00586 }
00587 
00588 int16 lat2row(double lat){
00589   int16 row;
00590 
00591   row = (int16)((90 + lat)*NUMROWS/180.0);
00592   if(row >= NUMROWS) row = NUMROWS - 1;
00593   return(row);
00594 }
00595 
00596 int32 rowlon2bin(int16 row, double lon){
00597   int16 col;
00598   int32 bin;
00599 
00600   lon = constrain_lon(lon);
00601   col = (int16)((lon + 180.0)*numbin[row]/360.0);
00602   if(col >= numbin[row]) col = numbin[row] - 1;
00603   bin = basebin[row] + col;
00604   return(bin);
00605 }
00606 
00607 int32 latlon2bin(double lat, double lon){
00608   int16 row, col;
00609   int32 bin;
00610 
00611   /* Constrain latitudes to [-90,90] and longitudes to [-180,180]. */
00612   lat = constrain_lat(lat);
00613   lon = constrain_lon(lon);
00614 
00615   row = lat2row(lat);
00616   col = (int16)((lon + 180.0)*numbin[row]/360.0);
00617   if(col >= numbin[row]) col = numbin[row] - 1;
00618   bin = basebin[row] + col;
00619   return(bin);
00620 }
00621 
00622 void bin2latlon(int32 bin, double *clat, double *clon){
00623   int16 row;
00624 
00625   row = NUMROWS - 1;
00626   if(bin < 1) bin = 1;
00627   while(bin < basebin[row]) row--;
00628   *clat = latbin[row];
00629   *clon = 360.0*(bin - basebin[row] + 0.5)/numbin[row] - 180.0;
00630 }
00631 
00632 void bin2bounds(
00633 int32   bin,
00634 double  *north,
00635 double  *south,
00636 double  *west,
00637 double  *east
00638 ){
00639   int16     row;
00640   double    lon;
00641 
00642   row = NUMROWS - 1;
00643   if(bin < 1) bin = 1;
00644   while(bin < basebin[row]) row--;
00645   *north = latbin[row] + 90.0/NUMROWS;
00646   *south = latbin[row] - 90.0/NUMROWS;
00647   lon = 360.0*(bin - basebin[row] + 0.5)/numbin[row] - 180.0;
00648   *west = lon - 180.0/numbin[row];
00649   *east = lon + 180.0/numbin[row];
00650 }
00651 
00652 double constrain_lat(double lat){
00653   if(lat >  90) lat =  90;
00654   if(lat < -90) lat = -90;
00655   return(lat);
00656 }
00657 
00658 double constrain_lon(double lon){
00659   while(lon < -180) lon += 360;
00660   while(lon >  180) lon -= 360;
00661   return(lon);
00662 }