OB.DAAC Logo
NASA Logo
Ocean Color Science Software

ocssw V2022
main_l1mapgen.c
Go to the documentation of this file.
1 /* ========================================================================
2  * MSl1tcpcbox - converts any L1B file to a ppm file
3  *
4  * Synopsis:
5  *
6  * MSl1tcpcbox input-l1[a|b]-filename output-ppm-filename
7  *
8  * Description:
9  *
10  * Modification history:
11  *
12  * Programmer Organization Date Description of change
13  * -------------- ------------ -------- ---------------------
14  * Bryan A. Franz GSC Jul 1998 Original development
15  * Joel Gales Futuretech Jan 2001 Added 8 and 24-bit hdf
16  * Norman Kuring NASA/GSFC Feb 2005 New scaling for true color
17  * Sean Bailey Futuretech Apr 2005 Modified MSl1brsgen to create
18  * MSl1tcpcbox by incorporating
19  * code from swtcpcbox
20  * Norman Kuring NASA/GSFC Mar 2006 New, more accurate estimate
21  * of pixel boundaries
22  * Norman Kuring NASA/GSFC Mar 2006 Changed binsoverlain from
23  * a static array to a
24  * dynamically allocated one
25  * to get rid of that pesky
26  * MAXBINSPERPIXEL warning.
27  * Norman Kuring NASA/GSFC Jul 2006 Removed sawtooth edges from
28  * output image and fixed bug
29  * that caused edge pixels to
30  * wrap from right to left side
31  * and vice versa.
32  *
33  * Sean Bailey Futuretech Nov 2007 Made scaling consistent with
34  * l1brsgen, use a sensor dependent defaults, and
35  * generally clean up the code
36  * Wayne Robinson SAIC Sep 2010 correct delta long
37  * computation for dateline wrap
38  * ======================================================================== */
39 #include "l12_proto.h"
40 #include "input_struc.h"
41 
42 #include "miscstruct.h"
43 #include "miscanfill.h"
44 #include "mipoly.h"
45 #include "clo.h"
46 #include <X11/X.h>
47 #include <X11/Xlib.h>
48 #include <png.h>
49 
50 #include <geotiffio.h>
51 #include <geo_normalize.h>
52 #include <geo_tiffp.h>
53 #include <geo_keyp.h>
54 #include <xtiffio.h>
55 #include <geokeys.h>
56 #include <scene_meta.h>
57 #include <libnav.h>
58 
59 //int l1mapgen_usage(char *prog);
60 
61 #define ROOT2 1.4142135623730950488016887242096981
62 
63 #define INT32 int32_t
64 #define FLOAT32 float
65 #define BYTE unsigned char
66 
67 #define BINBELOWTHRESH 110
68 
69 #define MALLOC(ptr,typ,num) { \
70  (ptr) = (typ *)malloc((num) * sizeof(typ)); \
71  if((ptr) == NULL){ \
72  fprintf(stderr,"-E- %s line %d: Memory allocation failure.\n", \
73  __FILE__,__LINE__); \
74  exit(EXIT_FAILURE); \
75  } \
76 }
77 #define CALLOC(ptr,typ,num) { \
78  (ptr) = (typ *)calloc((num) , sizeof(typ)); \
79  if((ptr) == NULL){ \
80  fprintf(stderr,"-E- %s line %d: Memory allocation failure.\n", \
81  __FILE__,__LINE__); \
82  exit(EXIT_FAILURE); \
83  } \
84 }
85 
86 BYTE logscale(float val, float min, float max);
87 BYTE linscale(float val, float min, float max);
88 
89 double rint(double);
90 int scan_convert(XPoint *);
91 int collect_bins(int, XPoint *, int *);
92 
93 static int *binsoverlain = NULL;
94 static int binsperpixel = 0;
95 static int numoverlain;
96 static int width, height;
97 static double imscale;
98 
99 /* -------------------------------------------------------------------- *
100  * main *
101  * -------------------------------------------------------------------- */
102 int main(int argc, char *argv[]) {
103 
104  int32_t iscan = 0; /* input scan number */
105  int32_t spix = 0; /* start pixel for subscene process */
106  int32_t epix = -1; /* end pixel for subscene process */
107  int32_t sscan = 0; /* start scan for subscene process */
108  int32_t escan = -1; /* end scan for subscene process */
109  int32_t dpix = 1; /* pixel increment for sub-sampling */
110  int32_t dscan = 1; /* scan subsampling increment */
111 
112  int32_t ip; /* input pixel number */
113 
114  int32_t npix = 0; /* Number of output pixels per scan */
115  int32_t nscan = 0; /* Number of output scans */
116 
117  BYTE rgb[3];
118  static int32_t r;
119  static int32_t g;
120  static int32_t b;
121 
122  int want_linscale = 0;
123  int want_atmocor = 0;
124  float min = 0.01;
125  float max = 0.9;
126 
127  double esdist;
128  int32_t sfactor = 1;
129  int32_t iw;
130 
131  l1str l1rec; /* generic level-1b scan structure */
132  filehandle l1file; /* input file handle */
133  FILE *outfp = NULL;
134 
135  char outfile[FILENAME_MAX] = "\0";
136 
137  int32_t bb;
138 
139  unsigned char *mean;
140  int32_t *count;
141  int32_t progress;
142  float64 * sum[3];
143  uint32_t numbins, bin, numoutpix;
144  XPoint corners[8]; /* actually, 4 pixel corners + 4 side midpoints */
145  float64 threshold, outpixpercent;
146  float32 north, south, west, east;
147  float32 nrad, srad, wrad, erad;
148 
149  float32 sr_r, sr_g, sr_b;
150 
151  int i;
152 
153  /* hold all of the command line options */
155 
156  float toa_reflect(l1str * l1rec, int32_t ip, int32_t ib);
157 
158  if (argc == 1) {
159  l2gen_usage("l1mapgen");
160  return 0;
161  }
162 
163  // see if help on command line
164  for (i = 0; i < argc; i++) {
165  if ((strcmp(argv[i], "-h") == 0) || (strcmp(argv[i], "-help") == 0)) {
166  l2gen_usage("l1mapgen");
167  return 1;
168  }
169  }
170 
171  cdata_();
174 
175  // create an option list
176  list = clo_createList();
177 
178  /* initialize the option list with descriptions and default values */
179  l2gen_init_options(list, "l1mapgen");
180 
181  // change the default values for this program
182  clo_setString(list, "atmocor", "off", "default");
183  clo_setString(list, "proc_land", "1", "default");
184  clo_setString(list, "sl_pixl", "0", "default");
185 
186  /* Parse input parameters */
187  if (msl12_option_input(argc, argv, list, "l1mapgen", &l1file) != 0) {
188  printf("-E- %s: Error parsing input parameters.\n", argv[0]);
189  exit(FATAL_ERROR);
190  }
191 
192  strcpy(outfile, input->ofile[0]);
193 
194  width = input->width;
195  threshold = input->threshold;
196  want_linscale = input->stype;
197  if (input->atmocor == 1)
198  want_atmocor = 1;
199 
200  min = input->datamin;
201  max = input->datamax;
202 
203  north = input->north;
204  south = input->south;
205  east = input->east;
206  west = input->west;
207 
208  /* */
209  /* Open input file and get sensor and scan information from handle */
210  /* */
211  if (openl1(&l1file) != 0) {
212  printf("-E- %s: Error opening %s for reading.\n", argv[0],
213  l1file.name);
214  exit(FATAL_ERROR);
215  }
216 
217  r = bindex_get(input->rgb[0]);
218  g = bindex_get(input->rgb[1]);
219  b = bindex_get(input->rgb[2]);
220  if (r < 0 || g < 0 || b < 0) {
221  printf("-E- Invalid RGB set for this sensor\n");
222  if (r < 0)
223  printf(" Invalid R: %d\n", input->rgb[0]);
224  if (g < 0)
225  printf(" Invalid G: %d\n", input->rgb[1]);
226  if (b < 0)
227  printf(" Invalid B: %d\n", input->rgb[2]);
228  exit(FATAL_ERROR);
229  }
230 
231 
232  /* Allocate memory for L1 scan data */
233 
234  if (alloc_l1(&l1file, &l1rec) == 0) {
235  printf("-E- %s: Unable to allocate L1 record.\n", argv[0]);
236  exit(FATAL_ERROR);
237  }
238 
239  /* Set the end pixel if it was not set by command argument */
240  if (l1_input->epixl < 1 || l1_input->epixl > l1file.npix)
241  l1_input->epixl = l1file.npix;
242  if (l1_input->eline < 1 || l1_input->eline > l1file.nscan)
243  l1_input->eline = l1file.nscan;
244  if (l1_input->spixl < 1)
245  l1_input->spixl = 1;
246  if (l1_input->sline < 1)
247  l1_input->sline = 1;
248  sfactor = 1;
249  spix = MAX(l1_input->spixl - 1, 0);
250  epix = MIN(l1_input->epixl - 1, l1file.npix - 1);
251  sscan = MAX(l1_input->sline - 1, 0);
252  escan = MIN(l1_input->eline - 1, l1file.nscan - 1);
253  dpix = sfactor;
254  dscan = sfactor;
255 
256  npix = (epix - spix) / sfactor + 1;
257  nscan = (escan - sscan) / sfactor + 1;
258 
259  l1file.spix = spix;
260  l1file.epix = epix;
261 
262  l1_input->sline = sscan + 1;
263  l1_input->eline = escan + 1;
264  l1_input->dline = dscan;
265  l1_input->spixl = spix + 1;
266  l1_input->epixl = epix + 1;
267  l1_input->dpixl = dpix;
268 
269  /* Determin scene boundaries */
270  if (north == -999 || south == -999 || east == -999 || south == -999) {
271  fprintf(stderr,
272  "Not all boundaries defined, grabbing from file...patience please...\n");
273 
274  // add a fix for seawifs, can not read seawifs lines out of order.
275  if (l1file.sensorID == SEAWIFS) {
276  int32_t sd_id = SDstart(l1file.name, DFACC_RDONLY);
277  if (sd_id == -1) {
278  printf("-E- lonlat2pixline: Error opening %s for reading.\n",
279  l1file.name);
280  exit(1);
281  }
282  float tmpf;
283  if (north == -999) {
284  READ_GLBL_ATTR_E("Northernmost Latitude", &tmpf);
285  north = ceilf(tmpf);
286  }
287  if (south == -999) {
288  READ_GLBL_ATTR_E("Southernmost Latitude", &tmpf);
289  south = floorf(tmpf);
290  }
291  if (east == -999) {
292  READ_GLBL_ATTR_E("Easternmost Longitude", &tmpf);
293  east = ceilf(tmpf);
294  }
295  if (west == -999) {
296  READ_GLBL_ATTR_E("Westernmost Longitude", &tmpf);
297  west = floorf(tmpf);
298  }
299  SDend(sd_id);
300 
301  } else {
302  // not a sweawifs L1 file
303 
304  scnstr *meta = scene_meta_get();
305 
306  for (iscan = sscan; iscan <= escan; iscan += 10) {
307 
308  if (readl1_lonlat(&l1file, iscan, &l1rec) != 0) {
309  fprintf(stderr, "-E- %s Line %d: error reading %s at scan %d.\n",
310  __FILE__, __LINE__, l1file.name, iscan);
311  exit(FATAL_ERROR);
312  }
313 
315  }
316 
317  if (north == -999)
318  north = ceilf(meta->northern_lat);
319  if (south == -999)
320  south = floorf(meta->southern_lat);
321  if (east == -999)
322  east = ceilf(meta->eastern_lon);
323  if (west == -999)
324  west = floorf(meta->western_lon);
325 
326  if (strcmp(meta->start_node, meta->end_node) != 0) {
327  printf("-E- Crossing the pole! Won't continue.\n");
328  closel1(&l1file);
329  exit(FATAL_ERROR);
330  }
331 
332  } // not seawifs
333 
334 
335  }
336  fprintf(stderr, "N: %f S: %f E: %f W:%f\n", north, south, east, west);
337  nrad = north * PI / 180;
338  srad = south * PI / 180;
339  wrad = west * PI / 180;
340  erad = east * PI / 180;
341 
342  if (nrad <= srad) {
343  fprintf(stderr,
344  "The northernmost boundary must be greater than the ");
345  fprintf(stderr, "southernmost boundary.\n");
346  exit(FATAL_ERROR);
347  }
348  /* Get the size of the output image. */
349  if (width < 32) {
350  fprintf(stderr,
351  "Width (%d) is too small to produce a useful image.\n",
352  width);
353  l2gen_usage("l1mapgen");
354  exit(FATAL_ERROR);
355  }
356  if (wrad < erad)
357  height = rint((nrad - srad) * width / (erad - wrad));
358  else
359  height = rint((nrad - srad) * width / (erad - wrad + 2 * PI));
360 
361  numbins = width * height;
362  imscale = height / (nrad - srad);
363 
364  for (bb = 0; bb < 3; bb++) {
365  CALLOC(sum[bb], float64, numbins);
366  }
367  CALLOC(count, int32_t, numbins);
368  CALLOC(mean, unsigned char, numbins * 3);
369 
370  /* Use the following variable to show this program's progress. */
371  progress = (int) ceil(((double) nscan / 78));
372 
373 
374  printf("Using r,g,b = %d, %d, %d\n", input->rgb[0], input->rgb[1],
375  input->rgb[2]);
376 
377  /* Read file scan by scan, scale radiances, and write. */
378  for (iscan = sscan; iscan <= escan; iscan++) {
379 
380  if (iscan % progress == 0)
381  fprintf(stderr, ".");
382  if (readl1(&l1file, iscan, &l1rec) != 0) {
383  fprintf(stderr,
384  "-E- %s Line %d: error reading %s at scan %d.\n",
385  __FILE__, __LINE__, l1file.name, iscan);
386  exit(FATAL_ERROR);
387  }
388 
389  if (want_atmocor) {
390  if (loadl1(&l1file, &l1rec) != 0) {
391  fprintf(stderr,
392  "-E- %s Line %d: error loading %s at scan %d.\n",
393  __FILE__, __LINE__, l1file.name, iscan);
394  exit(FATAL_ERROR);
395  }
396  } else {
397  /* Get correction for Earth-Sun distance and apply to Fo */
398  int16_t year, day;
399  double dsec;
400  unix2yds(l1rec.scantime, &year, &day, &dsec);
401  int32_t msec = (int32_t) (dsec * 1.e3);
402  int32_t yr = (int32_t) year;
403  int32_t dy = (int32_t) day;
404  esdist = esdist_(&yr, &dy, &msec);
405  l1rec.fsol = pow(1.0 / esdist, 2);
406  for (iw = 0; iw < l1file.nbands; iw++) {
407  l1rec.Fo[iw] = l1file.Fobar[iw] * l1rec.fsol;
408  }
409  }
410 
411 
412  /* Equations used to compute pixel boundaries below are taken from:
413  Map Projections -- A Working Manual
414  by John P. Snyder
415  U.S. Geological Survey Professional Paper 1395
416  Fourth Printing 1997
417  */
418 
419  for (ip = 0; ip < npix; ip++) {
420 
421  double plat, plon; /* pixel center */
422  double sinplat, cosplat;
423  double c[2]; /* edge/corner distance */
424  double sinc[2], cosc[2];
425  double sinaz[8], cosaz[8];
426  int i; /* loop index */
427  int out = 0; /* Number of pixel "corners" */
428 
429  /* that fall outside the image */
430 
431  plat = l1rec.lat[ip] * PI / 180;
432  plon = l1rec.lon[ip] * PI / 180;
433 
434  sinplat = sin(plat);
435  cosplat = cos(plat);
436 
437  if (ip < npix - 1) {
438 
439  double nlat, nlon; /* next pixel center */
440  double dlat, dlon; /* delta lat and lon */
441  double sindlat2, sindlon2, cosnlat;
442  double az; /* azimuth to next pixel */
443  double phw; /* pixel half width */
444 
445  nlat = l1rec.lat[ip + 1] * PI / 180;
446  nlon = l1rec.lon[ip + 1] * PI / 180;
447 
448  cosnlat = cos(nlat);
449 
450  dlat = nlat - plat;
451  dlon = nlon - plon;
452  /*
453  * WDR if del long is big in radians, assume dateline wrap
454  */
455  if (dlon > 5.) dlon = nlon - plon - 2 * PI;
456  if (dlon < -5.) dlon = nlon + 2 * PI - plon;
457 
458  sindlat2 = sin(dlat / 2);
459  sindlon2 = sin(dlon / 2);
460 
461  phw = asin(sqrt(sindlat2 * sindlat2 + /* Page 30, */
462  sindlon2 * sindlon2 * /* Equation */
463  cosplat * cosnlat)); /* 5-3a */
464 
465  /*
466  Make the pixel's coverage slightly broader to avoid
467  black pin holes in the output image where the estimated
468  pixel boundaries do not quite line up. Don't increase
469  the size too much, however, because that will cause
470  unwanted image blurring.
471  */
472  phw *= 1.6;
473 
474  c[0] = phw; /* center-to-edge distance */
475  c[1] = phw * ROOT2; /* center-to-corner distance */
476 
477  sinc[0] = sin(c[0]);
478  sinc[1] = sin(c[1]);
479  cosc[0] = cos(c[0]);
480  cosc[1] = cos(c[1]);
481 
482  az = /* Page 30, Equation 5-4b */
483  atan2(cosnlat * sin(dlon),
484  cosplat * sin(nlat) -
485  sinplat * cosnlat * cos(dlon)
486  );
487 
488  sinaz[0] = sin(az);
489  cosaz[0] = cos(az);
490  for (i = 1; i < 8; i++) {
491  az += PI / 4;
492  sinaz[i] = sin(az);
493  cosaz[i] = cos(az);
494  }
495  }
496 
497  for (i = 0; i < 8; i++) {
498  double lat, lon;
499  int ec; /* edge = 0, corner = 1 */
500 
501  ec = i & 1;
502 
503  /* Page 31, Equation 5-5 */
504  lat = asin(sinplat * cosc[ec]
505  + cosplat * sinc[ec] * cosaz[i]);
506 
507  lon = plon /* Page 31, Equation 5-6 */
508  + atan2(sinc[ec] * sinaz[i], cosplat * cosc[ec]
509  - sinplat * sinc[ec] * cosaz[i]);
510 
511  if (wrad > erad) { /* 180-degree meridian included */
512  if (lon >= wrad && lon > erad) {
513  corners[i].x = (lon - wrad) * imscale;
514  } else if (lon < wrad && lon <= erad) {
515  corners[i].x = (lon - wrad + 2 * PI) * imscale;
516  } else if (lon - erad < wrad - lon) {
517  corners[i].x = (lon - wrad + 2 * PI) * imscale;
518  } else {
519  corners[i].x = (lon - wrad) * imscale;
520  }
521  } else { /* 180-degree meridian not included */
522  corners[i].x = (lon - wrad) * imscale;
523  }
524 
525  corners[i].y = (nrad - lat) * imscale;
526 
527  if (corners[i].x < 0 || corners[i].x >= width
528  || corners[i].y < 0 || corners[i].y >= height)
529  out++;
530  }
531 
532  /*
533  If out == 8, then the entire pixel is outside the
534  image area, so I skip to the next one.
535  */
536  if (out == 8)
537  continue;
538 
539  if (l1rec.Lt[ip * l1rec.l1file->nbands + r] <= 0.01)
540  rgb[0] = rgb[1] = rgb[2] = 255;
541  else if (want_atmocor) {
542  sr_r = l1rec.rhos[ip * l1rec.l1file->nbands + r];
543  sr_g = l1rec.rhos[ip * l1rec.l1file->nbands + g];
544  sr_b = l1rec.rhos[ip * l1rec.l1file->nbands + b];
545 
546  /* Cheat blue band for MODIS */
547  /*
548  if ( (b == 2)
549  && (l1file.sensorID == 5 || l1file.sensorID == 6) )
550  sr_b *= 0.8;
551  */
552 
553  /* Cheat if red band saturates */
554  /* if (sr_r > 1.) sr_r = 0.975 * sr_g; */
555 
556  } else {
557  sr_r = toa_reflect(&l1rec, ip, r);
558  sr_g = toa_reflect(&l1rec, ip, g);
559  sr_b = toa_reflect(&l1rec, ip, b);
560  }
561 
562  if (want_linscale == 1) {
563  rgb[0] = linscale(sr_r, min, max);
564  rgb[1] = linscale(sr_g, min, max);
565  rgb[2] = linscale(sr_b, min, max);
566  } else {
567  rgb[0] = logscale(sr_r, min, max);
568  rgb[1] = logscale(sr_g, min, max);
569  rgb[2] = logscale(sr_b, min, max);
570  }
571 
572  if (l1file.sensorID == OCTS && rgb[2] > 234) {
573  if (rgb[0] < 230)
574  rgb[0] = 250;
575  if (rgb[1] < 230)
576  rgb[1] = 251;
577  rgb[2] = 252;
578  }
579 
580  /*
581  Use scan conversion to determine which bins are overlain
582  by this pixel. The global array, binsoverlain, is populated
583  by the scan_convert function.
584  */
585  numoverlain = 0;
586  scan_convert(corners);
587 
588  for (i = 0; i < numoverlain; i++) {
589  bin = binsoverlain[i];
590  /* Accumulate the sums for each bin. */
591  for (bb = 0; bb < 3; bb++) {
592  sum[bb][bin] += rgb[bb];
593  }
594  count[bin]++;
595  }
596 
597  } /* End for pixel */
598  } /* End for scan */
599 
600  fprintf(stderr, "\n");
601 
602  closel1(&l1file);
603 
604  /* Calculate the means for each bin. */
605  numoutpix = 0;
606  for (bin = 0; bin < numbins; bin++) {
607  if (count[bin] == 0) {
608  mean[3 * bin] = mean[3 * bin + 1] = mean[3 * bin + 2] = 0;
609  continue;
610  }
611  mean[3 * bin] = sum[0][bin] / count[bin];
612  mean[3 * bin + 1] = sum[1][bin] / count[bin];
613  mean[3 * bin + 2] = sum[2][bin] / count[bin];
614  if ((mean[3 * bin] + mean[3 * bin + 1] + mean[3 * bin + 2]) == 0) {
615  mean[3 * bin] = mean[3 * bin + 1] = mean[3 * bin + 2] = 1;
616  }
617  numoutpix++;
618  }
619 
620  /* Don't generate an image for underwhelming results. */
621  outpixpercent = (double) 100 * numoutpix / numbins;
622 
623  if (outpixpercent < threshold) {
624  fprintf(stderr, "Number of output pixels (%u of a possible %u) ",
625  numoutpix, numbins);
626  fprintf(stderr,
627  "< threshold (%.2lf%%). Output image not generated.\n",
628  threshold);
629  exit(BINBELOWTHRESH);
630  }
631 
632 
633  // write out the different file formats
634  // PPM file
635  if (strcmp(input->oformat, "PPM") == 0) {
636  if ((outfp = fopen(outfile, "w")) == NULL) {
637  printf("%s: Error: Unable to open %s for writing.\n",
638  argv[0], outfile);
639  exit(FATAL_ERROR);
640  }
641  fprintf(outfp, "P6\n");
642  fprintf(outfp, "%d\n", width);
643  fprintf(outfp, "%d\n", height);
644  fprintf(outfp, "255\n");
645  fwrite(mean, 3, numbins, outfp);
646  fclose(outfp);
647 
648  // PNG file
649  } else if (strcmp(input->oformat, "PNG") == 0) {
650  if ((outfp = fopen(outfile, "w")) == NULL) {
651  printf("%s: Error: Unable to open %s for writing.\n",
652  argv[0], outfile);
653  exit(FATAL_ERROR);
654  }
655 
656  png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
657  NULL, NULL, NULL);
658  if (!png_ptr) {
659  fprintf(stderr, "%s: Error: Unable to create PNG write structure.\n", argv[0]);
660  exit(FATAL_ERROR);
661  }
662 
663  png_infop info_ptr = png_create_info_struct(png_ptr);
664  if (!info_ptr) {
665  png_destroy_write_struct(&png_ptr, (png_infopp) NULL);
666  fprintf(stderr, "%s: Error: Unable to create PNG info structure.\n", argv[0]);
667  exit(FATAL_ERROR);
668  }
669  if (setjmp(png_jmpbuf(png_ptr))) {
670  png_destroy_write_struct(&png_ptr, (png_infopp) NULL);
671  fprintf(stderr, "%s: Error: Unable to call PNG setjmp().\n", argv[0]);
672  exit(FATAL_ERROR);
673  }
674  png_init_io(png_ptr, outfp);
675 
676  uint8_t * row_pointers[height];
677  for (i = 0; i < height; i++)
678  row_pointers[i] = mean + (i * width * 3);
679  png_set_rows(png_ptr, info_ptr, row_pointers);
680 
681  png_set_IHDR(png_ptr, info_ptr, width, height,
682  8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE,
683  PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
684 
685  png_write_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL);
686 
687  /* clean up after the write, and free any memory allocated */
688  png_destroy_write_struct(&png_ptr, (png_infopp) NULL);
689  fclose(outfp);
690 
691  // geoTIFF file
692  } else if (strcmp(input->oformat, "TIFF") == 0) {
693  TIFF *tiff;
694  GTIF *gtif;
695 
696  tiff = XTIFFOpen(outfile, "w");
697  if (tiff == NULL) {
698  fprintf(stderr, "Could not open outgoing image\n");
699  exit(FATAL_ERROR);
700  }
701  gtif = GTIFNew(tiff);
702  if (gtif == NULL) {
703  fprintf(stderr, "Could not create geoTIFF structure\n");
704  exit(FATAL_ERROR);
705  }
706 
707  // Write the tiff tags to the file
708  TIFFSetField(tiff, TIFFTAG_IMAGEWIDTH, width);
709  TIFFSetField(tiff, TIFFTAG_IMAGELENGTH, height);
710  //TIFFSetField(tiff, TIFFTAG_COMPRESSION, COMPRESSION_DEFLATE);
711  TIFFSetField(tiff, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
712  TIFFSetField(tiff, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB);
713  TIFFSetField(tiff, TIFFTAG_BITSPERSAMPLE, 8);
714  TIFFSetField(tiff, TIFFTAG_SAMPLESPERPIXEL, 3);
715 
716  // write geo TIFF tags
717  double tiepoints[6] = {0, 0, 0, 0, 0, 0};
718  double pixscale[3] = {0, 0, 0};
719 
720  // pixel width
721  pixscale[0] = (east - west) / width;
722 
723  // pixel height
724  pixscale[1] = (north - south) / height;
725 
726  // set top left corner pixel lat, lon
727  tiepoints[3] = west;
728  tiepoints[4] = north;
729 
730  TIFFSetField(tiff, GTIFF_PIXELSCALE, 3, pixscale);
731  TIFFSetField(tiff, GTIFF_TIEPOINTS, 6, tiepoints);
732 
733  // write geo TIFF keys
734  GTIFKeySet(gtif, GTModelTypeGeoKey, TYPE_SHORT, 1, ModelGeographic);
735  GTIFKeySet(gtif, GTRasterTypeGeoKey, TYPE_SHORT, 1, RasterPixelIsArea);
736  GTIFKeySet(gtif, GeographicTypeGeoKey, TYPE_SHORT, 1, GCS_WGS_84);
737 
738  GTIFWriteKeys(gtif);
739 
740  // Actually write the image
741  if (TIFFWriteEncodedStrip(tiff, 0, mean, width * height * 3) == 0) {
742  fprintf(stderr, "Could not write TIFF image\n");
743  exit(FATAL_ERROR);
744  }
745 
746  GTIFFree(gtif);
747  XTIFFClose(tiff);
748 
749 
750  } else {
751  fprintf(stderr, "%s Error: oformat=%s not valid.\n", argv[0], input->oformat);
752  exit(FATAL_ERROR);
753  }
754 
755  exit(EXIT_SUCCESS);
756 }
757 
758 /*------------------------------------------------------------------------------
759 
760  Function: scan_convert
761 
762  Returns type: int
763 
764  Description: This function is derived from the scan-conversion
765  code used by an X-server for filling in polygons.
766 
767  Parameters: (in calling order)
768  Type Name I/O Description
769  ---- ---- --- -----------
770  struct _DDXPoint* ptsIn In vertex specifications
771 
772  Modification history:
773  Programmer Date Description of change
774  ---------- ---- ---------------------
775  Norman Kuring 15-Sep-1992 Adaptation from X-server code
776  for my own nefarious purposes.
777 
778 ------------------------------------------------------------------------------*/
779 
780 /***********************************************************
781 Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts,
782 and the Massachusetts Institute of Technology, Cambridge, Massachusetts.
783 
784  All Rights Reserved
785 
786 Permission to use, copy, modify, and distribute this software and its
787 documentation for any purpose and without fee is hereby granted,
788 provided that the above copyright notice appear in all copies and that
789 both that copyright notice and this permission notice appear in
790 supporting documentation, and that the names of Digital or MIT not be
791 used in advertising or publicity pertaining to distribution of the
792 software without specific, written prior permission.
793 
794 DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
795 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
796 DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
797 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
798 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
799 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
800 SOFTWARE.
801 
802  ******************************************************************/
803 /* $XConsortium: mipolygen.c,v 5.0 89/06/09 15:08:35 keith Exp $ */
804 
805 extern void miloadAET(), micomputeWAET(), miFreeStorage();
806 extern int miCreateETandAET(), miInsertionSort();
807 
808 /*
809  * Written by Brian Kelleher; Oct. 1985
810  *
811  * Routine to fill a polygon. Two fill rules are
812  * supported: frWINDING and frEVENODD.
813  *
814  * See fillpoly.h for a complete description of the algorithm.
815  *
816  * Modified by Norman Kuring to fill a bin-number array instead of
817  * filling shapes on the server.
818  */
819 
820 int scan_convert(XPoint * ptsIn) {
821  int count = 8;
822  register EdgeTableEntry *pAET; /* the Active Edge Table */
823  register int y; /* the current scanline */
824  register int nPts = 0; /* number of pts in buffer */
825  register EdgeTableEntry *pWETE; /* Winding Edge Table */
826  register ScanLineList *pSLL; /* Current ScanLineList */
827  register XPoint *ptsOut; /* ptr to output buffers */
828  int *wdth;
829  XPoint FirstPoint[NUMPTSTOBUFFER]; /* the output buffers */
830  int FirstWidth[NUMPTSTOBUFFER];
831  EdgeTableEntry *pPrevAET; /* previous AET entry */
832  EdgeTable ET; /* Edge Table header node */
833  EdgeTableEntry AET; /* Active ET header node */
834  EdgeTableEntry *pETEs; /* Edge Table Entries buff */
835  ScanLineListBlock SLLBlock; /* header for ScanLineList */
836  int fixWAET = 0;
837 
838  if (!
839  (pETEs =
840  (EdgeTableEntry *) malloc(sizeof (EdgeTableEntry) * count))) {
841  return (0);
842  }
843  ptsOut = FirstPoint;
844  wdth = FirstWidth;
845  if (!miCreateETandAET(count, ptsIn, &ET, &AET, pETEs, &SLLBlock)) {
846  free(pETEs);
847  return (0);
848  }
849  pSLL = ET.scanlines.next;
850 
851  /*
852  * for each scanline
853  */
854  for (y = ET.ymin; y < ET.ymax; y++) {
855  /*
856  * Add a new edge to the active edge table when we
857  * get to the next edge.
858  */
859  if (pSLL && y == pSLL->scanline) {
860  miloadAET(&AET, pSLL->edgelist);
861  micomputeWAET(&AET);
862  pSLL = pSLL->next;
863  }
864  pPrevAET = &AET;
865  pAET = AET.next;
866  pWETE = pAET;
867 
868  /*
869  * for each active edge
870  */
871  while (pAET) {
872  /*
873  * if the next edge in the active edge table is
874  * also the next edge in the winding active edge
875  * table.
876  */
877  if (pWETE == pAET) {
878  ptsOut->x = pAET->bres.minor;
879  ptsOut++->y = y;
880  *wdth++ = pAET->nextWETE->bres.minor - pAET->bres.minor;
881  nPts++;
882 
883  /*
884  * send out the buffer
885  */
886  if (nPts == NUMPTSTOBUFFER) {
887  collect_bins(nPts, FirstPoint, FirstWidth);
888  ptsOut = FirstPoint;
889  wdth = FirstWidth;
890  nPts = 0;
891  }
892 
893  pWETE = pWETE->nextWETE;
894  while (pWETE != pAET)
895  EVALUATEEDGEWINDING(pAET, pPrevAET, y, fixWAET);
896  pWETE = pWETE->nextWETE;
897  }
898  EVALUATEEDGEWINDING(pAET, pPrevAET, y, fixWAET);
899  }
900 
901  /*
902  * reevaluate the Winding active edge table if we
903  * just had to resort it or if we just exited an edge.
904  */
905  if (miInsertionSort(&AET) || fixWAET) {
906  micomputeWAET(&AET);
907  fixWAET = 0;
908  }
909  }
910 
911  /*
912  * Get any spans that we missed by buffering
913  */
914  collect_bins(nPts, FirstPoint, FirstWidth);
915  free(pETEs);
916  miFreeStorage(SLLBlock.next);
917  return (1);
918 }
919 
920 int collect_bins(int number_of_initial_points,
921  XPoint * initial_point, int *span_width) {
922 
923  int i;
924  short x, y;
925  int end;
926 
927  /* The variables, width, height, binsoverlain, and numoverlain, are
928  * static global varibles. */
929 
930  for (i = 0; i < number_of_initial_points; i++) {
931 
932  y = initial_point[i].y;
933  if (y >= height || y < 0)
934  continue;
935 
936  for (x = initial_point[i].x,
937  end = initial_point[i].x + span_width[i]; x < end; x++) {
938  if (x >= width || x < 0)
939  continue;
940  if (numoverlain >= binsperpixel) {
941  binsperpixel += 1024;
942  binsoverlain =
943  (int *) realloc(binsoverlain,
944  binsperpixel * sizeof (int));
945  if (binsoverlain == NULL) {
946  fprintf(stderr, "-E- %s line %d: ", __FILE__, __LINE__);
947  fprintf(stderr,
948  "Memory allocation error (numoverlain=%d binsperpixel=%d\n",
949  numoverlain, binsperpixel);
950  exit(EXIT_FAILURE);
951  }
952  return (0);
953  }
954  binsoverlain[numoverlain++] = y * width + x;
955  }
956  }
957  return (1);
958 }
int32 l1file(int32 sdfid, int32 *nsamp, int32 *nscans, int16 *dtynum)
Definition: l1stat_chk.c:586
#define MAX(A, B)
Definition: swl0_utils.h:26
#define MIN(x, y)
Definition: rice.h:169
int r
Definition: decode_rs.h:73
#define EVALUATEEDGEWINDING(pAET, pPrevAET, y, fixWAET)
Definition: mipoly.h:114
int readl1(filehandle *l1file, int32_t recnum, l1str *l1rec)
Definition: l1_io.c:400
#define EXIT_SUCCESS
Definition: GEO_basic.h:72
int32_t day
#define ROOT2
Definition: main_l1mapgen.c:61
int ymin
Definition: mipoly.h:77
list(APPEND LIBS ${PGSTK_LIBRARIES}) add_executable(atteph_info_modis atteph_info_modis.c) target_link_libraries(atteph_info_modis $
Definition: CMakeLists.txt:7
#define CALLOC(ptr, typ, num)
Definition: main_l1mapgen.c:77
int l2gen_init_options(clo_optionList_t *list, const char *prog)
Definition: msl12_input.c:667
float mean(float *xs, int sample_size)
Definition: numerical.c:81
These are used to scale the SD before writing it to the HDF4 file The default is and which means the product is not scaled at all Since the product is usually stored as a float inside of this is a way to write the float out as a integer l2prod min
void micomputeWAET()
#define NULL
Definition: decode_rs.h:63
void filehandle_init(filehandle *file)
no change in intended resolving MODur00064 Corrected handling of bad ephemeris attitude resolving resolving GSFcd00179 Corrected handling of fill values for[Sensor|Solar][Zenith|Azimuth] resolving MODxl01751 Changed to validate LUT version against a value retrieved from the resolving MODxl02056 Changed to calculate Solar Diffuser angles without adjustment for estimated post launch changes in the MODIS orientation relative to incidentally resolving defects MODxl01766 Also resolves MODxl01947 Changed to ignore fill values in SCI_ABNORM and SCI_STATE rather than treating them as resolving MODxl01780 Changed to use spacecraft ancillary data to recognise when the mirror encoder data is being set by side A or side B and to change calculations accordingly This removes the need for seperate LUTs for Side A and Side B data it makes the new LUTs incompatible with older versions of the and vice versa Also resolves MODxl01685 A more robust GRing algorithm is being which will create a non default GRing anytime there s even a single geolocated pixel in a granule Removed obsolete messages from seed as required for compatibility with version of the SDP toolkit Corrected test output file names to end in out
Definition: HISTORY.txt:422
read l1rec
int msl12_option_input(int argc, char *argv[], clo_optionList_t *list, char *progName, filehandle *l1file)
float toa_reflect(l1str *l1rec, int32_t ip, int32_t ib)
Definition: l1_imgscale.c:8
float * lat
int32 * msec
Definition: l1_czcs_hdf.c:31
double esdist_(int32_t *year, int32_t *day, int32_t *msec)
void msl12_input_init()
Definition: msl12_input.c:485
void scene_meta_put(l1str *l1rec)
Definition: scene_meta.c:72
int clo_setString(clo_optionList_t *list, const char *key, const char *val, const char *source)
Definition: clo.c:1667
int32 nscan
Definition: l1_czcs_hdf.c:19
int l2gen_usage(const char *prog)
Definition: msl12_input.c:4254
instr * input
int collect_bins(int, XPoint *, int *)
#define PI
Definition: l3_get_org.c:6
unsigned char BYTE
Definition: elements.h:4
int bindex_get(int32_t wave)
Definition: windex.c:45
clo_optionList_t * clo_createList()
Definition: clo.c:532
int miCreateETandAET()
int ymax
Definition: mipoly.h:76
void cdata_()
l1_input_t * l1_input
Definition: l1_options.c:9
#define FATAL_ERROR
Definition: swl0_parms.h:5
int readl1_lonlat(filehandle *l1file, int32_t recnum, l1str *l1rec)
Definition: l1_io.c:587
void miloadAET()
void unix2yds(double usec, short *year, short *day, double *secs)
integer, parameter double
void closel1(filehandle *l1file)
Definition: l1_io.c:68
data_t b[NROOTS+1]
Definition: decode_rs.h:77
#define BINBELOWTHRESH
Definition: main_l1mapgen.c:67
#define OCTS
Definition: sensorDefs.h:14
int main(int argc, char *argv[])
int32 dpix
Definition: l1_czcs_hdf.c:22
int32 spix
Definition: l1_czcs_hdf.c:21
int32_t iscan
scnstr * scene_meta_get(void)
Definition: scene_meta.c:237
float * lon
int32 epix
Definition: l1_czcs_hdf.c:23
real *8 function esdist(iyr, iday, msec)
Definition: esdist.f:3
int scan_convert(XPoint *)
int32_t alloc_l1(filehandle *l1file, l1str *l1rec)
Definition: alloc_l1.c:15
#define NUMPTSTOBUFFER
Definition: mipoly.h:98
no change in intended resolving MODur00064 Corrected handling of bad ephemeris attitude resolving resolving GSFcd00179 Corrected handling of fill values for[Sensor|Solar][Zenith|Azimuth] resolving MODxl01751 Changed to validate LUT version against a value retrieved from the resolving MODxl02056 Changed to calculate Solar Diffuser angles without adjustment for estimated post launch changes in the MODIS orientation relative to incidentally resolving defects MODxl01766 Also resolves MODxl01947 Changed to ignore fill values in SCI_ABNORM and SCI_STATE rather than treating them as resolving MODxl01780 Changed to use spacecraft ancillary data to recognise when the mirror encoder data is being set by side A or side B and to change calculations accordingly This removes the need for seperate LUTs for Side A and Side B data it makes the new LUTs incompatible with older versions of the and vice versa Also resolves MODxl01685 A more robust GRing algorithm is being which will create a non default GRing anytime there s even a single geolocated pixel in a granule Removed obsolete messages from seed as required for compatibility with version of the SDP toolkit Corrected test output file names to end in per delivery and then split off a new MYD_PR03 pcf file for Aqua Added AssociatedPlatformInstrumentSensor to the inventory metadata in MOD01 mcf and MOD03 mcf Created new versions named MYD01 mcf and MYD03 where AssociatedPlatformShortName is rather than Terra The program itself has been changed to read the Satellite Instrument validate it against the input L1A and LUT and to use it determine the correct files to retrieve the ephemeris and attitude data from Changed to produce a LocalGranuleID starting with MYD03 if run on Aqua data Added the Scan Type file attribute to the Geolocation copied from the L1A and attitude_angels to radians rather than degrees The accumulation of Cumulated gflags was moved from GEO_validate_earth_location c to GEO_locate_one_scan c
Definition: HISTORY.txt:464
BYTE logscale(float val, float min, float max)
Definition: l1_imgscale.c:76
int loadl1(filehandle *l1file, l1str *l1rec)
Definition: loadl1.c:201
#define SEAWIFS
Definition: sensorDefs.h:12
int i
Definition: decode_rs.h:71
double rint(double)
msiBandIdx val
Definition: l1c_msi.cpp:34
BYTE linscale(float val, float min, float max)
Definition: l1_imgscale.c:25
int openl1(filehandle *l1file)
Definition: l1_io.c:207
How many dimensions is the output array Default is Not sure if anything above will work correctly strcpy(l2prod->title, "no title yet")
int miInsertionSort()
#define READ_GLBL_ATTR_E(nam, ptr)
Definition: hdf4utils.h:75
int npix
Definition: get_cmp.c:27
void miFreeStorage()
ScanLineList scanlines
Definition: mipoly.h:78
l2prod max
int count
Definition: decode_rs.h:79