int USGSDEMDataset::LoadFromFile(VSILFILE *InDem) { // check for version of DEM format CPL_IGNORE_RET_VAL(VSIFSeekL(InDem, 864, 0)); // Read DEM into matrix const int nRow = ReadInt(InDem); const int nColumn = ReadInt(InDem); const bool bNewFormat = VSIFTellL(InDem) >= 1024 || nRow != 1 || nColumn != 1; if (bNewFormat) { CPL_IGNORE_RET_VAL(VSIFSeekL(InDem, 1024, 0)); // New Format int i = ReadInt(InDem); int j = ReadInt(InDem); if ( i != 1 || ( j != 1 && j != 0 ) ) // File OK? { CPL_IGNORE_RET_VAL(VSIFSeekL(InDem, 893, 0)); // Undocumented Format (39109h1.dem) i = ReadInt(InDem); j = ReadInt(InDem); if ( i != 1 || j != 1 ) // File OK? { CPLError( CE_Failure, CPLE_AppDefined, "Does not appear to be a USGS DEM file." ); return FALSE; } else nDataStartOffset = 893; } else nDataStartOffset = 1024; } else nDataStartOffset = 864; CPL_IGNORE_RET_VAL(VSIFSeekL(InDem, 156, 0)); const int nCoordSystem = ReadInt(InDem); const int iUTMZone = ReadInt(InDem); CPL_IGNORE_RET_VAL(VSIFSeekL(InDem, 528, 0)); const int nGUnit = ReadInt(InDem); const int nVUnit = ReadInt(InDem); // Vertical Units in meters if (nVUnit==1) pszUnits = "ft"; else pszUnits = "m"; CPL_IGNORE_RET_VAL(VSIFSeekL(InDem, 816, 0)); const double dxdelta = DConvert(InDem, 12); const double dydelta = DConvert(InDem, 12); if( dydelta == 0 ) return FALSE; fVRes = DConvert(InDem, 12); /* -------------------------------------------------------------------- */ /* Should we treat this as floating point, or GInt16. */ /* -------------------------------------------------------------------- */ if (nVUnit==1 || fVRes < 1.0) eNaturalDataFormat = GDT_Float32; else eNaturalDataFormat = GDT_Int16; /* -------------------------------------------------------------------- */ /* Read four corner coordinates. */ /* -------------------------------------------------------------------- */ CPL_IGNORE_RET_VAL(VSIFSeekL(InDem, 546, 0)); DPoint2 corners[4]; // SW, NW, NE, SE for (int i = 0; i < 4; i++) { corners[i].x = DConvert(InDem, 24); corners[i].y = DConvert(InDem, 24); } // find absolute extents of raw vales DPoint2 extent_min, extent_max; extent_min.x = std::min(corners[0].x, corners[1].x); extent_max.x = std::max(corners[2].x, corners[3].x); extent_min.y = std::min(corners[0].y, corners[3].y); extent_max.y = std::max(corners[1].y, corners[2].y); /* dElevMin = */ DConvert(InDem, 48); /* dElevMax = */ DConvert(InDem, 48); CPL_IGNORE_RET_VAL(VSIFSeekL(InDem, 858, 0)); const int nProfiles = ReadInt(InDem); /* -------------------------------------------------------------------- */ /* Collect the spatial reference system. */ /* -------------------------------------------------------------------- */ OGRSpatialReference sr; bool bNAD83 = true; // OLD format header ends at byte 864 if (bNewFormat) { // year of data compilation CPL_IGNORE_RET_VAL(VSIFSeekL(InDem, 876, 0)); char szDateBuffer[5]; CPL_IGNORE_RET_VAL(VSIFReadL(szDateBuffer, 4, 1, InDem)); /* szDateBuffer[4] = 0; */ // Horizontal datum // 1=North American Datum 1927 (NAD 27) // 2=World Geodetic System 1972 (WGS 72) // 3=WGS 84 // 4=NAD 83 // 5=Old Hawaii Datum // 6=Puerto Rico Datum CPL_IGNORE_RET_VAL(VSIFSeekL(InDem, 890, 0)); char szHorzDatum[3]; CPL_IGNORE_RET_VAL(VSIFReadL( szHorzDatum, 1, 2, InDem )); szHorzDatum[2] = '\0'; const int datum = atoi(szHorzDatum); switch (datum) { case 1: sr.SetWellKnownGeogCS( "NAD27" ); bNAD83 = false; break; case 2: sr.SetWellKnownGeogCS( "WGS72" ); break; case 3: sr.SetWellKnownGeogCS( "WGS84" ); break; case 4: sr.SetWellKnownGeogCS( "NAD83" ); break; case -9: break; default: sr.SetWellKnownGeogCS( "NAD27" ); break; } } else { sr.SetWellKnownGeogCS( "NAD27" ); bNAD83 = false; } if (nCoordSystem == 1) // UTM { if( iUTMZone >= -60 && iUTMZone <= 60 ) { sr.SetUTM( abs(iUTMZone), iUTMZone >= 0 ); if( nGUnit == 1 ) { sr.SetLinearUnitsAndUpdateParameters( SRS_UL_US_FOOT, CPLAtof(SRS_UL_US_FOOT_CONV) ); char szUTMName[128]; snprintf( szUTMName, sizeof(szUTMName), "UTM Zone %d, Northern Hemisphere, us-ft", iUTMZone ); sr.SetNode( "PROJCS", szUTMName ); } } } else if (nCoordSystem == 2) // state plane { if( nGUnit == 1 ) sr.SetStatePlane( iUTMZone, bNAD83, "Foot", CPLAtof(SRS_UL_US_FOOT_CONV) ); else sr.SetStatePlane( iUTMZone, bNAD83 ); } sr.exportToWkt( &pszProjection ); /* -------------------------------------------------------------------- */ /* For UTM we use the extents (really the UTM coordinates of */ /* the lat/long corners of the quad) to determine the size in */ /* pixels and lines, but we have to make the anchors be modulus */ /* the pixel size which what really gets used. */ /* -------------------------------------------------------------------- */ if (nCoordSystem == 1 // UTM || nCoordSystem == 2 // State Plane || nCoordSystem == -9999 ) // unknown { // expand extents modulus the pixel size. extent_min.y = floor(extent_min.y/dydelta) * dydelta; extent_max.y = ceil(extent_max.y/dydelta) * dydelta; // Forcibly compute X extents based on first profile and pixelsize. CPL_IGNORE_RET_VAL(VSIFSeekL(InDem, nDataStartOffset, 0)); /* njunk = */ ReadInt(InDem); /* njunk = */ ReadInt(InDem); /* njunk = */ ReadInt(InDem); /* njunk = */ ReadInt(InDem); const double dxStart = DConvert(InDem, 24); nRasterYSize = static_cast<int>( ( extent_max.y - extent_min.y ) / dydelta + 1.5 ); nRasterXSize = nProfiles; adfGeoTransform[0] = dxStart - dxdelta/2.0; adfGeoTransform[1] = dxdelta; adfGeoTransform[2] = 0.0; adfGeoTransform[3] = extent_max.y + dydelta/2.0; adfGeoTransform[4] = 0.0; adfGeoTransform[5] = -dydelta; } /* -------------------------------------------------------------------- */ /* Geographic -- use corners directly. */ /* -------------------------------------------------------------------- */ else { nRasterYSize = static_cast<int>( ( extent_max.y - extent_min.y ) / dydelta + 1.5 ); nRasterXSize = nProfiles; // Translate extents from arc-seconds to decimal degrees. adfGeoTransform[0] = (extent_min.x - dxdelta/2.0) / 3600.0; adfGeoTransform[1] = dxdelta / 3600.0; adfGeoTransform[2] = 0.0; adfGeoTransform[3] = (extent_max.y + dydelta/2.0) / 3600.0; adfGeoTransform[4] = 0.0; adfGeoTransform[5] = (-dydelta) / 3600.0; } if (!GDALCheckDatasetDimensions(nRasterXSize, nRasterYSize)) { return FALSE; } return TRUE; }
int USGSDEMDataset::LoadFromFile(FILE *InDem) { int i, j; int nRow, nColumn; int nVUnit, nGUnit; double dxdelta, dydelta; double dElevMax, dElevMin; int bNewFormat; int nCoordSystem; int nProfiles; char szDateBuffer[5]; DPoint2 corners[4]; // SW, NW, NE, SE DPoint2 extent_min, extent_max; int iUTMZone; // check for version of DEM format VSIFSeek(InDem, 864, 0); // Read DEM into matrix fscanf(InDem, "%d", &nRow); fscanf(InDem, "%d", &nColumn); bNewFormat = ((nRow!=1)||(nColumn!=1)); if (bNewFormat) { VSIFSeek(InDem, 1024, 0); // New Format fscanf(InDem, "%d", &i); fscanf(InDem, "%d", &j); if ((i!=1)||(j!=1 && j != 0)) // File OK? { VSIFSeek(InDem, 893, 0); // Undocumented Format (39109h1.dem) fscanf(InDem, "%d", &i); fscanf(InDem, "%d", &j); if ((i!=1)||(j!=1)) // File OK? { CPLError( CE_Failure, CPLE_AppDefined, "Does not appear to be a USGS DEM file." ); return FALSE; } else nDataStartOffset = 893; } else nDataStartOffset = 1024; } else nDataStartOffset = 864; VSIFSeek(InDem, 156, 0); fscanf(InDem, "%d", &nCoordSystem); fscanf(InDem, "%d", &iUTMZone); VSIFSeek(InDem, 528, 0); fscanf(InDem, "%d", &nGUnit); fscanf(InDem, "%d", &nVUnit); // Vertical Units in meters if (nVUnit==1) pszUnits = "ft"; else pszUnits = "m"; VSIFSeek(InDem, 816, 0); dxdelta = DConvert(InDem, 12); dydelta = DConvert(InDem, 12); fVRes = DConvert(InDem, 12); /* -------------------------------------------------------------------- */ /* Should we treat this as floating point, or GInt16. */ /* -------------------------------------------------------------------- */ if (nVUnit==1 || fVRes < 1.0) eNaturalDataFormat = GDT_Float32; else eNaturalDataFormat = GDT_Int16; /* -------------------------------------------------------------------- */ /* Read four corner coordinates. */ /* -------------------------------------------------------------------- */ VSIFSeek(InDem, 546, 0); for (i = 0; i < 4; i++) { corners[i].x = DConvert(InDem, 24); corners[i].y = DConvert(InDem, 24); } // find absolute extents of raw vales extent_min.x = MIN(corners[0].x, corners[1].x); extent_max.x = MAX(corners[2].x, corners[3].x); extent_min.y = MIN(corners[0].y, corners[3].y); extent_max.y = MAX(corners[1].y, corners[2].y); dElevMin = DConvert(InDem, 48); dElevMax = DConvert(InDem, 48); VSIFSeek(InDem, 858, 0); fscanf(InDem, "%d", &nProfiles); /* -------------------------------------------------------------------- */ /* Collect the spatial reference system. */ /* -------------------------------------------------------------------- */ OGRSpatialReference sr; int bNAD83 =TRUE; // OLD format header ends at byte 864 if (bNewFormat) { char szHorzDatum[3]; // year of data compilation VSIFSeek(InDem, 876, 0); fread(szDateBuffer, 4, 1, InDem); szDateBuffer[4] = 0; // Horizontal datum // 1=North American Datum 1927 (NAD 27) // 2=World Geodetic System 1972 (WGS 72) // 3=WGS 84 // 4=NAD 83 // 5=Old Hawaii Datum // 6=Puerto Rico Datum int datum; VSIFSeek(InDem, 890, 0); VSIFRead( szHorzDatum, 1, 2, InDem ); szHorzDatum[2] = '\0'; datum = atoi(szHorzDatum); switch (datum) { case 1: sr.SetWellKnownGeogCS( "NAD27" ); bNAD83 = FALSE; break; case 2: sr.SetWellKnownGeogCS( "WGS72" ); break; case 3: sr.SetWellKnownGeogCS( "WGS84" ); break; case 4: sr.SetWellKnownGeogCS( "NAD83" ); break; case -9: break; default: sr.SetWellKnownGeogCS( "NAD27" ); break; } } else { sr.SetWellKnownGeogCS( "NAD27" ); bNAD83 = FALSE; } if (nCoordSystem == 1) // UTM sr.SetUTM( iUTMZone, TRUE ); else if (nCoordSystem == 2) // state plane { if( nGUnit == 1 ) sr.SetStatePlane( iUTMZone, bNAD83, "Foot", CPLAtof(SRS_UL_US_FOOT_CONV) ); else sr.SetStatePlane( iUTMZone, bNAD83 ); } sr.exportToWkt( &pszProjection ); /* -------------------------------------------------------------------- */ /* For UTM we use the extents (really the UTM coordinates of */ /* the lat/long corners of the quad) to determine the size in */ /* pixels and lines, but we have to make the anchors be modulus */ /* the pixel size which what really gets used. */ /* -------------------------------------------------------------------- */ if (nCoordSystem == 1 // UTM || nCoordSystem == 2 // State Plane || nCoordSystem == -9999 ) // unknown { int njunk; double dxStart; // expand extents modulus the pixel size. extent_min.y = floor(extent_min.y/dydelta) * dydelta; extent_max.y = ceil(extent_max.y/dydelta) * dydelta; // Forceably compute X extents based on first profile and pixelsize. VSIFSeek(InDem, nDataStartOffset, 0); fscanf(InDem, "%d", &njunk); fscanf(InDem, "%d", &njunk); fscanf(InDem, "%d", &njunk); fscanf(InDem, "%d", &njunk); dxStart = DConvert(InDem, 24); nRasterYSize = (int) ((extent_max.y - extent_min.y)/dydelta + 1.5); nRasterXSize = nProfiles; adfGeoTransform[0] = dxStart - dxdelta/2.0; adfGeoTransform[1] = dxdelta; adfGeoTransform[2] = 0.0; adfGeoTransform[3] = extent_max.y + dydelta/2.0; adfGeoTransform[4] = 0.0; adfGeoTransform[5] = -dydelta; } /* -------------------------------------------------------------------- */ /* Geographic -- use corners directly. */ /* -------------------------------------------------------------------- */ else { nRasterYSize = (int) ((extent_max.y - extent_min.y)/dydelta + 1.5); nRasterXSize = nProfiles; // Translate extents from arc-seconds to decimal degrees. adfGeoTransform[0] = (extent_min.x - dxdelta/2.0) / 3600.0; adfGeoTransform[1] = dxdelta / 3600.0; adfGeoTransform[2] = 0.0; adfGeoTransform[3] = (extent_max.y + dydelta/2.0) / 3600.0; adfGeoTransform[4] = 0.0; adfGeoTransform[5] = (-dydelta) / 3600.0; } if (!GDALCheckDatasetDimensions(nRasterXSize, nRasterYSize)) { return FALSE; } return TRUE; }
/** * Loads elevation from a USGS DEM file. * * Some non-standard variations of the DEM format are supported. * * You should call SetupLocalCS() after loading if you will be doing * heightfield operations on this grid. * * \returns \c true if the file was successfully opened and read. */ bool vtElevationGrid::LoadFromDEM(const char *szFileName, bool progress_callback(int), vtElevError *err) { // Free buffers to prepare to receive new data FreeData(); if (progress_callback != NULL) progress_callback(0); FILE *fp = vtFileOpen(szFileName,"rb"); if (!fp) // Cannot Open File { SetError(err, vtElevError::FILE_OPEN, "Couldn't open file '%s'", szFileName); return false; } // check for version of DEM format int iRow, iColumn; char buffer[158]; fseek(fp, 864, 0); if (fread(buffer, 144, 1, fp) != 1) { SetError(err, vtElevError::READ_DATA, "Couldn't read DEM data from '%s'", szFileName); return false; } bool bOldFormat = (strncmp(buffer, " 1 1", 12) == 0); bool bNewFormat = false; bool bFixedLength = true; int iDataStartOffset = 1024; // set here to avoid compiler warning int i, j; if (bOldFormat) iDataStartOffset = 1024; // 1024 is record length else { fseek(fp, 1024, 0); // Check for New Format IConvert(fp, 6, iRow); IConvert(fp, 6, iColumn); if (iRow==1 && iColumn==1) // File OK? { bNewFormat = true; iDataStartOffset = 1024; } else { // might be the Non-fixed-length record format // Record B can start anywhere from 865 to 1023 // Record B is identified by starting with the row/column // of its first profile, " 1 1" fseek(fp, 865, 0); if (fread(buffer, 158, 1, fp) != 1) { SetError(err, vtElevError::READ_DATA, "Couldn't read DEM data from '%s'", szFileName); fclose(fp); return false; } for (i = 0; i < 158-12; i++) { if (!strncmp(buffer+i, " 1 1", 12)) { // Found it bFixedLength = false; iDataStartOffset = 865+i; break; } } if (i == 158-12) { // Not a DEM file SetError(err, vtElevError::READ_DATA, "Couldn't read DEM data from '%s'", szFileName); fclose(fp); return false; } } } // Read the embedded DEM name char szName[41]; fseek(fp, 0, 0); if (fgets(szName, 41, fp) == NULL) return false; int len = strlen(szName); // trim trailing whitespace while (len > 0 && szName[len-1] == ' ') { szName[len-1] = 0; len--; } m_strOriginalDEMName = szName; fseek(fp, 156, 0); int iCoordSystem, iUTMZone; IConvert(fp, 6, iCoordSystem); IConvert(fp, 6, iUTMZone); fseek(fp, 168, 0); double dProjParams[15]; for (i = 0; i < 15; i++) { if (!DConvert(fp, 24, dProjParams[i], DEBUG_DEM)) return false; } int iDatum = EPSG_DATUM_NAD27; // default // OLD format header ends at byte 864 (0x360); new format has Datum if (bNewFormat) { // year of data compilation char szDateBuffer[5]; fseek(fp, 876, 0); // 0x36C if (fread(szDateBuffer, 4, 1, fp) != 1) return false; szDateBuffer[4] = 0; // Horizontal datum // 1=North American Datum 1927 (NAD 27) // 2=World Geodetic System 1972 (WGS 72) // 3=WGS 84 // 4=NAD 83 // 5=Old Hawaii Datum // 6=Puerto Rico Datum fseek(fp, 890, 0); // 0x37A int datum; IConvert(fp, 2, datum); VTLOG("DEM Reader: Read Datum Value %d\n", datum); switch (datum) { case 1: iDatum = EPSG_DATUM_NAD27; break; case 2: iDatum = EPSG_DATUM_WGS72; break; case 3: iDatum = EPSG_DATUM_WGS84; break; case 4: iDatum = EPSG_DATUM_NAD83; break; case 5: iDatum = EPSG_DATUM_OLD_HAWAIIAN; break; case 6: iDatum = EPSG_DATUM_PUERTO_RICO; break; } } fseek(fp, 528, 0); int iGUnit, iVUnit; IConvert(fp, 6, iGUnit); IConvert(fp, 6, iVUnit); // Ground (Horizontal) Units in meters double fGMeters; switch (iGUnit) { case 0: fGMeters = 1.0; break; // 0 = radians (never encountered) case 1: fGMeters = 0.3048; break; // 1 = feet case 2: fGMeters = 1.0; break; // 2 = meters case 3: fGMeters = 30.922; break; // 3 = arc-seconds } // Vertical Units in meters double fVertUnits; switch (iVUnit) { case 1: fVertUnits = 0.3048; break; // feet to meter conversion case 2: fVertUnits = 1.0; break; // meters == meters default: fVertUnits = 1.0; break; // anything else, assume meters } fseek(fp, 816, 0); double dxdelta, dydelta, dzdelta; DConvert(fp, 12, dxdelta, DEBUG_DEM); // dxdelta (unused) DConvert(fp, 12, dydelta, DEBUG_DEM); DConvert(fp, 12, dzdelta, DEBUG_DEM); m_bFloatMode = false; // Read the coordinates of the 4 corners VTLOG("DEM corners:\n"); DPoint2 corners[4]; // SW, NW, NE, SE fseek(fp, 546, 0); for (i = 0; i < 4; i++) { DConvert(fp, 24, corners[i].x, DEBUG_DEM); DConvert(fp, 24, corners[i].y, DEBUG_DEM); } for (i = 0; i < 4; i++) VTLOG(" (%lf, %lf)", corners[i].x, corners[i].y); VTLOG("\n"); // Set up the projection and corners bool bGeographic = (iCoordSystem == 0); if (bGeographic) { for (i = 0; i < 4; i++) { // convert arcseconds to degrees m_Corners[i].x = corners[i].x / 3600.0; m_Corners[i].y = corners[i].y / 3600.0; } } else { // some linear coordinate system for (i = 0; i < 4; i++) m_Corners[i] = corners[i]; } // Special case. Some old DEMs claim to be NAD27, but they are of Hawai'i, // and Hawai'i has no NAD27, it is actually OHD. if (iDatum == EPSG_DATUM_NAD27) { DRECT Hawaii(0,0,0,0); if (bGeographic) Hawaii.SetRect(-164, 24, -152, 17); else if (iCoordSystem == 1) // UTM { if (iUTMZone == 4) Hawaii.SetRect(240000, 2600000, 1000000, 2000000); else if (iUTMZone == 5) Hawaii.SetRect(-400000, 2600000, 400000, 2000000); } for (i = 0; i < 4; i++) { if (Hawaii.ContainsPoint(m_Corners[i])) iDatum = EPSG_DATUM_OLD_HAWAIIAN; } } bool bSuccessfulCRS = true; switch (iCoordSystem) { case 0: // geographic (lat-lon) iUTMZone = -1; bSuccessfulCRS = m_proj.SetProjectionSimple(false, iUTMZone, iDatum); break; case 1: // utm m_proj.SetProjectionSimple(true, iUTMZone, iDatum); break; case 3: // Albers Conical Equal Area { // The Official DEM documentation says: // "Note: All angles (latitudes, longitudes, or azimuth) are // required in degrees, minutes, and arc seconds in the packed // real number format +DDDOMMOSS.SSSSS." // However, what i've actually seen is values like: // 0.420000000000000D+06' -> 420000 // for 42 degrees, which is off by a decimal point from the DEM docs. // So, intepret the values with factor of 10000 to convert to degrees: // double semi_major = dProjParams[0]; // unused // double eccentricity = dProjParams[1]; // unused double lat_1st_std_parallel = dProjParams[2] / 10000; double lat_2nd_std_parallel = dProjParams[3] / 10000; double lon_central_meridian = dProjParams[4] / 10000; double lat_origin = dProjParams[5] / 10000; double false_easting = dProjParams[6]; double false_northing = dProjParams[7]; m_proj.SetGeogCSFromDatum(iDatum); m_proj.SetACEA(lat_1st_std_parallel, lat_2nd_std_parallel, lat_origin, lon_central_meridian, false_easting, false_northing); } break; case 2: // State Plane (!) case 4: // Lambert Conformal case 5: // Mercator case 6: // Polar Stereographic case 7: // Polyconic case 8: // Equidistant Conic Type A / B case 9: // Transverse Mercator case 10: // Stereographic case 11: // Lambert Azimuthal Equal-Area case 12: // Azimuthal Equidistant case 13: // Gnomonic case 14: // Orthographic case 15: // General Vertical Near-Side Perspective case 16: // Sinusoidal (Plate Caree) case 17: // Equirectangular case 18: // Miller Cylindrical case 19: // Van Der Grinten I case 20: // Oblique Mercator VTLOG("Warning! We don't yet support DEM coordinate system %d.\n", iCoordSystem); break; } // We must have a functional CRS, or it will sebsequently fail if (!bSuccessfulCRS) { SetError(err, vtElevError::READ_CRS, "Couldn't determine CRS of DEM file"); return false; } double dElevMin, dElevMax; DConvert(fp, 24, dElevMin, DEBUG_DEM); DConvert(fp, 24, dElevMax, DEBUG_DEM); fseek(fp, 852, 0); int iRows, iProfiles; IConvert(fp, 6, iRows); // This "Rows" value will always be 1 IConvert(fp, 6, iProfiles); VTLOG("DEM profiles: %d\n", iProfiles); m_iSize.x = iProfiles; // values we'll need while scanning the elevation profiles int iProfileRows, iProfileCols; int iElev; double dLocalDatumElev, dProfileMin, dProfileMax; int ygap; double dMinY; DPoint2 start; if (bGeographic) { // If it's in degrees, it's flush square, so we can simply // derive the extents (m_EarthExtents) from the quad corners (m_Corners) ComputeExtentsFromCorners(); dMinY = std::min(corners[0].y, corners[3].y); } else { VTLOG("DEM scanning to compute extents\n"); m_EarthExtents.SetInsideOut(); if (!bFixedLength) fseek(fp, iDataStartOffset, 0); // Need to scan over all the profiles, accumulating the TRUE // extents of the actual data points. int record = 0; int data_len; for (i = 0; i < iProfiles; i++) { if (progress_callback != NULL) progress_callback(i*49/iProfiles); if (bFixedLength) fseek(fp, iDataStartOffset + (record * 1024), 0); // We cannot use IConvert here, because there *might* be a spurious LF // after the number - seen in some rare files. if (fscanf(fp, "%d", &iRow) != 1) { SetError(err, vtElevError::READ_DATA, "Error reading DEM at profile %d of %d", i, iProfiles); return false; } IConvert(fp, 6, iColumn); // assert(iColumn == i+1); IConvert(fp, 6, iProfileRows); IConvert(fp, 6, iProfileCols); DConvert(fp, 24, start.x); DConvert(fp, 24, start.y); m_EarthExtents.GrowToContainPoint(start); start.y += ((iProfileRows-1) * dydelta); m_EarthExtents.GrowToContainPoint(start); if (bFixedLength) { record++; data_len = 144 + (iProfileRows * 6); while (data_len > 1020) // max bytes in a record { data_len -= 1020; record++; } } else { DConvert(fp, 24, dLocalDatumElev); DConvert(fp, 24, dProfileMin); DConvert(fp, 24, dProfileMax); for (j = 0; j < iProfileRows; j++) { // We cannot use IConvert here, because there *might* be a spurious LF // after the number - seen in some rare files. if (fscanf(fp, "%d", &iElev) != 1) return false; } } } dMinY = m_EarthExtents.bottom; } VTLOG("DEM extents LRTB: %lf, %lf, %lf, %lf\n", m_EarthExtents.left, m_EarthExtents.right, m_EarthExtents.top, m_EarthExtents.bottom); // Compute number of rows double fRows; if (bGeographic) { // degrees fRows = m_EarthExtents.Height() / dydelta * 3600.0f; m_iSize.y = (int)fRows + 1; // 1 more than quad spacing } else { // some linear coordinate system fRows = m_EarthExtents.Height() / dydelta; m_iSize.y = (int)(fRows + 0.5) + 1; // round to the nearest integer } // safety check if (m_iSize.y > 20000) return false; if (!AllocateGrid(err)) return false; // jump to start of actual data fseek(fp, iDataStartOffset, 0); for (i = 0; i < iProfiles; i++) { if (progress_callback != NULL) progress_callback(50+i*49/iProfiles); // We cannot use IConvert here, because there *might* be a spurious LF // after the number - seen in some rare files. if (fscanf(fp, "%d", &iRow) != 1) return false; IConvert(fp, 6, iColumn); //assert(iColumn == i+1); IConvert(fp, 6, iProfileRows); IConvert(fp, 6, iProfileCols); DConvert(fp, 24, start.x); DConvert(fp, 24, start.y); DConvert(fp, 24, dLocalDatumElev); DConvert(fp, 24, dProfileMin); DConvert(fp, 24, dProfileMax); ygap = (int)((start.y - dMinY)/dydelta); for (j = ygap; j < (ygap + iProfileRows); j++) { //assert(j >=0 && j < m_iSize.y); // useful safety check // We cannot use IConvert here, because there *might* be a spurious LF // after the number - seen in some rare files. if (fscanf(fp, "%d", &iElev) != 1) return false; if (iElev == -32767 || iElev == -32768) SetValue(i, j, INVALID_ELEVATION); else { // The DEM spec says: // "A value in this array would be multiplied by the "z" spatial // resolution (data element 15, record type A) and added to the // "Elevation of local datum for the profile" (data element 4, record // type B) to obtain the elevation for the point." SetValue(i, j, (short) iElev + (short) dLocalDatumElev); } } } fclose(fp); m_fVMeters = (float) (fVertUnits * dzdelta); ComputeHeightExtents(); if (m_fMinHeight != dElevMin || m_fMaxHeight != dElevMax) VTLOG("DEM Reader: elevation extents in .dem (%.1f, %.1f) don't match data (%.1f, %.1f).\n", dElevMin, dElevMax, m_fMinHeight, m_fMaxHeight); return true; }
CPLErr USGSDEMRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff, void * pImage ) { double dfYMin; int bad = FALSE; USGSDEMDataset *poGDS = (USGSDEMDataset *) poDS; /* -------------------------------------------------------------------- */ /* Initialize image buffer to nodata value. */ /* -------------------------------------------------------------------- */ for( int k = GetXSize() * GetYSize() - 1; k >= 0; k-- ) { if( GetRasterDataType() == GDT_Int16 ) ((GInt16 *) pImage)[k] = USGSDEM_NODATA; else ((float *) pImage)[k] = USGSDEM_NODATA; } /* -------------------------------------------------------------------- */ /* Seek to data. */ /* -------------------------------------------------------------------- */ VSIFSeek(poGDS->fp, poGDS->nDataStartOffset, 0); dfYMin = poGDS->adfGeoTransform[3] + (GetYSize()-0.5) * poGDS->adfGeoTransform[5]; /* -------------------------------------------------------------------- */ /* Read all the profiles into the image buffer. */ /* -------------------------------------------------------------------- */ for( int i = 0; i < GetXSize(); i++) { int njunk, nCPoints, lygap; double djunk, dxStart, dyStart, dfElevOffset; fscanf(poGDS->fp, "%d", &njunk); fscanf(poGDS->fp, "%d", &njunk); fscanf(poGDS->fp, "%d", &nCPoints); fscanf(poGDS->fp, "%d", &njunk); dxStart = DConvert(poGDS->fp, 24); dyStart = DConvert(poGDS->fp, 24); dfElevOffset = DConvert(poGDS->fp, 24); djunk = DConvert(poGDS->fp, 24); djunk = DConvert(poGDS->fp, 24); if( EQUALN(poGDS->pszProjection,"GEOGCS",6) ) dyStart = dyStart / 3600.0; lygap = (int)((dfYMin - dyStart)/poGDS->adfGeoTransform[5]+ 0.5); for (int j=lygap; j < (nCPoints+(int)lygap); j++) { int iY = GetYSize() - j - 1; int nElev; fscanf(poGDS->fp, "%d", &nElev); if (iY < 0 || iY >= GetYSize() ) bad = TRUE; else if( nElev == USGSDEM_NODATA ) /* leave in output buffer as nodata */; else { float fComputedElev = (float)(nElev * poGDS->fVRes + dfElevOffset); if( GetRasterDataType() == GDT_Int16 ) { ((GInt16 *) pImage)[i + iY*GetXSize()] = (GInt16) fComputedElev; } else { ((float *) pImage)[i + iY*GetXSize()] = fComputedElev; } } } } return CE_None; }