meta_parameters *iso2meta(iso_meta *iso) { int ii; meta_parameters *meta = raw_init(); char str[30]; // Convenience pointers iso_generalHeader *header = iso->generalHeader; iso_productComponents *comps = iso->productComponents; iso_productInfo *info = iso->productInfo; iso_productSpecific *spec = iso->productSpecific; iso_setup *setup = iso->setup; iso_processing *proc = iso->processing; iso_instrument *inst = iso->instrument; iso_platform *platform = iso->platform; iso_productQuality *quality = iso->productQuality; meta->meta_version = 3.5; // General block for (ii=0; ii<comps->numAnnotations; ii++) if (comps->annotation[ii].type == MAIN_TYPE) strncpy(meta->general->basename, comps->annotation[ii].file.name, 256); strcpy(meta->general->sensor, header->mission); strcpy(meta->general->sensor_name, info->sensor); strcpy(meta->general->mode, info->elevationBeamConfiguration); strcpy(meta->general->receiving_station, info->receivingStation); strcpy(meta->general->processor, header->generationSystem); if (info->imageDataType == DETECTED_DATA_TYPE && info->imageDataDepth == 8) meta->general->data_type = ASF_BYTE; else if (info->imageDataType == DETECTED_DATA_TYPE && info->imageDataDepth == 16) meta->general->data_type = INTEGER16; else if (info->imageDataType == DETECTED_DATA_TYPE && info->imageDataDepth == 32) // assumption here is that we are not dealing with INTERGER32 meta->general->data_type = REAL32; else if (info->imageDataType == DETECTED_DATA_TYPE && info->imageDataDepth == 64) meta->general->data_type = REAL64; else if (info->imageDataType == COMPLEX_DATA_TYPE && info->imageDataDepth == 8) meta->general->data_type = COMPLEX_BYTE; else if (info->imageDataType == COMPLEX_DATA_TYPE && info->imageDataDepth == 16) meta->general->data_type = COMPLEX_INTEGER16; else if (info->imageDataType == COMPLEX_DATA_TYPE && info->imageDataDepth == 32) // assumption here is that we are not dealing with COMPLEX_INTEGER32 meta->general->data_type = COMPLEX_REAL32; else if (info->imageDataType == COMPLEX_DATA_TYPE && info->imageDataDepth == 64) meta->general->data_type = COMPLEX_REAL64; if (info->imageDataType == RAW_DATA_TYPE) meta->general->image_data_type = RAW_IMAGE; else if (info->imageDataType == COMPLEX_DATA_TYPE) meta->general->image_data_type = COMPLEX_IMAGE; else if (info->imageDataType == DETECTED_DATA_TYPE) meta->general->image_data_type = AMPLITUDE_IMAGE; // more detailed mapping of imageDataType will probably need pixelValueID // context if (strcmp_case(info->pixelValueID, "RADAR BRIGHTNESS") == 0) meta->general->radiometry = r_AMP; // dealing with any form of calibration not implemented yet dateTime2str(info->sceneCenterCoord.azimuthTimeUTC, meta->general->acquisition_date); meta->general->orbit = info->absOrbit; if (info->orbitDirection == ASCENDING) meta->general->orbit_direction = 'A'; else if (info->orbitDirection == DESCENDING) meta->general->orbit_direction = 'D'; meta->general->frame = setup->frameID; meta->general->band_count = comps->numLayers; strcpy(meta->general->bands, polLayer2str(comps->imageData[0].polLayer)); for (ii=1; ii<comps->numLayers; ii++) { sprintf(str, ", %s", polLayer2str(comps->imageData[ii].polLayer)); strcat(meta->general->bands, str); } meta->general->line_count = info->numberOfRows; meta->general->sample_count = info->numberOfColumns; meta->general->start_line = info->startRow; meta->general->start_sample = info->startColumn; meta->general->x_pixel_size = info->groundRangeResolution; meta->general->y_pixel_size = info->azimuthResolution; meta->general->center_latitude = info->sceneCenterCoord.lat; meta->general->center_longitude = info->sceneCenterCoord.lon; spheroid_type_t spheroid = WGS84_SPHEROID; // FIXME: needs to know reference spheroid_axes_lengths(spheroid, &meta->general->re_major, &meta->general->re_minor); meta->general->bit_error_rate = quality->imageDataQuality[0].bitErrorRate; meta->general->missing_lines = quality->imageDataQuality[0].missingLines; meta->general->no_data = (float) quality->imageDataQuality[0].noData; // SAR block meta->sar = meta_sar_init(); if (info->projection == SLANTRANGE_PROJ) meta->sar->image_type = 'S'; else if (info->projection == GROUNDRANGE_PROJ) meta->sar->image_type = 'G'; else if (info->projection == MAP_PROJ) meta->sar->image_type = 'P'; if (setup->lookDirection == RIGHT_LOOK) meta->sar->look_direction = 'R'; else if (setup->lookDirection == LEFT_LOOK) meta->sar->look_direction = 'L'; meta->sar->azimuth_look_count = info->azimuthLooks; meta->sar->range_look_count = info->rangeLooks; if (spec->imageCoordinateType == RAW_COORD) meta->sar->deskewed = FALSE; else if (spec->imageCoordinateType == ZERODOPPLER) meta->sar->deskewed = TRUE; meta->general->line_scaling = info->rowScaling; meta->general->sample_scaling = info->columnScaling; meta->sar->range_time_per_pixel = info->columnSpacing; meta->sar->azimuth_time_per_pixel = info->rowSpacing; meta->sar->slant_shift = spec->slantRangeShift; //meta->sar->slant_range_first_pixel = info->rangeTimeFirstPixel * SPD_LIGHT; meta->sar->slant_range_first_pixel = spec->projectedSpacingSlantRange; meta->sar->wavelength = SPD_LIGHT / inst->centerFrequency; meta->sar->prf = spec->commonPRF; meta->sar->earth_radius = info->earthRadius; meta->sar->satellite_height = info->satelliteHeight; // meta->sar->satellite_binary_time; // meta->sar->satellite_clock_time; for (ii=0; ii<=proc->doppler[0].polynomialDegree; ii++) meta->sar->range_doppler_coefficients[ii] = proc->doppler[0].coefficient[ii]; meta->sar->azimuth_doppler_coefficients[0] = proc->doppler[0].coefficient[0]; // meta->sar->chirp_rate // meta->sar->pulse_duration meta->sar->range_sampling_rate = spec->commonRSF; if (info->polarizationMode == SINGLE_POL) strcpy(meta->sar->polarization, "SINGLE"); else if (info->polarizationMode == DUAL_POL) strcpy(meta->sar->polarization, "DUAL"); else if (info->polarizationMode == QUAD_POL) strcpy(meta->sar->polarization, "QUAD"); meta->sar->multilook = proc->multiLookedFlag; meta->sar->pitch = info->pitch; meta->sar->roll = info->roll; meta->sar->yaw = info->yaw; meta->sar->incid_a[0] = info->sceneCenterCoord.incidenceAngle; meta->sar->heading_angle = info->headingAngle; meta->sar->chirp_rate = proc->processingParameter[0].chirpRate; meta->sar->pulse_duration = proc->processingParameter[0].pulseDuration; // meta->projection // meta->transform // meta->airsar // meta->uavsar // meta->statistics int numVectors = platform->numStateVectors; meta->state_vectors = meta_state_vectors_init(numVectors); meta->state_vectors->vector_count = numVectors; ymd_date ymdStart, ymdSV; julian_date jd; hms_time hmsStart, hmsSV; ymdStart.year = info->startTimeUTC.year; ymdStart.month = info->startTimeUTC.month; ymdStart.day = info->startTimeUTC.day; hmsStart.hour = info->startTimeUTC.hour; hmsStart.min = info->startTimeUTC.min; hmsStart.sec = info->startTimeUTC.second; meta->state_vectors->year = info->startTimeUTC.year; date_ymd2jd(&ymdStart, &jd); meta->state_vectors->julDay = jd.jd; meta->state_vectors->second = date_hms2sec(&hmsStart); for (ii=0; ii<numVectors; ii++) { ymdSV.year = platform->stateVec[ii].timeUTC.year; ymdSV.month = platform->stateVec[ii].timeUTC.month; ymdSV.day = platform->stateVec[ii].timeUTC.day; hmsSV.hour = platform->stateVec[ii].timeUTC.hour; hmsSV.min = platform->stateVec[ii].timeUTC.min; hmsSV.sec = platform->stateVec[ii].timeUTC.second; meta->state_vectors->vecs[ii].time = time_difference(&ymdSV, &hmsSV, &ymdStart, &hmsStart); meta->state_vectors->vecs[ii].vec.pos.x = platform->stateVec[ii].posX; meta->state_vectors->vecs[ii].vec.pos.y = platform->stateVec[ii].posY; meta->state_vectors->vecs[ii].vec.pos.z = platform->stateVec[ii].posZ; meta->state_vectors->vecs[ii].vec.vel.x = platform->stateVec[ii].velX; meta->state_vectors->vecs[ii].vec.vel.y = platform->stateVec[ii].velY; meta->state_vectors->vecs[ii].vec.vel.z = platform->stateVec[ii].velZ; } if (meta->sar->azimuth_time_per_pixel > 0) meta->sar->time_shift = 0.0; else meta->sar->time_shift = meta->state_vectors->vecs[numVectors-1].time; if (meta->sar->yaw == 0 || !meta_is_valid_double(meta->sar->yaw)) { meta->sar->yaw = meta_yaw(meta, meta->general->line_count/2.0, meta->general->sample_count/2.0); } /* // few calculations need state vectors meta->sar->earth_radius = meta_get_earth_radius(meta, line_count/2, sample_count/2); // meta->sar->earth_radius_pp meta->sar->satellite_height = meta_get_sat_height(meta, meta->general->line_count/2, meta->general->sample_count/2); meta->sar->incid_a[0] = meta_incid(meta, line_count/2, sample_count/2)*R2D; */ // Location block meta_get_corner_coords(meta); /* meta->location = meta_location_init(); for (ii=0; ii<4; ii++) { if (info->sceneCornerCoord[ii].refRow == 0 && info->sceneCornerCoord[ii].refColumn == 0) { meta->location->lat_start_near_range = info->sceneCornerCoord[ii].lat; meta->location->lon_start_near_range = info->sceneCornerCoord[ii].lon; } else if (info->sceneCornerCoord[ii].refRow == 0 && info->sceneCornerCoord[ii].refColumn == sample_count) { meta->location->lat_start_far_range = info->sceneCornerCoord[ii].lat; meta->location->lon_start_far_range = info->sceneCornerCoord[ii].lon; } else if (info->sceneCornerCoord[ii].refRow == line_count && info->sceneCornerCoord[ii].refColumn == 0) { meta->location->lat_end_near_range = info->sceneCornerCoord[ii].lat; meta->location->lon_end_near_range = info->sceneCornerCoord[ii].lon; } else if (info->sceneCornerCoord[ii].refRow == line_count && info->sceneCornerCoord[ii].refColumn == sample_count) { meta->location->lat_end_far_range = info->sceneCornerCoord[ii].lat; meta->location->lon_end_far_range = info->sceneCornerCoord[ii].lon; } } */ return meta; }
int main(int argc, char **argv) { FILE *fpIn, *fpOut, *fpInList, *fpOutList, *fpXml; meta_parameters *meta; extern int currArg; /* from cla.h in asf.h... initialized to 1 */ logflag = 0; // Parse command line args while (currArg < (argc-2)) { char *key=argv[currArg++]; if (strmatch(key,"-log")) { sprintf(logFile, "%s", argv[currArg]); logflag = 1; } else { printf("\n ***Invalid option: %s\n\n", argv[currArg-1]); usage(argv[0]); } } if ((argc-currArg) < 2) { printf("Insufficient arguments.\n"); usage(argv[0]); } asfSplashScreen(argc, argv); char *listInFile = (char *) MALLOC(sizeof(char)*(strlen(argv[1])+1)); strcpy(listInFile, argv[1]); char *outFile = (char *) MALLOC(sizeof(char)*(strlen(argv[2])+1)); strcpy(outFile, argv[2]); // Setup file names char outDirName[512], outFileName[512]; split_dir_and_file(outFile, outDirName, outFileName); char *tmpDir = (char *) MALLOC(sizeof(char)*512); sprintf(tmpDir, "%smeasures-", outDirName); char *tsdir = time_stamp_dir(); strcat(tmpDir, tsdir); FREE(tsdir); create_clean_dir(tmpDir); char *isoStr = iso_date(); // Read header information char inFile[512], imgFile[768], metaFile[768]; char listOutFile[768], citation[50], start[30], end[30], first[30]; char header[120], baseName[512], dirName[512], ext[5]; float x_pix, y_pix, x_map_ll, y_map_ll, x_map_ur, y_map_ur, inc, cat; double lat, lon, height, x, y, z; int ii, kk, nFiles=0, num = 1, sample_count, line_count; image_data_type_t image_data_type; sprintf(listOutFile, "%s%crgps.xml", tmpDir, DIR_SEPARATOR); // Preparing map projection information project_parameters_t pps; projection_type_t proj_type; datum_type_t datum; spheroid_type_t spheroid; read_proj_file("polar_stereographic_north_ssmi.proj", &pps, &proj_type, &datum, &spheroid); pps.ps.false_easting = 0.0; pps.ps.false_northing = 0.0; meta_projection *proj = meta_projection_init(); proj->type = proj_type; proj->datum = HUGHES_DATUM; proj->spheroid = HUGHES_SPHEROID; proj->param = pps; strcpy(proj->units, "meters"); proj->hem = 'N'; spheroid_axes_lengths(spheroid, &proj->re_major, &proj->re_minor); FREE(proj); // Set up supplemental file names: water mask, lat/lon, x/y grids char maskFile[768], latFile[768], lonFile[768], xFile[768], yFile[768]; sprintf(maskFile, "%s%cwater_mask.img", tmpDir, DIR_SEPARATOR); sprintf(latFile, "%s%clatitude.img", tmpDir, DIR_SEPARATOR); sprintf(lonFile, "%s%clongitude.img", tmpDir, DIR_SEPARATOR); sprintf(xFile, "%s%cxgrid.img", tmpDir, DIR_SEPARATOR); sprintf(yFile, "%s%cygrid.img", tmpDir, DIR_SEPARATOR); // Generating output XML file fpInList = FOPEN(listInFile, "r"); fpOutList = FOPEN(listOutFile, "w"); fprintf(fpOutList, "<netcdf>\n"); fprintf(fpOutList, " <data>\n"); fprintf(fpOutList, " <latitude>%s</latitude>\n", latFile); fprintf(fpOutList, " <longitude>%s</longitude>\n", lonFile); fprintf(fpOutList, " <xgrid>%s</xgrid>\n", xFile); fprintf(fpOutList, " <ygrid>%s</ygrid>\n", yFile); fprintf(fpOutList, " <mask>%s</mask>\n", maskFile); julian_date jdStart, jdEnd, jdRef; hms_time hms; hms.hour = 0; hms.min = 0; hms.sec = 0.0; asfPrintStatus("Working through the file list:\n"); int myrFlag=FALSE, divFlag=FALSE, vrtFlag=FALSE, shrFlag=FALSE; int firstYear, firstDay, startYear, startDay, endYear, endDay; double westBoundLon, eastBoundLon, northBoundLat, southBoundLat; double minLat=90.0, maxLat=-90.0, minLon=180.0, maxLon=-180.0; while (fgets(inFile, 512, fpInList)) { chomp(inFile); char inDirName[512], inFileName[512]; split_dir_and_file(inFile, inDirName, inFileName); // Preparing map projection information project_parameters_t pps; projection_type_t proj_type; datum_type_t datum; spheroid_type_t spheroid; read_proj_file("polar_stereographic_north_ssmi.proj", &pps, &proj_type, &datum, &spheroid); pps.ps.false_easting = 0.0; pps.ps.false_northing = 0.0; meta_projection *proj = meta_projection_init(); proj->type = proj_type; proj->datum = HUGHES_DATUM; proj->spheroid = HUGHES_SPHEROID; proj->param = pps; strcpy(proj->units, "meters"); proj->hem = 'N'; spheroid_axes_lengths(spheroid, &proj->re_major, &proj->re_minor); // Sort out dates startYear = subInt(inFileName, 0, 4); startDay = subInt(inFileName, 4, 3); endYear = subInt(inFileName, 8, 4); endDay = subInt(inFileName, 12, 3); if (nFiles == 0) { firstYear = startYear; firstDay = startDay; } sprintf(citation, "%d%03d to %d%03d", startYear, startDay, endYear, endDay); rgps2iso_date(startYear, (double) startDay, start); rgps2iso_date(endYear, (double) endDay, end); rgps2iso_date(firstYear, (double) firstDay, first); // Read header information FILE *fpIn = FOPEN(inFile, "r"); fgets(header, 100, fpIn); sscanf(header, "%f %f %f %f %f %f", &x_pix, &y_pix, &x_map_ll, &y_map_ll, &x_map_ur, &y_map_ur); fgets(header, 100, fpIn); int params = sscanf(header, "%f %f %d %d", &inc, &cat, &sample_count, &line_count); if (params == 3) { sscanf(header, "%f %d %d", &cat, &sample_count, &line_count); inc = 0; } else if (params == 2) { sscanf(header, "%d %d", &sample_count, &line_count); inc = 0; cat = 1; } num = (int) cat; if (num > 1) asfPrintError("Multiband imagery (%s) not supported for netCDF " "generation!\n", inFile); /* printf("x_pix: %f, y_pix: %f\n", x_pix, y_pix); printf("x_map_ll: %f, y_map_ll: %f\n", x_map_ll, y_map_ll); printf("x_map_ur: %f, y_map_ur: %f\n", x_map_ur, y_map_ur); printf("sample_count: %d, line_count: %d\n\n", sample_count, line_count); */ // Check extension split_base_and_ext(inFileName, 1, '.', baseName, ext); asfPrintStatus("Processing %s ...\n", inFileName); sprintf(imgFile, "%s%c%s_%s.img", tmpDir, DIR_SEPARATOR, baseName, &ext[1]); sprintf(metaFile, "%s%c%s_%s.meta", tmpDir, DIR_SEPARATOR, baseName, &ext[1]); jdRef.year = firstYear; jdRef.jd = 1; jdStart.year = startYear; jdStart.jd = startDay; jdEnd.year = endYear; jdEnd.jd = endDay; double startSec = date2sec(&jdStart, &hms) - date2sec(&jdRef, &hms); double endSec = date2sec(&jdEnd, &hms) - date2sec(&jdRef, &hms); if (strcmp_case(ext, ".MYR") == 0) { fprintf(fpOutList, " <multiyear_ice_fraction start=\"%.0f\" end=\"%.0f" "\">%s</multiyear_ice_fraction>\n", startSec, endSec, imgFile); image_data_type = MULTIYEAR_ICE_FRACTION; myrFlag = TRUE; } else if (strcmp_case(ext, ".DIV") == 0) { fprintf(fpOutList, " <divergence start=\"%.0f\" end=\"%.0f\">%s" "</divergence>\n", startSec, endSec, imgFile); image_data_type = DIVERGENCE; divFlag = TRUE; } else if (strcmp_case(ext, ".VRT") == 0) { fprintf(fpOutList, " <vorticity start=\"%.0f\" end=\"%.0f\">%s" "</vorticity>\n", startSec, endSec, imgFile); image_data_type = VORTICITY; vrtFlag = TRUE; } else if (strcmp_case(ext, ".SHR") == 0) { fprintf(fpOutList, " <shear start=\"%.0f\" end=\"%.0f\">%s</shear>", startSec, endSec, imgFile); image_data_type = SHEAR; shrFlag = TRUE; } // Generate basic metadata meta = raw_init(); meta->general->line_count = line_count; meta->general->sample_count = sample_count; meta->general->band_count = 1; meta->general->data_type = REAL32; meta->general->image_data_type = image_data_type; strcpy(meta->general->basename, inFile); meta->general->x_pixel_size = x_pix*1000.0; meta->general->y_pixel_size = y_pix*1000.0; meta->general->start_line = 0; meta->general->start_sample = 0; meta->general->no_data = MAGIC_UNSET_DOUBLE; strcpy(meta->general->sensor, "RGPS MEaSUREs"); char *tmp = image_data_type2str(meta->general->image_data_type); sprintf(meta->general->bands, "%s", lc(tmp)); FREE(tmp); sprintf(meta->general->acquisition_date, "%s", baseName); // Sort out map projection proj->startX = x_map_ll*1000.0; proj->startY = y_map_ur*1000.0; proj->perX = x_pix*1000.0; proj->perY = -y_pix*1000.0; meta->projection = proj; meta_write(meta, metaFile); strcpy(meta->general->bands, "water mask"); sprintf(metaFile, "%s%cwater_mask.meta", tmpDir, DIR_SEPARATOR); meta_write(meta, metaFile); sprintf(metaFile, "%s%c%s_%s.meta", tmpDir, DIR_SEPARATOR, baseName, &ext[1]); float *floatBuf = (float *) MALLOC(sizeof(float)*sample_count); // Write gridded data to ASF internal format fpOut = FOPEN(imgFile, "wb"); for (ii=0; ii<line_count; ii++) { for (kk=0; kk<sample_count; kk++) { ASF_FREAD(&floatBuf[kk], sizeof(float), 1, fpIn); ieee_big32(floatBuf[kk]); if (floatBuf[kk] > 10000000000.0 || FLOAT_EQUIVALENT(floatBuf[kk], 10000000000.0)) floatBuf[kk] = MAGIC_UNSET_DOUBLE; } put_float_line(fpOut, meta, line_count-ii-1, floatBuf); } FCLOSE(fpOut); FREE(floatBuf); double lat1, lon1, lat2, lon2, lat3, lon3, lat4, lon4; proj_to_latlon(proj, x_map_ll*1000.0, y_map_ll*1000.0, 0.0, &lat1, &lon1, &height); proj_to_latlon(proj, x_map_ll*1000.0, y_map_ur*1000.0, 0.0, &lat2, &lon2, &height); proj_to_latlon(proj, x_map_ur*1000.0, y_map_ur*1000.0, 0.0, &lat3, &lon3, &height); proj_to_latlon(proj, x_map_ur*1000.0, y_map_ll*1000.0, 0.0, &lat4, &lon4, &height); westBoundLon = minValue(lon1*R2D, lon2*R2D, lon3*R2D, lon4*R2D); eastBoundLon = maxValue(lon1*R2D, lon2*R2D, lon3*R2D, lon4*R2D); northBoundLat = maxValue(lat1*R2D, lat2*R2D, lat3*R2D, lat4*R2D); southBoundLat = minValue(lat1*R2D, lat2*R2D, lat3*R2D, lat4*R2D); if (westBoundLon < minLon) minLon = westBoundLon; if (eastBoundLon > maxLon) maxLon = eastBoundLon; if (southBoundLat < minLat) minLat = southBoundLat; if (northBoundLat > maxLat) maxLat = northBoundLat; meta_free(meta); nFiles++; } FCLOSE(fpInList); fprintf(fpOutList, " </data>\n"); fprintf(fpOutList, " <metadata>\n"); fprintf(fpOutList, " <time>\n"); fprintf(fpOutList, " <axis type=\"string\" definition=\"name of axis\">T" "</axis>\n"); fprintf(fpOutList, " <long_name type=\"string\" definition=\"long " "descriptive name\">serial date</long_name>\n"); fprintf(fpOutList, " <references type=\"string\" definition=\"reference " "of the value\">start time of 3-day average</references>\n"); fprintf(fpOutList, " <standard_name type=\"string\" definition=\"name " "used to identify the physical quantity\">time</standard_name>\n"); fprintf(fpOutList, " <units type=\"string\" definition=\"unit of " "dimensional quantity\">seconds since %d-01-01T00:00:00Z</units>\n", firstYear); fprintf(fpOutList, " <bounds type=\"string\" definition=\"variable " "containing data range\">time_bounds</bounds>\n"); fprintf(fpOutList, " <FillValue type=\"double\" definition=\"default " "value\">0</FillValue>\n"); fprintf(fpOutList, " </time>\n"); fprintf(fpOutList, " <time_bounds>\n"); fprintf(fpOutList, " <long_name type=\"string\" definition=\"long " "descriptive name\">serial date</long_name>\n"); fprintf(fpOutList, " <references type=\"string\" definition=\"reference " "of the value\">start and end time of 3-day average</references>\n"); fprintf(fpOutList, " <standard_name type=\"string\" definition=\"name " "used to identify the physical quantity\">time</standard_name>\n"); fprintf(fpOutList, " <units type=\"string\" definition=\"unit of " "dimensional quantity\">seconds since %d-01-01T00:00:00Z</units>\n", firstYear); fprintf(fpOutList, " <FillValue type=\"double\" definition=\"default " "value\">0</FillValue>\n"); fprintf(fpOutList, " </time_bounds>\n"); fprintf(fpOutList, " <latitude>\n"); fprintf(fpOutList, " <long_name type=\"string\" definition=\"long " "descriptive name\">latitude</long_name>\n"); fprintf(fpOutList, " <standard_name type=\"string\" definition=\"name " "used to identify the physical quantity\">latitude</standard_name>\n"); fprintf(fpOutList, " <units type=\"string\" definition=\"unit of " "dimensional quantity\">degrees_north</units>\n"); fprintf(fpOutList, " <FillValue type=\"float\" definition=\"default " "value\">-999</FillValue>\n"); fprintf(fpOutList, " <valid_min type=\"float\" definition=\"minimum " "valid value\">-90.0</valid_min>\n"); fprintf(fpOutList, " <valid_max type=\"float\" definition=\"minimum " "valid value\">90.0</valid_max>\n"); fprintf(fpOutList, " </latitude>\n"); fprintf(fpOutList, " <longitude>\n"); fprintf(fpOutList, " <long_name type=\"string\" definition=\"long " "descriptive name\">longitude</long_name>\n"); fprintf(fpOutList, " <standard_name type=\"string\" definition=\"name " "used to identify the physical quantity\">longitude</standard_name>\n"); fprintf(fpOutList, " <units type=\"string\" definition=\"unit of " "dimensional quantity\">degrees_east</units>\n"); fprintf(fpOutList, " <FillValue type=\"float\" definition=\"default " "value\">-999</FillValue>\n"); fprintf(fpOutList, " <valid_min type=\"float\" definition=\"minimum " "valid value\">-180.0</valid_min>\n"); fprintf(fpOutList, " <valid_max type=\"float\" definition=\"minimum " "valid value\">180.0</valid_max>\n"); fprintf(fpOutList, " </longitude>\n"); fprintf(fpOutList, " <xgrid>\n"); fprintf(fpOutList, " <axis type=\"string\" definition=\"name of axis\">X" "</axis>\n"); fprintf(fpOutList, " <long_name type=\"string\" definition=\"long " "descriptive name\">projection_grid_x_center</long_name>\n"); fprintf(fpOutList, " <standard_name type=\"string\" definition=\"name " "used to identify the physical quantity\">projection_x_coordinate" "</standard_name>\n"); fprintf(fpOutList, " <units type=\"string\" definition=\"unit of " "dimensional quantity\">meters</units>\n"); fprintf(fpOutList, " <FillValue type=\"float\" definition=\"default " "value\">NaN</FillValue>\n"); fprintf(fpOutList, " </xgrid>\n"); fprintf(fpOutList, " <ygrid>\n"); fprintf(fpOutList, " <axis type=\"string\" definition=\"name of axis\">Y" "</axis>\n"); fprintf(fpOutList, " <long_name type=\"string\" definition=\"long " "descriptive name\">projection_grid_y_center</long_name>\n"); fprintf(fpOutList, " <standard_name type=\"string\" definition=\"name " "used to identify the physical quantity\">projection_y_coordinate" "</standard_name>\n"); fprintf(fpOutList, " <units type=\"string\" definition=\"unit of " "dimensional quantity\">meters</units>\n"); fprintf(fpOutList, " <FillValue type=\"float\" definition=\"default " "value\">NaN</FillValue>\n"); fprintf(fpOutList, " </ygrid>\n"); fprintf(fpOutList, " <Polar_Stereographic>\n"); fprintf(fpOutList, " <grid_mapping_name>polar_stereographic" "</grid_mapping_name>\n"); fprintf(fpOutList, " <straight_vertical_longitude_from_pole>%.1f" "</straight_vertical_longitude_from_pole>\n", pps.ps.slon); fprintf(fpOutList, " <longitude_of_central_meridian>90.0" "</longitude_of_central_meridian>\n"); fprintf(fpOutList, " <standard_parallel>%.1f</standard_parallel>\n", pps.ps.slat); fprintf(fpOutList, " <false_easting>%.1f</false_easting>\n", pps.ps.false_easting); fprintf(fpOutList, " <false_northing>%.1f</false_northing>\n", pps.ps.false_northing); fprintf(fpOutList, " <projection_x_coordinate>xgrid" "</projection_x_coordinate>\n"); fprintf(fpOutList, " <projection_y_coordinate>ygrid" "</projection_y_coordinate>\n"); fprintf(fpOutList, " <units>meters</units>\n"); fprintf(fpOutList, " </Polar_Stereographic>\n"); fprintf(fpOutList, " <mask>\n"); fprintf(fpOutList, " <coordinates type=\"string\" definition=\"" "coordinate reference\">ygrid xgrid</coordinates>\n"); fprintf(fpOutList, " <grid_mapping type=\"string\" definition=\"\">" "Polar_Stereographic</grid_mapping>\n"); fprintf(fpOutList, " <long_name type=\"string\" definition=\"long " "descriptive name\">projection_grid_y_center</long_name>\n"); fprintf(fpOutList, " <units type=\"string\" definition=\"unit of " "dimensional quantity\">1</units>\n"); fprintf(fpOutList, " <units_description type=\"string\" definition=\"" "descriptive information about dimensionless quantity\">unitless" "</units_description>\n"); fprintf(fpOutList, " <FillValue type=\"int\" definition=\"default " "value\">0</FillValue>\n"); fprintf(fpOutList, " </mask>\n"); if (myrFlag) { fprintf(fpOutList, " <multiyear_ice_fraction>\n"); fprintf(fpOutList, " <cell_methods type=\"string\" definition=\"" "characteristic of a field that is represented by cell values\">area: " "multiyear ice fraction value</cell_methods>\n"); fprintf(fpOutList, " <coordinates type=\"string\" definition=\"" "coordinate reference\">ygrid xgrid</coordinates>\n"); fprintf(fpOutList, " <grid_mapping type=\"string\" definition=\"\">" "Polar_Stereographic</grid_mapping>\n"); fprintf(fpOutList, " <long_name type=\"string\" definition=\"long " "descriptive name\">RGPS MEaSUREs multiyear ice fraction</long_name>\n"); fprintf(fpOutList, " <units type=\"string\" definition=\"unit of " "dimensional quantity\">1</units>\n"); fprintf(fpOutList, " <units_description type=\"string\" definition=\"" "descriptive information about dimensionless quantity\">unitless" "</units_description>\n"); fprintf(fpOutList, " <FillValue type=\"float\" definition=\"default " "value\">NaN</FillValue>\n"); fprintf(fpOutList, " </multiyear_ice_fraction>\n"); } if (divFlag) { fprintf(fpOutList, " <divergence>\n"); fprintf(fpOutList, " <cell_methods type=\"string\" definition=\"" "characteristic of a field that is represented by cell values\">area: " "divergence value</cell_methods>\n"); fprintf(fpOutList, " <coordinates type=\"string\" definition=\"" "coordinate reference\">ygrid xgrid</coordinates>\n"); fprintf(fpOutList, " <grid_mapping type=\"string\" definition=\"\">" "Polar_Stereographic</grid_mapping>\n"); fprintf(fpOutList, " <long_name type=\"string\" definition=\"long " "descriptive name\">RGPS MEaSUREs divergence</long_name>\n"); fprintf(fpOutList, " <units type=\"string\" definition=\"unit of " "dimensional quantity\">1</units>\n"); fprintf(fpOutList, " <units_description type=\"string\" definition=\"" "descriptive information about dimensionless quantity\">unitless" "</units_description>\n"); fprintf(fpOutList, " <FillValue type=\"float\" definition=\"default " "value\">NaN</FillValue>\n"); fprintf(fpOutList, " </divergence>\n"); } if (vrtFlag) { fprintf(fpOutList, " <vorticity>\n"); fprintf(fpOutList, " <cell_methods type=\"string\" definition=\"" "characteristic of a field that is represented by cell values\">area: " "vorticity value</cell_methods>\n"); fprintf(fpOutList, " <coordinates type=\"string\" definition=\"" "coordinate reference\">ygrid xgrid</coordinates>\n"); fprintf(fpOutList, " <grid_mapping type=\"string\" definition=\"\">" "Polar_Stereographic</grid_mapping>\n"); fprintf(fpOutList, " <long_name type=\"string\" definition=\"long " "descriptive name\">RGPS MEaSUREs vorticity</long_name>\n"); fprintf(fpOutList, " <units type=\"string\" definition=\"unit of " "dimensional quantity\">1</units>\n"); fprintf(fpOutList, " <units_description type=\"string\" definition=\"" "descriptive information about dimensionless quantity\">unitless" "</units_description>\n"); fprintf(fpOutList, " <FillValue type=\"float\" definition=\"default " "value\">NaN</FillValue>\n"); fprintf(fpOutList, " </vorticity>\n"); } if (shrFlag) { fprintf(fpOutList, " <shear>\n"); fprintf(fpOutList, " <cell_methods type=\"string\" definition=\"" "characteristic of a field that is represented by cell values\">area: " "shear value</cell_methods>\n"); fprintf(fpOutList, " <coordinates type=\"string\" definition=\"" "coordinate reference\">ygrid xgrid</coordinates>\n"); fprintf(fpOutList, " <grid_mapping type=\"string\" definition=\"\">" "Polar_Stereographic</grid_mapping>\n"); fprintf(fpOutList, " <long_name type=\"string\" definition=\"long " "descriptive name\">RGPS MEaSUREs shear</long_name>\n"); fprintf(fpOutList, " <units type=\"string\" definition=\"unit of " "dimensional quantity\">1</units>\n"); fprintf(fpOutList, " <units_description type=\"string\" definition=\"" "descriptive information about dimensionless quantity\">unitless" "</units_description>\n"); fprintf(fpOutList, " <FillValue type=\"float\" definition=\"default " "value\">NaN</FillValue>\n"); fprintf(fpOutList, " </shear>\n"); } fprintf(fpOutList, " </metadata>\n"); fprintf(fpOutList, " <parameter>\n"); if (myrFlag) fprintf(fpOutList, " <multiyear_ice_fraction type=\"float\"/>\n"); if (divFlag) fprintf(fpOutList, " <divergence type=\"float\"/>\n"); if (vrtFlag) fprintf(fpOutList, " <vorticity type=\"float\"/>\n"); if (shrFlag) fprintf(fpOutList, " <shear type=\"float\"/>\n"); fprintf(fpOutList, " </parameter>\n"); char startStr[15], endStr[15]; jdStart.year = firstYear; jdStart.jd = firstDay; jdEnd.year = endYear; jdEnd.jd = endDay; jd2date(&jdStart, startStr); jd2date(&jdEnd, endStr); if (firstYear != endYear || firstDay != endDay) sprintf(citation, "%s to %s", startStr, endStr); else sprintf(citation, "%s", startStr); fprintf(fpOutList, " <root>\n"); fprintf(fpOutList, " <Conventions>CF-1.6</Conventions>\n"); fprintf(fpOutList, " <institution>Alaska Satellite Facility</institution>\n"); fprintf(fpOutList, " <title>Kwok, Ron. 2008. MEaSUREs Small-Scale Kinematics" " of Arctic Ocean Sea Ice, Version 01, %s. Jet Propulsion Laboratory " "Pasadena, CA USA and Alaska Satellite Facility Fairbanks, AK USA. " "Digital media.</title>\n", citation); fprintf(fpOutList, " <source>Products derived from RADARSAT-1 SWB imagery at " "100 m resolution</source>\n"); fprintf(fpOutList, " <comment>Imagery the products are derived from: Copyright " "Canadian Space Agency (1996 to 2008)</comment>\n"); fprintf(fpOutList, " <reference>Documentation available at: www.asf.alaska.edu" "</reference>\n"); fprintf(fpOutList, " <history>%s: netCDF file created.</history>\n", isoStr); fprintf(fpOutList, " </root>\n"); fprintf(fpOutList, "</netcdf>\n"); FCLOSE(fpOutList); // Generate supplemental files: water mask, lat/lon, x/y grids asfPrintStatus("Generating supplemental files ...\n"); float *floatBuf = (float *) MALLOC(sizeof(float)*sample_count); float *maskBuf = (float *) MALLOC(sizeof(float)*sample_count); float *latBuf = (float *) MALLOC(sizeof(float)*sample_count); float *lonBuf = (float *) MALLOC(sizeof(float)*sample_count); float *xBuf = (float *) MALLOC(sizeof(float)*sample_count); float *yBuf = (float *) MALLOC(sizeof(float)*sample_count); meta = meta_read(metaFile); fpIn = FOPEN(inFile, "r"); fgets(header, 100, fpIn); sscanf(header, "%f %f %f %f %f %f", &x_pix, &y_pix, &x_map_ll, &y_map_ll, &x_map_ur, &y_map_ur); fgets(header, 100, fpIn); sscanf(header, "%d %d", &sample_count, &line_count); FILE *fpMask = FOPEN(maskFile, "wb"); FILE *fpLat = FOPEN(latFile, "wb"); FILE *fpLon = FOPEN(lonFile, "wb"); FILE *fpXgrid = FOPEN(xFile, "wb"); FILE *fpYgrid = FOPEN(yFile, "wb"); for (ii=0; ii<line_count; ii++) { for (kk=0; kk<sample_count; kk++) { ASF_FREAD(&floatBuf[kk], sizeof(float), 1, fpIn); ieee_big32(floatBuf[kk]); } for (kk=0; kk<sample_count; kk++) { meta_get_latLon(meta, line_count-ii-1, kk, 0.0, &lat, &lon); latlon_to_proj(meta->projection, 'R', lat*D2R, lon*D2R, 0.0, &x, &y, &z); latBuf[kk] = lat; lonBuf[kk] = lon; xBuf[kk] = x; yBuf[kk] = y; if (floatBuf[kk] < 10000000000.0) { maskBuf[kk] = 1.0; } else if (floatBuf[kk] > 10000000000.0) { maskBuf[kk] = 1.0; } else { maskBuf[kk] = 0.0; } } put_float_line(fpMask, meta, line_count-ii-1, maskBuf); put_float_line(fpLat, meta, line_count-ii-1, latBuf); put_float_line(fpLon, meta, line_count-ii-1, lonBuf); put_float_line(fpXgrid, meta, line_count-ii-1, xBuf); put_float_line(fpYgrid, meta, line_count-ii-1, yBuf); } FCLOSE(fpIn); FCLOSE(fpMask); FCLOSE(fpLat); FCLOSE(fpLon); FREE(floatBuf); FREE(maskBuf); FREE(latBuf); FREE(lonBuf); FREE(xBuf); FREE(yBuf); meta_write(meta, latFile); meta_write(meta, lonFile); meta_write(meta, xFile); meta_write(meta, yFile); // Write ISO meatadata for netCDF asfPrintStatus("Generating metadata for netCDF file ...\n"); char *ncXmlBase = get_basename(outFile); char *ncXmlFile = appendExt(outFile, ".xml"); fpXml = FOPEN(ncXmlFile, "w"); fprintf(fpXml, "<rgps>\n"); fprintf(fpXml, " <granule>%s</granule>\n", ncXmlBase); fprintf(fpXml, " <metadata_creation>%s</metadata_creation>\n", isoStr); fprintf(fpXml, " <metadata>\n"); fprintf(fpXml, " <product>\n"); fprintf(fpXml, " <file type=\"string\" definition=\"name of product " "file\">%s.nc</file>\n", ncXmlBase); if (divFlag && vrtFlag && shrFlag) fprintf(fpXml, " <type type=\"string\" definition=\"product type\">" "divergence, vorticity, shear</type>\n"); else if (myrFlag) fprintf(fpXml, " <type type=\"string\" definition=\"product type\">" "multiyear ice fraction</type>\n"); fprintf(fpXml, " <format type=\"string\" definition=\"name of the data " "format\">netCDF</format>\n"); fpInList = FOPEN(listInFile, "r"); while (fgets(inFile, 512, fpInList)) { chomp(inFile); split_dir_and_file(inFile, dirName, baseName); fprintf(fpXml, " <source type=\"string\" definition=\"name of the data" " source\">%s</source>\n", baseName); } FCLOSE(fpInList); fprintf(fpXml, " <cell_size_x type=\"double\" definition=\"cell size " "in x direction\" units=\"m\">%.2f</cell_size_x>\n", x_pix*1000.0); fprintf(fpXml, " <cell_size_y type=\"double\" definition=\"cell size " "in y direction\" units=\"m\">%.2f</cell_size_y>\n", y_pix*1000.0); fprintf(fpXml, " <map_x_lower_left type=\"double\" definition=\"x " "coordinate of lower left corner\" units=\"m\">%.6f</map_x_lower_left>\n", x_map_ll*1000.0); fprintf(fpXml, " <map_y_lower_left type=\"double\" definition=\"y " "coordinate of lower left corner\" units=\"m\">%.6f</map_y_lower_left>\n", y_map_ll*1000.0); fprintf(fpXml, " <map_x_upper_right type=\"double\" definition=\"x " "coordinate of upper right corner\" units=\"m\">%.6f</map_x_upper_right>" "\n", x_map_ur*1000.0); fprintf(fpXml, " <map_y_upper_right type=\"double\" definition=\"y " "coordinate of upper right corner\" units=\"m\">%.6f</map_y_upper_right>" "\n", y_map_ur*1000.0); fprintf(fpXml, " <cell_dimension_x type=\"int\" definition=\"cell " "dimension in x direction\">%d</cell_dimension_x>\n", sample_count); fprintf(fpXml, " <cell_dimension_y type=\"int\" definition=\"cell " "dimension in y direction\">%d</cell_dimension_y>\n", line_count); fprintf(fpXml, " <projection_string type=\"string\" definition=\"map " "projection information as well known text\">%s</projection_string>\n", meta2esri_proj(meta, NULL)); fprintf(fpXml, " </product>\n"); fprintf(fpXml, " </metadata>\n"); fprintf(fpXml, " <extent>\n"); fprintf(fpXml, " <product>\n"); fprintf(fpXml, " <westBoundLongitude>%.5f</westBoundLongitude>\n", minLon); fprintf(fpXml, " <eastBoundLongitude>%.5f</eastBoundLongitude>\n", maxLon); fprintf(fpXml, " <northBoundLatitude>%.5f</northBoundLatitude>\n", maxLat); fprintf(fpXml, " <southBoundLatitude>%.5f</southBoundLatitude>\n", minLat); fprintf(fpXml, " <start_datetime>%s</start_datetime>\n", first); fprintf(fpXml, " <end_datetime>%s</end_datetime>\n", end); fprintf(fpXml, " </product>\n"); fprintf(fpXml, " </extent>\n"); fprintf(fpXml, "</rgps>\n"); FCLOSE(fpXml); FREE(ncXmlBase); FREE(ncXmlFile); meta_free(meta); // Export to netCDF asfPrintStatus("Exporting to netCDF file ...\n"); export_netcdf_xml(listOutFile, outFile); // Clean up remove_dir(tmpDir); FREE(tmpDir); FREE(outFile); FREE(listInFile); FREE(isoStr); return 0; }
meta_parameters *read_meta_gridfloat_ext(char *inBaseName, char *flt_file, int *column_count, int *row_count) { // all three of these must be present char *hdr_file = appendExt(inBaseName, ".hdr"); char *prj_file = appendExt(inBaseName, ".prj"); flt_file = appendExt(inBaseName, ".flt"); if (!fileExists(flt_file) || !fileExists(hdr_file) || !fileExists(prj_file)) { asfPrintError( "The BIL and/or associated metadata files were not found:\n" " FLT File: %s %s\n" " PRJ File: %s %s\n" " HDR File: %s %s\n", flt_file, fileExists(flt_file) ? "Found" : "NOT FOUND", prj_file, fileExists(prj_file) ? "Found" : "NOT FOUND", hdr_file, fileExists(hdr_file) ? "Found" : "NOT FOUND"); } asfPrintStatus("Parsing %s ...\n", hdr_file); // Info we'll get from the header file int nrows=-1; int ncols=-1; double cell_size = 0; double lat_ll = -999; double lon_ll = -999; double nodata = -9999; int msbfirst = FALSE; // Read header file char line[1024], value[1024]; FILE *fp = FOPEN(hdr_file, "r"); while (NULL!=fgets(line, 1024, fp)) { if (matches(line, "ncols")) { get_value(line, value); ncols = atoi(value); } else if (matches(line, "nrows")) { get_value(line, value); nrows = atoi(value); } else if (matches(line, "xllcorner")) { get_value(line, value); lon_ll = atof(value); } else if (matches(line, "yllcorner")) { get_value(line, value); lat_ll = atof(value); } else if (matches(line, "cellsize")) { get_value(line, value); cell_size = atof(value); } else if (matches(line, "NODATA_value")) { get_value(line, value); nodata = atof(value); } else if (matches(line, "byteorder")) { get_value(line, value); if (strcmp(value, "LSBFIRST") == 0) { msbfirst = FALSE; } else if (strcmp(value, "MSBFIRST") == 0) { msbfirst = TRUE; } else { asfPrintError("Unsupported byte order (should be 'LSBFIRST' or 'MSBFIRST'): %s\n", value); } } } fclose(fp); if (nrows < 0 || ncols < 0) { asfPrintError( "Header file did not contain Row/Column infomation.\n" "It is a valid .HDR file?\n"); } // PRJ File asfPrintStatus("Parsing %s ...\n", prj_file); datum_type_t datum=UNKNOWN_DATUM; spheroid_type_t spheroid=UNKNOWN_SPHEROID; fp = FOPEN(prj_file, "r"); while (NULL!=fgets(line, 1024, fp)) { if (matches(line, "Projection")) { get_value(line, value); if (strcmp(value, "GEOGRAPHIC") != 0) asfPrintError("Unsupported byte order (should be GEOGRAPHIC): %s\n", value); } else if (matches(line, "Units")) { get_value(line, value); if (strcmp(value, "DD") != 0) asfPrintError("Unsupported Units (should be DD): %s\n", value); } else if (matches(line, "Zunits")) { get_value(line, value); if (strcmp(value, "METERS") != 0) asfPrintError("Unsupported Zunits (should be METERS): %s\n", value); } else if (matches(line, "Datum")) { get_value(line, value); if (strcmp_case(value, "NAD27") == 0) datum = NAD27_DATUM; else if (strcmp_case(value, "NAD83") == 0) datum = NAD83_DATUM; else if (strcmp_case(value, "WGS83") == 0) datum = WGS84_DATUM; else asfPrintError( "Unsupported Datum (should be NAD27, NAD83, or WGS84): %s\n", value); } else if (matches(line, "Spheroid")) { get_value(line, value); if (strcmp_case(value, "CLARKE1866") == 0) spheroid = CLARKE1866_SPHEROID; else if (strcmp_case(value, "BESSEL") == 0) spheroid = BESSEL_SPHEROID; else if (strcmp_case(value, "CLARKE1880") == 0) spheroid = CLARKE1880_SPHEROID; else if (strcmp_case(value, "GEM6") == 0) spheroid = GEM6_SPHEROID; else if (strcmp_case(value, "GEM10C") == 0) spheroid = GEM10C_SPHEROID; else if (strcmp_case(value, "GRS1980") == 0) spheroid = GRS1980_SPHEROID; else if (strcmp_case(value, "WGS72") == 0) spheroid = WGS72_SPHEROID; else if (strcmp_case(value, "WGS84") == 0) spheroid = WGS84_SPHEROID; else if (strcmp_case(value, "INTERNATIONAL1924") == 0) spheroid = INTERNATIONAL1924_SPHEROID; else if (strcmp_case(value, "INTERNATIONAL1967") == 0) spheroid = INTERNATIONAL1967_SPHEROID; else asfPrintError("Unsupported Spheroid: %s\n", value); } } fclose(fp); meta_parameters *meta = raw_init(); meta->projection = meta_projection_init(); meta->location = meta_location_init(); // aliases meta_general *mg = meta->general; meta_projection *mp = meta->projection; meta_location *ml = meta->location; // populate general block info mg->data_type = REAL32; mg->image_data_type = DEM; //presumably!? mg->no_data = nodata; // these are supposed to be in meters // currently, cell_size_* is in arcsecs... so here is a kludgey // calculation, to round to the nearest 10m. usgs data is either // 30, 60, or 90 meter. // Note that the projection block will have the actual pixel size int cell_size_m = 10 * (int)(11131.95 * cell_size + .5); if (cell_size_m != 30 && cell_size_m != 60 && cell_size_m != 90) { asfPrintWarning("Unexpected pixel size of %dm (%.10f degree) detected.\n" "USGS Seamless data should be 30, 60, or 90 meter.\n", cell_size_m, cell_size); } mg->x_pixel_size = cell_size_m; mg->y_pixel_size = cell_size_m; mg->line_count = nrows; mg->sample_count = ncols; mg->band_count = 1; mg->start_line = 0; mg->start_sample = 0; char *basename = get_basename(inBaseName); strcpy(mg->basename, basename); free(basename); strcpy(mg->sensor, "USGS Seamless data (e.g., NED, STRM)"); strcpy(mg->mode, "N/A"); strcpy(mg->processor, "Unknown"); mg->center_latitude = lat_ll + cell_size * ncols / 2.0; mg->center_longitude = lon_ll + cell_size * nrows / 2.0; // populate projection block info mp->type = LAT_LONG_PSEUDO_PROJECTION; mp->startX = lon_ll; mp->startY = lat_ll + cell_size * nrows; mp->perX = cell_size; mp->perY = -cell_size; strcpy(mp->units, "degrees"); mp->hem = mg->center_latitude > 0 ? 'N' : 'S'; // the datum for NED is NAD83, for SRTM it is WGS84 mp->datum = datum; mp->spheroid = spheroid; spheroid_axes_lengths(spheroid, &mg->re_major, &mg->re_minor); mp->re_major = mg->re_major; mp->re_minor = mg->re_minor; // location block ml->lon_start_near_range = mp->startX; ml->lat_start_near_range = mp->startY; ml->lon_start_far_range = mp->startX + mp->perX * ncols; ml->lat_start_far_range = mp->startY; ml->lon_end_near_range = mp->startX; ml->lat_end_near_range = mp->startY + mp->perY * nrows; ml->lon_end_far_range = mp->startX + mp->perX * ncols; ml->lat_end_far_range = mp->startY + mp->perY * nrows; free(hdr_file); free(prj_file); *column_count = ncols; *row_count = nrows; return meta; }
int geocode_dem (projection_type_t projection_type, // What we are projection to. project_parameters_t *pp, // Parameters we project to. datum_type_t datum, // Datum we project to. // Pixel size of output image, in output projection units // (meters or possibly degrees, if we decide to support // projecting to pseudoprojected form). double pixel_size, resample_method_t resample_method, // How to resample pixels. const char *input_image, // Base name of input image. const meta_parameters *imd, // Input DEM image metadata. const char *output_image // Base name of output image. ) { int return_code; // Holds return codes from functions. // Function to use to project or unproject between latlon and input // or output coordinates. projector_t project_input; // latlon => input image map projection projector_t unproject_input; // input image_map_projection => latlon projector_t project_output; // latlon => output image map projection projector_t unproject_output; // output image map projection => latlon // Like the above, but act on arrays. array_projector_t array_project_input, array_unproject_input; array_projector_t array_project_output, array_unproject_output; // We only deal with reprojection map projected DEMs. g_assert (imd->projection != NULL); // FIXME: what to do with background value is something that still // needs to be determined (probably in consultation with the guys // working on terrain correction). const float background_value = 0.0; // Geocoding to pseudoprojected form presents issues, for example // with the meaning of the pixel_size argument, which is taken as a // distance in map projection coordinates for all other projections // (deciding how to interpret it when projecting to pseudoprojected // form is tough), and since there probably isn't much need, we // don't allow it. g_assert (projection_type != LAT_LONG_PSEUDO_PROJECTION); // Get the functions we want to use for projecting and unprojecting. set_projection_functions (imd->projection->type, &project_input, &unproject_input, &array_project_input, &array_unproject_input); set_projection_functions (projection_type, &project_output, &unproject_output, &array_project_output, &array_unproject_output); // Input image dimensions in pixels in x and y directions. size_t ii_size_x = imd->general->sample_count; size_t ii_size_y = imd->general->line_count; // Convenience aliases. meta_projection *ipb = imd->projection; project_parameters_t *ipp = &imd->projection->param; // First we march around the entire outside of the image and compute // projection coordinates for every pixel, keeping track of the // minimum and maximum projection coordinates in each dimension. // This lets us determine the exact extent of the DEM in // output projection coordinates. asfPrintStatus ("Determining input image extent in projection coordinate " "space... "); double min_x = DBL_MAX; double max_x = -DBL_MAX; double min_y = DBL_MAX; double max_y = -DBL_MAX; // In going around the edge, we are just trying to determine the // extent of the image in the horizontal, so we don't care about // height yet. { // Scoping block. // Number of pixels in the edge of the image. size_t edge_point_count = 2 * ii_size_x + 2 * ii_size_y - 4; double *lats = g_new0 (double, edge_point_count); double *lons = g_new0 (double, edge_point_count); size_t current_edge_point = 0; size_t ii = 0, jj = 0; for ( ; ii < ii_size_x - 1 ; ii++ ) { return_code = get_pixel_lat_long (imd, unproject_input, ii, jj, &(lats[current_edge_point]), &(lons[current_edge_point])); g_assert (return_code); current_edge_point++; } for ( ; jj < ii_size_y - 1 ; jj++ ) { return_code = get_pixel_lat_long (imd, unproject_input, ii, jj, &(lats[current_edge_point]), &(lons[current_edge_point])); g_assert (return_code); current_edge_point++; } for ( ; ii > 0 ; ii-- ) { return_code = get_pixel_lat_long (imd, unproject_input, ii, jj, &(lats[current_edge_point]), &(lons[current_edge_point])); g_assert (return_code); current_edge_point++; } for ( ; jj > 0 ; jj-- ) { return_code = get_pixel_lat_long (imd, unproject_input, ii, jj, &(lats[current_edge_point]), &(lons[current_edge_point])); g_assert (return_code); current_edge_point++; } g_assert (current_edge_point == edge_point_count); // Pointers to arrays of projected coordinates to be filled in. // The projection function will allocate this memory itself. double *x = NULL, *y = NULL; // Project all the edge pixels. return_code = array_project_output (pp, lats, lons, NULL, &x, &y, NULL, edge_point_count, datum); g_assert (return_code == TRUE); // Find the extents of the image in projection coordinates. for ( ii = 0 ; ii < edge_point_count ; ii++ ) { if ( x[ii] < min_x ) { min_x = x[ii]; } if ( x[ii] > max_x ) { max_x = x[ii]; } if ( y[ii] < min_y ) { min_y = y[ii]; } if ( y[ii] > max_y ) { max_y = y[ii]; } } free (y); free (x); g_free (lons); g_free (lats); } asfPrintStatus ("done.\n\n"); // Issue a warning when the chosen pixel size is smaller than the // input pixel size. FIXME: this condition will really never fire // for pseudoprojected image, since the pixels size of the input is // tiny (degrees per pixel) and the pixel_size has already been // computed in asf_geocode function itself as an arc length on the // ground. if ( GSL_MIN(imd->general->x_pixel_size, imd->general->y_pixel_size) > pixel_size ) { asfPrintWarning ("Requested pixel size %f is smaller then the input image resolution " "(%le meters).\n", pixel_size, GSL_MIN (imd->general->x_pixel_size, imd->general->y_pixel_size)); } // The pixel size requested by the user better not oversample by the // factor of 2. Specifying --force will skip this check. FIXME: // same essential problem as the above condition, but in this case // it always goes off. // if (!force_flag && GSL_MIN(imd->general->x_pixel_size, // imd->general->y_pixel_size) > (2*pixel_size) ) { // report_func // ("Requested pixel size %f is smaller then the minimum implied by half \n" // "the input image resolution (%le meters), this is not supported.\n", // pixel_size, GSL_MIN (imd->general->x_pixel_size, // imd->general->y_pixel_size)); // } asfPrintStatus ("Opening input DEM image... "); char *input_data_file = (char *) MALLOC(sizeof(char)*(strlen(input_image)+5)); sprintf(input_data_file, "%s.img", input_image); FloatImage *iim = float_image_new_from_file (ii_size_x, ii_size_y, input_data_file, 0, FLOAT_IMAGE_BYTE_ORDER_BIG_ENDIAN); FREE(input_data_file); asfPrintStatus ("done.\n\n"); // Maximum pixel indicies in output image. size_t oix_max = ceil ((max_x - min_x) / pixel_size); size_t oiy_max = ceil ((max_y - min_y) / pixel_size); // Output image dimensions. size_t oi_size_x = oix_max + 1; size_t oi_size_y = oiy_max + 1; // Output image. FloatImage *oim = float_image_new (oi_size_x, oi_size_y); // Translate the command line notion of the resampling method into // the lingo known by the float_image class. The compiler is // reassured with a default. float_image_sample_method_t float_image_sample_method = FLOAT_IMAGE_SAMPLE_METHOD_BILINEAR; switch ( resample_method ) { case RESAMPLE_NEAREST_NEIGHBOR: float_image_sample_method = FLOAT_IMAGE_SAMPLE_METHOD_NEAREST_NEIGHBOR; break; case RESAMPLE_BILINEAR: float_image_sample_method = FLOAT_IMAGE_SAMPLE_METHOD_BILINEAR; break; case RESAMPLE_BICUBIC: float_image_sample_method = FLOAT_IMAGE_SAMPLE_METHOD_BICUBIC; break; default: g_assert_not_reached (); } // We need to find the z coordinates in the output projection of all // the pixels in the input DEM. We store these values in their own // FloatImage instance. //FloatImage *x_coords = float_image_new (ii_size_x, ii_size_y); //FloatImage *y_coords = float_image_new (ii_size_x, ii_size_y); FloatImage *z_coords = float_image_new (ii_size_x, ii_size_y); // We transform the points using the array transformation function // for efficiency, but we don't want to do them all at once, since // that would require huge gobs of memory. const size_t max_transform_chunk_pixels = 5000000; size_t rows_per_chunk = max_transform_chunk_pixels / ii_size_x; size_t chunk_pixels = rows_per_chunk * ii_size_x; double *chunk_x = g_new0 (double, chunk_pixels); double *chunk_y = g_new0 (double, chunk_pixels); double *chunk_z = g_new0 (double, chunk_pixels); double *lat = g_new0 (double, chunk_pixels); double *lon = g_new0 (double, chunk_pixels); double *height = g_new0 (double, chunk_pixels); asfPrintStatus ("Determining Z coordinates of input pixels in output " "projection space... "); // Transform all the chunks, storing results in the z coordinate image. size_t ii, jj, kk; // Index variables. for ( ii = 0 ; ii < ii_size_y ; ) { size_t rows_remaining = ii_size_y - ii; size_t rows_to_load = rows_per_chunk < rows_remaining ? rows_per_chunk : rows_remaining; for ( jj = 0 ; jj < rows_to_load ; jj++ ) { size_t current_image_row = ii + jj; for ( kk = 0 ; kk < ii_size_x ; kk++ ) { size_t current_chunk_pixel = jj * ii_size_x + kk; chunk_x[current_chunk_pixel] = ipb->startX + kk * ipb->perX; chunk_y[current_chunk_pixel] = ipb->startY + current_image_row * ipb->perY; if ( imd->projection->type == LAT_LONG_PSEUDO_PROJECTION ) { chunk_x[current_chunk_pixel] *= D2R; chunk_y[current_chunk_pixel] *= D2R; } chunk_z[current_chunk_pixel] = float_image_get_pixel (iim, kk, current_image_row); } } long current_chunk_pixels = rows_to_load * ii_size_x; array_unproject_input (ipp, chunk_x, chunk_y, chunk_z, &lat, &lon, &height, current_chunk_pixels, ipb->datum); array_project_output (pp, lat, lon, height, &chunk_x, &chunk_y, &chunk_z, current_chunk_pixels, datum); for ( jj = 0 ; jj < rows_to_load ; jj++ ) { size_t current_image_row = ii + jj; for ( kk = 0 ; kk < ii_size_x ; kk++ ) { size_t current_chunk_pixel = jj * ii_size_x + kk; // Current pixel x, y, z coordinates. //float cp_x = (float) chunk_x[current_chunk_pixel]; //float cp_y = (float) chunk_y[current_chunk_pixel]; float cp_z = (float) chunk_z[current_chunk_pixel]; //float_image_set_pixel (x_coords, kk, current_image_row, cp_x); //float_image_set_pixel (y_coords, kk, current_image_row, cp_y); float_image_set_pixel (z_coords, kk, current_image_row, cp_z); } } ii += rows_to_load; } asfPrintStatus ("done.\n\n"); #ifdef DEBUG_GEOCODE_DEM_Z_COORDS_IMAGE_AS_JPEG // Take a look at the z_coordinate image (for debugging). float_image_export_as_jpeg_with_mask_interval (z_coords, "z_coords.jpg", GSL_MAX (z_coords->size_x, z_coords->size_y), -FLT_MAX, -100); #endif g_free (chunk_x); g_free (chunk_y); g_free (chunk_z); g_free (lat); g_free (lon); g_free (height); // Now we want to determine the pixel coordinates in the input which // correspond to each of the output pixels. We can then sample the // new height value already computed for that input pixel to // determine the pixel value to use as output. // We want to proceed in chunks as we did when going in the other // direction. rows_per_chunk = max_transform_chunk_pixels / oi_size_x; chunk_pixels = rows_per_chunk * oi_size_x; chunk_x = g_new0 (double, chunk_pixels); chunk_y = g_new0 (double, chunk_pixels); // We don't have height information in this direction, nor do we care. chunk_z = NULL; lat = g_new0 (double, chunk_pixels); lon = g_new0 (double, chunk_pixels); // We don't have height information in this direction, nor do we care. height = NULL; asfPrintStatus ("Sampling Z coordinates to form pixels in output projection " "space... "); // Transform all the chunks, using the results to form the output image. for ( ii = 0 ; ii < oi_size_y ; ) { size_t rows_remaining = oi_size_y - ii; size_t rows_to_load = rows_per_chunk < rows_remaining ? rows_per_chunk : rows_remaining; for ( jj = 0 ; jj < rows_to_load ; jj++ ) { size_t current_image_row = ii + jj; for ( kk = 0 ; kk < oi_size_x ; kk++ ) { size_t current_chunk_pixel = jj * oi_size_x + kk; chunk_x[current_chunk_pixel] = min_x + kk * pixel_size; chunk_y[current_chunk_pixel] = max_y - current_image_row * pixel_size; } } long current_chunk_pixels = rows_to_load * oi_size_x; array_unproject_output (pp, chunk_x, chunk_y, NULL, &lat, &lon, NULL, current_chunk_pixels, datum); array_project_input (ipp, lat, lon, NULL, &chunk_x, &chunk_y, NULL, current_chunk_pixels, ipb->datum); if ( imd->projection->type == LAT_LONG_PSEUDO_PROJECTION ) { ssize_t ll; // For (semi)clarity we don't reuse index variable :) for ( ll = 0 ; ll < current_chunk_pixels ; ll++ ) { chunk_x[ll] *= R2D; chunk_y[ll] *= R2D; } } for ( jj = 0 ; jj < rows_to_load ; jj++ ) { size_t current_image_row = ii + jj; for ( kk = 0 ; kk < oi_size_x ; kk++ ) { size_t current_chunk_pixel = jj * oi_size_x + kk; // Compute pixel coordinates in input image. ssize_t in_x = (chunk_x[current_chunk_pixel] - ipb->startX) / ipb->perX; ssize_t in_y = (chunk_y[current_chunk_pixel] - ipb->startY) / ipb->perY; if ( in_image (z_coords, in_x, in_y) ) { // FIXME: something needs to be done somewhere about // propogating no data values. float_image_set_pixel (oim, kk, current_image_row, float_image_sample (z_coords, in_x, in_y, resample_method)); } else { float_image_set_pixel (oim, kk, current_image_row, background_value); } } } ii += rows_to_load; } asfPrintStatus ("done.\n\n"); g_free (chunk_x); g_free (chunk_y); g_free (lat); g_free (lon); #ifdef DEBUG_GEOCODE_DEM_OUTPUT_IMAGE_AS_JPEG // Take a look at the output image (for debugging). float_image_export_as_jpeg_with_mask_interval (oim, "oim.jpg", GSL_MAX (oim->size_x, oim->size_y), -FLT_MAX, -100); #endif // Store the output image. asfPrintStatus ("Storing output image... "); char *output_data_file = (char *) MALLOC(sizeof(char)*(strlen(output_image)+5)); sprintf(output_data_file, "%s.img", output_image); return_code = float_image_store (oim, output_data_file, FLOAT_IMAGE_BYTE_ORDER_BIG_ENDIAN); g_assert (return_code == 0); asfPrintStatus ("done.\n\n"); // Now we need some metadata for the output image. We will just // start with the metadata from the input image and add the // geocoding parameters. char *input_meta_file = (char *) MALLOC(sizeof(char)*(strlen(input_image)+6)); sprintf(input_meta_file, "%s.meta", input_image); char *output_meta_file = (char *) MALLOC(sizeof(char)*(strlen(output_image)+6)); sprintf(output_meta_file, "%s.meta", output_image); meta_parameters *omd = meta_read (input_meta_file); // Adjust the metadata to correspond to the output image instead of // the input image. omd->general->x_pixel_size = pixel_size; omd->general->y_pixel_size = pixel_size; omd->general->line_count = oi_size_y; omd->general->sample_count = oi_size_x; // SAR block is not really appropriate for map projected images, but // since it ended up with this value that can signify map // projectedness in it somehow, we fill it in for safety. omd->sar->image_type = 'P'; // Note that we have already verified that the input image is // projected, and since we initialize the output metadata from there // we know we will have a projection block. omd->projection->type = projection_type; omd->projection->startX = min_x; omd->projection->startY = max_y; omd->projection->perX = pixel_size; omd->projection->perY = -pixel_size; strcpy (omd->projection->units, "meters"); // Set the spheroid axes lengths as appropriate for the output datum. spheroid_axes_lengths (datum_spheroid (datum), &(omd->projection->re_major), &(omd->projection->re_minor)); // What the heck, might as well set the ones in the general block as // well. spheroid_axes_lengths (datum_spheroid (datum), &(omd->general->re_major), &(omd->general->re_minor)); // Latitude and longitude at center of the output image. We will // set these relative to the spheroid underlying the datum in use // for the projected image. Yeah, that seems appropriate. double lat_0, lon_0; double center_x = omd->projection->startX + (omd->projection->perX * omd->general->line_count / 2); double center_y = (omd->projection->startY + (omd->projection->perY * omd->general->sample_count / 2)); unproject_output (pp, center_x, center_y, ASF_PROJ_NO_HEIGHT, &lat_0, &lon_0, NULL, datum); omd->general->center_latitude = R2D * lat_0; omd->general->center_longitude = R2D * lon_0; // FIXME: We are ignoring the meta_location fields for now since I'm // not sure whether they are supposed to refer to the corner pixels // or the corners of the data itself. if ( lat_0 > 0.0 ) { omd->projection->hem = 'N'; } else { omd->projection->hem = 'S'; } // Convert the projection parameter values back into degrees. to_degrees (projection_type, pp); omd->projection->param = *pp; meta_write (omd, output_meta_file); float_image_free (oim); FREE(output_data_file); meta_free (omd); FREE(input_meta_file); FREE(output_meta_file); return 0; }