#define GRIB_FUNCTIONS_C #include "GRIB_Constants.h" #include "GRIB_Functions.h" #define PI 3.1415926535897932384626433832795 #define EARTH_SPHERICAL_DIAMETER (2.0 * PI * 6367470.0) #define MetersToLatitudeSpherical(meters) (meters * (float)(360.0 / EARTH_SPHERICAL_DIAMETER)) #define MetersToLongitudeSpherical(latitude, meters) (meters * (360.0 / EARTH_SPHERICAL_DIAMETER) * cos(latitude))) const float g_fltWrapValues[] = {0.0f, 360.0f, -90.0f, 90.0f}; /* Reads a 3 byte signed integer */ inline bool InputNumber(UTIL::Input * p_ptrIn, int & p_intResult) { unsigned char uchrData[3]; if ( p_ptrIn->Read(&uchrData, 3) ) { p_intResult = (int)((((((unsigned int)(uchrData[0]) & 0x7f) << 16) + ((unsigned int)(uchrData[1]) << 8) + (unsigned int)(uchrData[2])) * (( uchrData[0] & 0x80 ) ? -1 : 1))); return true; } else return false; } /* Reads a 2 byte signed integer */ inline bool InputNumber(UTIL::Input * p_ptrIn, short & p_shtResult) { unsigned char uchrData[2]; if ( p_ptrIn->Read(&uchrData, 2) ) { p_shtResult = (short)((((((unsigned int)(uchrData[0]) & 0x7f) << 8) + (unsigned int)(uchrData[1])) * (( uchrData[0] & 0x80 ) ? -1 : 1))); return true; } else return false; } /* Reads a 3 byte unsigned integer */ inline bool InputNumber(UTIL::Input * p_ptrIn, unsigned int & p_uintResult) { unsigned char uchrData[3]; if ( p_ptrIn->Read(&uchrData, 3) ) { p_uintResult = (unsigned int)(((unsigned int)(uchrData[0]) << 16) + ((unsigned int)(uchrData[1]) << 8) + (unsigned int)(uchrData[2])); return true; } else return false; } /* Reads a 2 byte unsigned integer */ inline bool InputNumber(UTIL::Input * p_ptrIn, unsigned short & p_ushtResult) { unsigned char uchrData[2]; if ( p_ptrIn->Read(&uchrData, 2) ) { p_ushtResult = (unsigned short)(((unsigned int)(uchrData[0]) << 8) + (unsigned int)(uchrData[1])); return true; } else return false; } /* Writes a 2 byte signed integer */ inline bool OutputNumber(UTIL::Output * p_ptrOut, const short p_shtValue) { unsigned char uchrData[2]; if ( p_shtValue < 0 ) { unsigned short ushtValue = (unsigned short)(-p_shtValue); uchrData[0] = (unsigned char)((ushtValue / 256) | 0x80); uchrData[1] = (unsigned char)(ushtValue % 256); } else { uchrData[0] = (unsigned char)(p_shtValue / 256); uchrData[1] = (unsigned char)(p_shtValue % 256); } return p_ptrOut->Write(&uchrData, 2); } /* Writes a 2 byte unsigned integer */ inline bool OutputNumber(UTIL::Output * p_ptrOut, const unsigned short p_ushtValue) { unsigned char uchrData[2] = { (unsigned char)(p_ushtValue / 256), (unsigned char)(p_ushtValue % 256), }; return p_ptrOut->Write(&uchrData, 2); } /* Writes a 3 byte signed integer */ inline bool OutputNumber(UTIL::Output * p_ptrOut, const int p_intValue) { unsigned char uchrData[3]; if ( p_intValue < 0 ) { unsigned int uintValue = -p_intValue; uchrData[0] = (unsigned char)(((uintValue / 65536) % 256) | 0x80); uchrData[1] = (unsigned char)((uintValue / 256) % 256); uchrData[2] = (unsigned char)(uintValue % 256); } else { uchrData[0] = (unsigned char)((p_intValue / 65536) % 256); uchrData[1] = (unsigned char)((p_intValue / 256) % 256); uchrData[2] = (unsigned char)(p_intValue % 256); } return p_ptrOut->Write(&uchrData, 3); } /* Writes a 3 byte unsigned integer */ inline bool OutputNumber(UTIL::Output * p_ptrOut, const unsigned int p_uintValue) { unsigned char uchrData[3] = { (unsigned char)((p_uintValue / 65536) % 256), (unsigned char)((p_uintValue / 256) % 256), (unsigned char)(p_uintValue % 256), }; return p_ptrOut->Write(&uchrData, 3); } /* Reads the Indicator section */ bool GRIB::Is:: Read(UTIL::Input * p_ptrIn) { char chrData[4]; return ( p_ptrIn->Read(&chrData, 4) && memcmp(&chrData, "GRIB", 4) == 0 && InputNumber(p_ptrIn, m_uintSectionLength) && p_ptrIn->Read(&m_uchrVersionNumber, 1) ); } /* Writes the Indicator Section */ bool GRIB::Is:: Write(UTIL::Output * p_ptrOut) const { return ( p_ptrOut->Write("GRIB", 4) && OutputNumber(p_ptrOut, m_uintSectionLength) && p_ptrOut->Write(&m_uchrVersionNumber, 1) ); } void GRIB::Pds:: Finish(void) { UTIL_SAFE_FREE(m_ptrExtraData); m_ulngExtraDataLength = 0; } /* Reads the Product Definition Section */ bool GRIB::Pds:: Read(UTIL::Input * p_ptrIn) { if ( InputNumber(p_ptrIn, m_uintSectionLength) == false || // 1 - 3 p_ptrIn->Read(&m_uchrVersionNumber, 1) == false || // 4 p_ptrIn->Read(&m_uchrOriginatingCenter, 1) == false || // 5 p_ptrIn->Read(&m_uchrGeneratingProcess, 1) == false || // 6 p_ptrIn->Read(&m_uchrGridIndex, 1) == false || // 7 p_ptrIn->Read(&m_uchrFlag, 1) == false || // 8 p_ptrIn->Read(&m_uchrParameter, 1) == false || // 9 p_ptrIn->Read(&m_uchrParameterLevel, 1) == false || // 10 InputNumber(p_ptrIn, m_ushtHeightPressureLevels) == false || // 11 - 12 p_ptrIn->Read(&m_uchrYear, 1) == false || // 13 p_ptrIn->Read(&m_uchrMonth, 1) == false || // 14 p_ptrIn->Read(&m_uchrDay, 1) == false || // 15 p_ptrIn->Read(&m_uchrHour, 1) == false || // 16 p_ptrIn->Read(&m_uchrMinute, 1) == false || // 17 p_ptrIn->Read(&m_uchrForecastTimeUnit, 1) == false || // 18 p_ptrIn->Read(&m_uchrTimePeriod1, 1) == false || // 19 p_ptrIn->Read(&m_uchrTimePeriod2, 1) == false || // 20 p_ptrIn->Read(&m_uchrTimeRangeIndicator, 1) == false || // 21 InputNumber(p_ptrIn, m_ushtTimePeriod1) == false || // 22 - 23 p_ptrIn->Read(&m_uchrMissingNumber, 1) == false || // 24 p_ptrIn->Read(&m_uchrCentury, 1) == false || // 25 p_ptrIn->Read(&m_uchrSubIdNumber, 1) == false || // 26 InputNumber(p_ptrIn, m_shtScaleFactor) == false ) // 27 - 28 { return false; } else if ( m_uintSectionLength > 28 ) { m_ulngExtraDataLength = m_uintSectionLength - 28; m_ptrExtraData = p_ptrIn->Read(m_ulngExtraDataLength); return ( m_ptrExtraData != NULL ); } else return true; } /* Writes the Product Definition Section */ bool GRIB::Pds:: Write(UTIL::Output * p_ptrOut, const int p_intFlagGds, const int p_intFlagBms) const { unsigned char uchrFlag = m_uchrFlag; if ( p_intFlagGds < 0 ) uchrFlag &= ~(0x80); else if ( p_intFlagGds > 0 ) uchrFlag |= 0x80; if ( p_intFlagBms < 0 ) uchrFlag &= ~(0x40); else if ( p_intFlagBms > 0 ) uchrFlag |= 0x40; return ( OutputNumber(p_ptrOut, m_uintSectionLength) && p_ptrOut->Write(&m_uchrVersionNumber, 1) && p_ptrOut->Write(&m_uchrOriginatingCenter, 1) && p_ptrOut->Write(&m_uchrGeneratingProcess, 1) && p_ptrOut->Write(&m_uchrGridIndex, 1) && p_ptrOut->Write(&uchrFlag, 1) && p_ptrOut->Write(&m_uchrParameter, 1) && p_ptrOut->Write(&m_uchrParameterLevel, 1) && OutputNumber(p_ptrOut, m_ushtHeightPressureLevels) && p_ptrOut->Write(&m_uchrYear, 1) && p_ptrOut->Write(&m_uchrMonth, 1) && p_ptrOut->Write(&m_uchrDay, 1) && p_ptrOut->Write(&m_uchrHour, 1) && p_ptrOut->Write(&m_uchrMinute, 1) && p_ptrOut->Write(&m_uchrForecastTimeUnit, 1) && p_ptrOut->Write(&m_uchrTimePeriod1, 1) && p_ptrOut->Write(&m_uchrTimePeriod2, 1) && p_ptrOut->Write(&m_uchrTimeRangeIndicator, 1) && OutputNumber(p_ptrOut, m_ushtTimePeriod1) && p_ptrOut->Write(&m_uchrMissingNumber, 1) && p_ptrOut->Write(&m_uchrCentury, 1) && p_ptrOut->Write(&m_uchrSubIdNumber, 1) && OutputNumber(p_ptrOut, m_shtScaleFactor) && (m_ulngExtraDataLength == 0 || p_ptrOut->Write(m_ptrExtraData, m_ulngExtraDataLength)) ); } void GRIB::Gds:: Finish(void) { UTIL_DELETE(m_ptrGrid); } /* Reads the Grid Definition Section, along with the grid itself */ bool GRIB::Gds:: Read(UTIL::Input * p_ptrIn) { if ( InputNumber(p_ptrIn, m_uintSectionLength) == false || p_ptrIn->Read(&m_uchrVerticalNumberAmount, 1) == false || p_ptrIn->Read(&m_uchrVerticalIndex, 1) == false || p_ptrIn->Read(&m_uchrDataRepresentType, 1) == false ) { return false; } switch ( m_uchrDataRepresentType ) { case 0: // Latitude/Longitude Grid (equidistant cylindrical) m_ptrGrid = new Grid_0; //uintGridSize = 32; break; case 1: // Mercator m_ptrGrid = new Grid_1; //uintGridSize = 42; break; case 2: // Gnomic return false; // Lambert Conformal case 3: m_ptrGrid = new Grid_3; //uintGridSize = 42; break; // Gaussian Latitude/Longitude case 4: return false; // Polar Stereographic case 5: m_ptrGrid = new Grid_5; //uintGridSize = 42; break; /* 6 - 12 are reserved */ // Oblique Lambert conformal case 13: return false; /* 14 - 49 are reserved */ // Spherical Harmonic Coefficients case 50: return false; /* 51 - 89 are reserved */ // Space view perspective or orthographic case 90: return false; /* 91 - 191 are reserved */ /* 192 - 254 are reserved for local use */ default: return false; } return m_ptrGrid->Read(p_ptrIn, m_fltCorners, &m_ulngGridPoints); } /* Writes the Grid Definition Section, along with the grid itself */ bool GRIB::Gds:: Write(UTIL::Output * p_ptrOut, const unsigned short * p_ptrIndices) const { return ( OutputNumber(p_ptrOut, m_uintSectionLength) && p_ptrOut->Write(&m_uchrVerticalNumberAmount, 1) && p_ptrOut->Write(&m_uchrVerticalIndex, 1) && p_ptrOut->Write(&m_uchrDataRepresentType, 1) && m_ptrGrid->Write(p_ptrOut, p_ptrIndices) ); } /* Checks to see if a bit in the Bitmap Section is turned on */ int GRIB::Bms:: CheckBit(const unsigned long p_ulngBit) const { return ( m_ptrBitmap != NULL ) ? (int)((m_ptrBitmap[p_ulngBit / 8] & ((unsigned char)(0x80 >> (p_ulngBit % 8))))) : -1; } /* Reads the Bitmap Section */ bool GRIB::Bms:: Read(UTIL::Input * p_ptrIn, const bool p_blnReadMask) { if ( InputNumber(p_ptrIn, m_uintSectionLength) && p_ptrIn->Read(&m_uchrUnusedBits, 1) == true && InputNumber(p_ptrIn, m_ushtBitmapReference) ) { if ( m_ushtBitmapReference ) return false; if ( p_blnReadMask ) { m_ptrBitmap = (unsigned char *)(p_ptrIn->Read(m_uintSectionLength - 6)); return ( m_ptrBitmap != NULL ); } else return ( p_ptrIn->Skip(m_uintSectionLength - 6) == (m_uintSectionLength - 6) ); } return false; } /* Writes the Bitmap Section */ bool GRIB::Bms:: Write(UTIL::Output * p_ptrOut) const { return ( OutputNumber(p_ptrOut, m_uintSectionLength) && p_ptrOut->Write(&m_uchrUnusedBits, 1) && OutputNumber(p_ptrOut, m_ushtBitmapReference) && (m_ushtBitmapReference == 0 || p_ptrOut->Write(m_ptrBitmap, m_uintSectionLength - 6)) ); } /* Copies a value from the Binary Data Section */ void GRIB::Bds:: ValueCopy(const unsigned int p_uintIndex, char * p_ptrData, unsigned int & p_uintByte, unsigned int & p_uintBit) const { unsigned int uintByteOffset = (p_uintIndex * m_uchrPackBits) / 8; unsigned int uintBitOffset = (p_uintIndex * m_uchrPackBits) % 8; for (unsigned char i=0; i> uintBitOffset) ) p_ptrData[p_uintByte] |= ((unsigned char)(0x80) >> p_uintBit); else p_ptrData[p_uintByte] &= ~((unsigned char)(0x80) >> p_uintBit); if ( ++uintBitOffset >= 8 ) { uintBitOffset = 0; uintByteOffset++; } if ( ++p_uintBit >= 8 ) { p_uintBit = 0; p_uintByte++; } } } /* Retrieves a value from the Binary Data Section */ float GRIB::Bds:: ValueGet(const unsigned int p_uintIndex) const { unsigned int uintValue = 0; unsigned int uintOffsetByte = (p_uintIndex * m_uchrPackBits) / 8; unsigned char uchrOffsetBit = (unsigned char)((p_uintIndex * m_uchrPackBits) % 8); for (unsigned int i=(m_uchrPackBits - 1); i> uchrOffsetBit) ) uintValue += (1 << i); if ( ++uchrOffsetBit >= 8 ) { uchrOffsetBit = 0; uintOffsetByte++; } } return ((((float)(uintValue)) * m_fltScaleFactorBinary) + m_fltReferenceValue) * m_fltScaleFactorDecimal; } /* Reads the Binary Data Section */ bool GRIB::Bds:: Read(UTIL::Input * p_ptrIn, const bool p_blnReadData) { if ( InputNumber(p_ptrIn, m_uintSectionLength) && // 1 - 3 p_ptrIn->Read(&m_uchrFlag, 1) && // 4 InputNumber(p_ptrIn, m_shtScaleFactor) && // 5 - 6 p_ptrIn->Read(&m_uchrReferenceValue, 4) && // 7 - 10 p_ptrIn->Read(&m_uchrPackBits, 1) ) // 11 { m_fltScaleFactorBinary = (float)(pow(2.0, (double)(m_shtScaleFactor))); m_fltReferenceValue = (float)(pow(2.0, -24.0) * (double)((m_uchrReferenceValue[1] << 16) + (m_uchrReferenceValue[2] << 8) + m_uchrReferenceValue[3]) * pow(16.0, (double)(m_uchrReferenceValue[0] & (~(0x80))) - 64.0)); if ( m_uchrReferenceValue[0] & 0x80 ) m_fltReferenceValue *= -1.0; if ( (m_uchrFlag & 0x10) == 0 ) { m_uchrFlagExtention = 0; m_uintDataLength = m_uintSectionLength - 11; if ( p_blnReadData ) { m_ptrData = (unsigned char *)(p_ptrIn->Read(m_uintDataLength)); return ( m_ptrData != NULL ); } else return ( p_ptrIn->Skip(m_uintDataLength) == m_uintDataLength ); } else return false; } else return false; } /* Writes the Binary Data Section */ bool GRIB::Bds:: Write(UTIL::Output * p_ptrOut, const char * p_ptrBitmapNew, const unsigned long p_ulngPointsNew, const char * p_ptrBitmapCurrent, const unsigned long p_ulngPointsCurrent) const { unsigned int uintSectionLength; if ( p_ptrBitmapNew ) { uintSectionLength = ( (m_uchrPackBits * p_ulngPointsNew) % 8 ) ? ((m_uchrPackBits * p_ulngPointsNew) / 8) + 12 : ((m_uchrPackBits * p_ulngPointsNew) / 8) + 11; } else uintSectionLength = m_uintSectionLength; if ( OutputNumber(p_ptrOut, uintSectionLength) == false || p_ptrOut->Write(&m_uchrFlag, 1) == false || OutputNumber(p_ptrOut, m_shtScaleFactor) == false || p_ptrOut->Write(&m_uchrReferenceValue, 4) == false || p_ptrOut->Write(&m_uchrPackBits, 1) == false ) { return false; } if ( p_ptrBitmapNew ) { unsigned int uintBit = 0; unsigned int uintByte = 0; unsigned long ulngDataPosition = 0; char * ptrData = (char *)(alloca((m_uchrPackBits / 8) + 1)); for (unsigned int i=0; i> (i % 8)))) == 0 ) { continue; } ulngDataPosition++; if ( (p_ptrBitmapNew[i / 8] & ((unsigned char)(0x80 >> (i % 8)))) == 0 ) continue; ValueCopy(ulngDataPosition - 1, ptrData, uintByte, uintBit); if ( uintByte ) { if ( p_ptrOut->Write(ptrData, uintByte) == false ) return false; ptrData[0] = ptrData[uintByte]; uintByte = 0; } } return ( uintBit == 0 || p_ptrOut->Write(ptrData, 1) ); } else return p_ptrOut->Write(m_ptrData, m_uintSectionLength - 11); } bool GRIB::Message:: Chop(TREE::Basic * p_ptrTree, UTIL::Output * p_ptrOut, GRIB::ChopParameters * p_ptrParameters, GRIB::ChopResults * p_ptrResults) const { GRIB::ChopData stuData; if ( m_stuGds.m_ptrGrid->SetChopData(&stuData) == false ) return false; unsigned char * ptrBitmap; unsigned long ulngDataPointsNew; GRIB::ChopResults stuResults; GRIB::ChopParameters stuParameters; if ( p_ptrParameters == NULL ) p_ptrParameters = &stuParameters; if ( p_ptrResults == NULL ) p_ptrResults = &stuResults; stuData.m_ptrBds = &m_stuBds; if ( p_ptrOut != NULL ) { ptrBitmap = ( m_stuPds.m_uchrFlag & 0x40 ) ? new unsigned char[m_stuBms.m_uintSectionLength - 6] : new unsigned char[(m_stuGds.m_ulngGridPoints / 8) + 1]; ulngDataPointsNew = ( m_stuBms.CheckBit(0) >= 0 ) ? stuData.Chop(p_ptrTree, p_ptrParameters, p_ptrResults, &m_stuBms, ptrBitmap) : stuData.Chop(p_ptrTree, p_ptrParameters, p_ptrResults, ptrBitmap); } else { ptrBitmap = NULL; ulngDataPointsNew = ( m_stuBms.CheckBit(0) >= 0 ) ? stuData.Chop(p_ptrTree, p_ptrParameters, p_ptrResults, &m_stuBms) : stuData.Chop(p_ptrTree, p_ptrParameters, p_ptrResults); } if ( ulngDataPointsNew <= 1 ) { UTIL_DELETE_ARRAY(ptrBitmap); return true; } else if ( ulngDataPointsNew == (unsigned long)(-1) ) { UTIL_DELETE_ARRAY(ptrBitmap); return false; } else if ( p_ptrOut == NULL ) return true; else if ( ulngDataPointsNew == stuData.m_ulngDataPosition ) { delete [] ptrBitmap; return Write(p_ptrOut); } ++(stuData.m_ushtIndices[1]); ++(stuData.m_ushtIndices[3]); unsigned int uintNewBitmapBits = (stuData.m_ushtIndices[1] - stuData.m_ushtIndices[0]) * (stuData.m_ushtIndices[3] - stuData.m_ushtIndices[2]); unsigned int uintNewDataLength = ( (ulngDataPointsNew * m_stuBds.m_uchrPackBits) % 8 ) ? ((ulngDataPointsNew * m_stuBds.m_uchrPackBits) / 8) + 1 : (ulngDataPointsNew * m_stuBds.m_uchrPackBits) / 8; if ( uintNewBitmapBits > ulngDataPointsNew ) { unsigned char uchrUnusedBits = (unsigned char)(( uintNewBitmapBits % 8 ) ? 8 - (uintNewBitmapBits % 8) : 0); unsigned int uintNewBitmapBytes = ( uintNewBitmapBits % 8 ) ? (uintNewBitmapBits / 8) + 1 : uintNewBitmapBits / 8; if ( p_ptrOut->Write("GRIB", 4) == false || OutputNumber(p_ptrOut, 8 + m_stuPds.m_uintSectionLength + (( m_stuPds.m_uchrFlag & 0x80 ) ? m_stuGds.m_uintSectionLength : 0) + 6 + uintNewBitmapBytes + 11 + uintNewDataLength + 4) == false || p_ptrOut->Write(&(m_stuIs.m_uchrVersionNumber), 1) == false || m_stuPds.Write(p_ptrOut, 0, 1) == false || m_stuGds.Write(p_ptrOut, stuData.m_ushtIndices) == false || OutputNumber(p_ptrOut, uintNewBitmapBytes + 6) == false || p_ptrOut->Write(&uchrUnusedBits, 1) == false || OutputNumber(p_ptrOut, m_stuBms.m_ushtBitmapReference) == false ) { delete [] ptrBitmap; return false; } // // Print the new bitmap // unsigned char uchrBit = 0; unsigned char uchrByte = 0; for (unsigned short i=stuData.m_ushtIndices[2]; i> (ulngIndex % 8)) ) uchrByte |= (0x80 >> uchrBit); if ( ++uchrBit >= 8 ) { if ( p_ptrOut->Write(&uchrByte, 1) == false ) { delete [] ptrBitmap; return false; } uchrBit = uchrByte = 0; } } } if ( uchrBit && p_ptrOut->Write(&uchrByte, 1) == false ) return false; } else { if ( p_ptrOut->Write("GRIB", 4) == false || OutputNumber(p_ptrOut, 8 + m_stuPds.m_uintSectionLength + (( m_stuPds.m_uchrFlag & 0x80 ) ? m_stuGds.m_uintSectionLength : 0) + 11 + uintNewDataLength + 4) == false || p_ptrOut->Write(&(m_stuIs.m_uchrVersionNumber), 1) == false || m_stuPds.Write(p_ptrOut, 0, -1) == false || m_stuGds.Write(p_ptrOut, stuData.m_ushtIndices) == false ) { delete [] ptrBitmap; return false; } } // // Print the data section // if ( m_stuBds.Write(p_ptrOut, (char *)(ptrBitmap), ulngDataPointsNew, (char *)(m_stuBms.m_ptrBitmap), m_stuGds.m_ulngGridPoints) == false ) { delete [] ptrBitmap; return false; } delete [] ptrBitmap; return p_ptrOut->Write("7777", 4); } bool GRIB::Message:: Read(UTIL::Input * p_ptrIn, const bool p_blnReadMask, const bool p_blnReadData) { if ( m_stuIs.Read(p_ptrIn) == false || m_stuPds.Read(p_ptrIn) == false ) { return false; } // // Read the Grid Description Section if there is one // if ( m_stuPds.m_uchrFlag & 0x80 ) { if ( m_stuGds.Read(p_ptrIn) == false ) return false; } else memset(&m_stuGds, 0, sizeof(Gds)); // // Read the Bit Map Section if there is one // if ( m_stuPds.m_uchrFlag & 0x40 ) { if ( m_stuBms.Read(p_ptrIn, p_blnReadMask) == false ) return false; } else memset(&m_stuBms, 0, sizeof(Bms)); // // Read the Binary Data Section // m_stuBds.m_fltScaleFactorDecimal = (float)(1.0 / pow(10.0, (double)(m_stuPds.m_shtScaleFactor))); if ( m_stuBds.Read(p_ptrIn, p_blnReadData) == false ) return false; // // Make sure the trailing '7777' appears at the end of the data // char chrData[4]; return ( p_ptrIn->Read(&chrData, 4) && memcmp(&chrData, "7777", 4) == 0 ); } bool GRIB:: Split(UTIL::Parser * p_ptrGribData, const char * p_ptrDirectory, const char * p_ptrPrefix, const char * p_ptrSuffix, const unsigned char * p_ptrFilter) { UTIL::File clsFile; clsFile.m_blnPrintNulls = false; unsigned int uintPeriod = (unsigned int)(-1); unsigned int uintFilterLength = (unsigned int)(( p_ptrFilter ) ? strlen((const char *)(p_ptrFilter)) : 0); if ( p_ptrDirectory == NULL ) p_ptrDirectory = ""; while ( p_ptrGribData->ToString("GRIB") ) { unsigned char uchrData[29]; unsigned int uintGribLength = 0; if ( InputNumber(p_ptrGribData, uintGribLength) == false || p_ptrGribData->Read(&uchrData, 29) == false ) { return false; } if ( p_ptrFilter && UTIL::InArray(uchrData[9], (const unsigned char *)(p_ptrFilter), uintFilterLength) == false ) { if ( p_ptrGribData->Skip(uintGribLength - 40) == false || p_ptrGribData->Compare("7777") ) { return false; } continue; } unsigned int uintMultiplier = 1; if ( uchrData[18] == 2 ) uintMultiplier = 24; else if ( uchrData[18] != 1 ) return false; unsigned int uintPeriodSub; if ( uchrData[21] <= 4 ) uintPeriodSub = uintMultiplier * uchrData[19]; else if ( uchrData[21] == 10 ) uintPeriodSub = uintMultiplier * ((256 * uchrData[19]) + uchrData[20]); else return false; if ( uintPeriod != uintPeriodSub ) { uintPeriod = uintPeriodSub; clsFile.Finish(); if ( clsFile.Open("wa", ( UTIL_CHECK_PATH(p_ptrDirectory) ) ? "%s%s.%03u%s" : "%s/%s.%03u%s", p_ptrDirectory, ( p_ptrPrefix ) ? p_ptrPrefix : "", uintPeriod, ( p_ptrSuffix ) ? p_ptrSuffix : "") == false ) { return false; } } if ( clsFile.Write("GRIB", 4) == false || OutputNumber(&clsFile, uintGribLength) == false || clsFile.Write(&uchrData, 29) == false || p_ptrGribData->Read(&clsFile, uintGribLength - 40) == false || p_ptrGribData->Compare("7777") || clsFile.Write("7777", 4) == false ) { return false; } } return true; } void GRIB::Message:: Basetime(UTIL::Time * p_ptrTime) const { p_ptrTime->ushtYear = (unsigned short)(((m_stuPds.m_uchrCentury - 1) * 100) + m_stuPds.m_uchrYear); p_ptrTime->ushtMonth = m_stuPds.m_uchrMonth; p_ptrTime->ushtDay = m_stuPds.m_uchrDay; p_ptrTime->ushtHour = m_stuPds.m_uchrHour; p_ptrTime->ushtMinute = m_stuPds.m_uchrMinute; p_ptrTime->ushtSecond = 0; } int GRIB::Message:: Interval(void) const { int intMultiplier = 0; switch ( m_stuPds.m_uchrForecastTimeUnit ) { // Second case 254: intMultiplier = 1; break; // Minute case 0: intMultiplier = 60; break; // Hour case 1: intMultiplier = 3600; break; // Day case 2: intMultiplier = 86400; break; // These are not supported case 3: // Month case 4: // Year case 5: // Decade case 6: // 30 years case 7: // Century default: // (reserved) return -1; } switch ( m_stuPds.m_uchrTimeRangeIndicator ) { case 0: // Forecast product valid at reference time + P1 (P1>0), or Uninitialized analysis product for reference time (P1=0). or Image product for reference time (P1=0) case 1: // Initialized analysis product for reference time (P1=0). case 2: // Product with a valid time ranging between reference time + P1 and reference time + P2 case 3: // Average (reference time + P1 to reference time + P2) return intMultiplier * (int)(m_stuPds.m_uchrTimePeriod1); case 4: // Accumulation (reference time + P1 to reference time + P2) product considered valid at reference time + P2 case 5: // Difference (reference time + P2 minus reference time + P1) product considered valid at reference time + P2 return intMultiplier * (int)(m_stuPds.m_uchrTimePeriod2); case 10: // P1 occupies octets 19 and 20; product valid at reference time + P1 return intMultiplier * (int)((m_stuPds.m_uchrTimePeriod1 << 8) + m_stuPds.m_uchrTimePeriod2); default: return -1; } } time_t GRIB::Message:: Time(void) const { int intInterval = Interval(); if ( intInterval < 0 ) return -1; UTIL::Time clsTime; Basetime(&clsTime); return clsTime.ToEpoch() + (unsigned int)(intInterval); /* int intTime = clsTime.ToInt(); switch ( m_stuPds.m_uchrForecastTimeUnit ) { // Second case 254: return clsTime.ToInt() + ( m_stuPds.m_uchrTimeRangeIndicator != 10 ) ? (int)(m_stuPds.m_uchrTimePeriod1) : (int)(m_stuPds.m_ushtTimePeriod1); // Minute case 0: return clsTime.ToInt() + ( m_stuPds.m_uchrTimeRangeIndicator != 10 ) ? 60 * (int)(m_stuPds.m_uchrTimePeriod1) : 60 * (int)(m_stuPds.m_ushtTimePeriod1); break; // Hour case 1: return clsTime.ToInt() + ( m_stuPds.m_uchrTimeRangeIndicator != 10 ) ? 3600 * (int)(m_stuPds.m_uchrTimePeriod1) : 3600 * (int)(m_stuPds.m_ushtTimePeriod1); // Day case 2: return clsTime.ToInt() + ( m_stuPds.m_uchrTimeRangeIndicator != 10 ) ? 86400 * (int)(m_stuPds.m_uchrTimePeriod1) : 86400 * (int)(m_stuPds.m_ushtTimePeriod1); // These are not supported (so, resulting time will be invalid) case 3: // Month case 4: // Year case 5: // decade case 6: // 30 years case 7: // century default: // (reserved) return clsTime.ToInt() + ( m_stuPds.m_uchrTimeRangeIndicator != 10 ) ? (int)(m_stuPds.m_uchrTimePeriod1) : (int)(m_stuPds.m_ushtTimePeriod1); break; } return intTime; */ } bool GRIB::Message:: Write(UTIL::Output * p_ptrOut) const { return ( p_ptrOut->Write("GRIB", 4) && OutputNumber(p_ptrOut, m_stuIs.m_uintSectionLength) && p_ptrOut->Write(&(m_stuIs.m_uchrVersionNumber), 1) && m_stuPds.Write(p_ptrOut) && ((m_stuPds.m_uchrFlag & 0x80) || m_stuGds.Write(p_ptrOut)) && ((m_stuPds.m_uchrFlag & 0x40) || m_stuBms.Write(p_ptrOut)) && m_stuBds.Write(p_ptrOut) && p_ptrOut->Write("7777", 4) == 0 ); } unsigned long GRIB::ChopData:: Chop(TREE::Basic * p_ptrTree, GRIB::ChopParameters * p_ptrParameters, GRIB::ChopResults * p_ptrResults, const GRIB::Bms * p_ptrBms, unsigned char * p_ptrBitmap) { UTIL::D2::Point stuPoint; unsigned int uintBit; unsigned int uintRow; float fltValue; unsigned long ulngDataPointsNew = 0; for (unsigned short i=0; iIntersect((const float *)(&stuPoint), 0x2) == false ) { uintRow = i * m_ushtPointsX; for (unsigned short j=0; j> (uintBit % 8)))); if ( p_ptrBms->CheckBit(uintBit) ) m_ulngDataPosition++; } continue; } uintRow = i * m_ushtPointsX; for (unsigned short j=0; jCheckBit(uintBit) == 0 ) { p_ptrBitmap[uintBit / 8] &= ((unsigned char)(~(0x80 >> (uintBit % 8)))); continue; } // // Insert the point into the tree // stuPoint[0] = 0.001f * (float)(m_intFirstPointX + (j * m_shtIncrementX)); fltValue = p_ptrParameters->Value(m_ptrBds->ValueGet(m_ulngDataPosition++)); if ( p_ptrTree->Insert(fltValue, stuPoint, 0x01 | 0x02) == false ) { p_ptrBitmap[uintBit / 8] &= ((unsigned char)(~(0x80 >> (uintBit % 8)))); continue; } p_ptrResults->Add(fltValue, stuPoint, ( ulngDataPointsNew++ > 0 )); p_ptrBitmap[uintBit / 8] |= ((unsigned char)(0x80 >> (uintBit % 8))); // // Keep track of the area of inserted points // if ( m_ushtIndices[0] > j ) m_ushtIndices[0] = j; if ( m_ushtIndices[1] < j ) m_ushtIndices[1] = j; if ( m_ushtIndices[2] > i ) m_ushtIndices[2] = i; if ( m_ushtIndices[3] < i ) m_ushtIndices[3] = i; } } p_ptrResults->m_blnDataSet = ( ulngDataPointsNew > 0 ); return ulngDataPointsNew; } unsigned long GRIB::ChopData:: Chop(TREE::Basic * p_ptrTree, GRIB::ChopParameters * p_ptrParameters, GRIB::ChopResults * p_ptrResults, unsigned char * p_ptrBitmap) { UTIL::D2::Point stuPoint; unsigned int uintBit; unsigned int uintRow; float fltValue; unsigned long ulngDataPointsNew = 0; for (unsigned short i=0; iIntersect((const float *)(&stuPoint), 0x2) == false ) { unsigned short j = 0; for (uintBit = uintRow; ( (uintBit % 8) != 0) && j> (uintBit % 8)))); for (; j> (uintBit % 8)))); } m_ulngDataPosition += m_ushtPointsX; continue; } for (unsigned short j=0; jValue(m_ptrBds->ValueGet(m_ulngDataPosition++)); if ( p_ptrTree->Insert(fltValue, stuPoint, 0x01 | 0x02) == false ) { p_ptrBitmap[uintBit / 8] &= ((unsigned char)(~(0x80 >> (uintBit % 8)))); continue; } p_ptrResults->Add(fltValue, stuPoint, ( ulngDataPointsNew++ > 0)); p_ptrBitmap[uintBit / 8] |= ((unsigned char)(0x80 >> (uintBit % 8))); // // Keep track of the area of inserted points // if ( m_ushtIndices[0] > j ) m_ushtIndices[0] = j; if ( m_ushtIndices[1] < j ) m_ushtIndices[1] = j; if ( m_ushtIndices[2] > i ) m_ushtIndices[2] = i; if ( m_ushtIndices[3] < i ) m_ushtIndices[3] = i; } } p_ptrResults->m_blnDataSet = ( ulngDataPointsNew > 0 ); return ulngDataPointsNew; } unsigned long GRIB::ChopData:: Chop(TREE::Basic * p_ptrTree, GRIB::ChopParameters * p_ptrParameters, GRIB::ChopResults * p_ptrResults, const GRIB::Bms * p_ptrBms) { UTIL::D2::Point stuPoint; unsigned int uintBit; unsigned int uintRow; float fltValue; unsigned long ulngDataPointsNew = 0; for (unsigned short i=0; iIntersect((const float *)(&stuPoint), 0x2) == false ) { for (unsigned short j=0; jCheckBit(uintRow + j) ) m_ulngDataPosition++; } continue; } for (unsigned short j=0; jCheckBit(uintBit) == 0 ) continue; // // Insert the point into the tree // stuPoint[0] = 0.001f * (float)(m_intFirstPointX + (j * m_shtIncrementX)); fltValue = p_ptrParameters->Value(m_ptrBds->ValueGet(m_ulngDataPosition++)); if ( p_ptrTree->Insert(fltValue, stuPoint, 0x01 | 0x02) == false ) { continue; } p_ptrResults->Add(fltValue, stuPoint, ( ulngDataPointsNew++ > 0 )); // // Keep track of the area of inserted points // if ( m_ushtIndices[0] > j ) m_ushtIndices[0] = j; if ( m_ushtIndices[1] < j ) m_ushtIndices[1] = j; if ( m_ushtIndices[2] > i ) m_ushtIndices[2] = i; if ( m_ushtIndices[3] < i ) m_ushtIndices[3] = i; } } p_ptrResults->m_blnDataSet = ( ulngDataPointsNew > 0 ); return ulngDataPointsNew; } unsigned long GRIB::ChopData:: Chop(TREE::Basic * p_ptrTree, GRIB::ChopParameters * p_ptrParameters, GRIB::ChopResults * p_ptrResults) { UTIL::D2::Point stuPoint; float fltValue; unsigned long ulngDataPointsNew = 0; for (unsigned short i=0; iIntersect((const float *)(&stuPoint), 0x2) == false ) { m_ulngDataPosition += m_ushtPointsX; continue; } for (unsigned short j=0; jValue(m_ptrBds->ValueGet(m_ulngDataPosition++)); if ( p_ptrTree->Insert(fltValue, stuPoint, 0x01 | 0x02) == false ) { continue; } p_ptrResults->Add(fltValue, stuPoint, ( ulngDataPointsNew++ > 0 )); // // Keep track of the area of inserted points // if ( m_ushtIndices[0] > j ) m_ushtIndices[0] = j; if ( m_ushtIndices[1] < j ) m_ushtIndices[1] = j; if ( m_ushtIndices[2] > i ) m_ushtIndices[2] = i; if ( m_ushtIndices[3] < i ) m_ushtIndices[3] = i; } } p_ptrResults->m_blnDataSet = ( ulngDataPointsNew > 0 ); return ulngDataPointsNew; } ////////////////////////////////////////////////////////////////////////////////////////////////////////// // Grid 0 ////////////////////////////////////////////////////////////////////////////////////////////////////////// bool GRIB::Grid_0:: SetChopData(GRIB::ChopData * p_ptrData) { if ( m_uchrResolutionFlags & 0x10 || // The grid lines are not parallel to lat/long lines (m_uchrScanMode & 0x04) ) // The grid lines are scanned Y axis first { return false; } p_ptrData->m_ushtPointsY = m_ushtMeridianPoints; p_ptrData->m_ushtPointsX = m_ushtParallelPoints; p_ptrData->m_intFirstPointX = m_intFirstPointLon; p_ptrData->m_intFirstPointY = m_intFirstPointLat; p_ptrData->m_shtIncrementX = (short)(( m_uchrScanMode & 0x1 ) ? -m_shtIncrementDirectionI : m_shtIncrementDirectionI); p_ptrData->m_shtIncrementY = (short)(( m_uchrScanMode & 0x2 ) ? m_shtIncrementDirectionJ : -m_shtIncrementDirectionJ); return true; } bool GRIB::Grid_0:: Read(UTIL::Input * p_ptrIn, float * p_ptrCorners, unsigned long * p_ptrGridPoints) { if ( InputNumber(p_ptrIn, m_ushtParallelPoints) && // 7 - 8 InputNumber(p_ptrIn, m_ushtMeridianPoints) && // 9 - 10 InputNumber(p_ptrIn, m_intFirstPointLat) && // 11 - 13 InputNumber(p_ptrIn, m_intFirstPointLon) && // 14 - 16 p_ptrIn->Read(&m_uchrResolutionFlags, 1) && // 17 InputNumber(p_ptrIn, m_intLastPointLat) && // 18 - 20 InputNumber(p_ptrIn, m_intLastPointLon) && // 21 - 23 InputNumber(p_ptrIn, m_shtIncrementDirectionI) && // 24 - 25 InputNumber(p_ptrIn, m_shtIncrementDirectionJ) && // 26 - 27 p_ptrIn->Read(&m_uchrScanMode, 1) && // 28 p_ptrIn->Skip(4) == 4 ) // 29 - 32 { p_ptrCorners[0] = ((float)(m_intFirstPointLon)) * 0.001f; p_ptrCorners[1] = ((float)(m_intLastPointLon)) * 0.001f; p_ptrCorners[2] = ((float)(m_intFirstPointLat)) * 0.001f; p_ptrCorners[3] = ((float)(m_intLastPointLat)) * 0.001f; *p_ptrGridPoints = m_ushtParallelPoints * m_ushtMeridianPoints; if ( p_ptrCorners[2] > p_ptrCorners[3] ) UTIL::Swap(p_ptrCorners + 2, p_ptrCorners + 3, sizeof(float)); return true; } return false; } bool GRIB::Grid_0:: Write(UTIL::Output * p_ptrOut, const unsigned short * p_ptrNewIndices) { if ( m_uchrResolutionFlags & 0x10 || // The grid lines are not parallel to lat/long lines (m_uchrScanMode & 0x04) ) // The grid lines are scanned Y axis first { return false; } int intLastPointLat = m_intLastPointLat; int intLastPointLon = m_intLastPointLon; int intFirstPointLat = m_intFirstPointLat; int intFirstPointLon = m_intFirstPointLon; unsigned short ushtPointsI = m_ushtParallelPoints; unsigned short ushtPointsJ = m_ushtMeridianPoints; short shtIncrementI = (short)(( m_uchrScanMode & 0x1 ) ? -m_shtIncrementDirectionI : m_shtIncrementDirectionI); short shtIncrementJ = (short)(( m_uchrScanMode & 0x2 ) ? m_shtIncrementDirectionJ : -m_shtIncrementDirectionJ); if ( p_ptrNewIndices ) { ushtPointsI = (unsigned short)(p_ptrNewIndices[1] - p_ptrNewIndices[0]); ushtPointsJ = (unsigned short)(p_ptrNewIndices[3] - p_ptrNewIndices[2]); intFirstPointLon += p_ptrNewIndices[0] * shtIncrementI; intFirstPointLat += p_ptrNewIndices[2] * shtIncrementJ; intLastPointLon -= (m_ushtParallelPoints - p_ptrNewIndices[1]) * shtIncrementI; intLastPointLat -= (m_ushtMeridianPoints - p_ptrNewIndices[3]) * shtIncrementJ; } return ( OutputNumber(p_ptrOut, ushtPointsI) && OutputNumber(p_ptrOut, ushtPointsJ) && OutputNumber(p_ptrOut, intFirstPointLat) && OutputNumber(p_ptrOut, intFirstPointLon) && p_ptrOut->WriteByte(m_uchrResolutionFlags) && OutputNumber(p_ptrOut, intLastPointLat) && OutputNumber(p_ptrOut, intLastPointLon) && OutputNumber(p_ptrOut, m_shtIncrementDirectionI) && OutputNumber(p_ptrOut, m_shtIncrementDirectionJ) && p_ptrOut->WriteByte(m_uchrScanMode) && p_ptrOut->WriteByte(0, 3) ); } ////////////////////////////////////////////////////////////////////////////////////////////////////////// // Grid 1 ////////////////////////////////////////////////////////////////////////////////////////////////////////// bool GRIB::Grid_1:: SetChopData(GRIB::ChopData *) { return false; } bool GRIB::Grid_1:: Read(UTIL::Input * p_ptrIn, float * p_ptrCorners, unsigned long * p_ptrGridPoints) { if ( InputNumber(p_ptrIn, m_ushtParallelPoints) && // 7 - 8 InputNumber(p_ptrIn, m_ushtMeridianPoints) && // 9 - 10 InputNumber(p_ptrIn, m_intFirstPointLat) && // 11 - 13 InputNumber(p_ptrIn, m_intFirstPointLon) && // 14 - 16 p_ptrIn->Read(&m_uchrResolutionFlags, 1) == 0 && // 17 InputNumber(p_ptrIn, m_intLastPointLat) && // 18 - 20 InputNumber(p_ptrIn, m_intLastPointLon) && // 21 - 23 InputNumber(p_ptrIn, m_intIntersectionLat) && // 24 - 27 p_ptrIn->Skip(1) && // 27 p_ptrIn->Read(&m_uchrScanMode, 1) == 0 && // 28 InputNumber(p_ptrIn, m_intIncrementDirectionI) && // 29 - 31 InputNumber(p_ptrIn, m_intIncrementDirectionJ) && // 32 - 34 p_ptrIn->Skip(7) ) // 35 - 42 { p_ptrCorners[0] = ((float)(m_intFirstPointLon)) * 0.001f; p_ptrCorners[1] = ((float)(m_intLastPointLon)) * 0.001f; p_ptrCorners[2] = ((float)(m_intFirstPointLat)) * 0.001f; p_ptrCorners[3] = ((float)(m_intLastPointLat)) * 0.001f; *p_ptrGridPoints = m_ushtParallelPoints * m_ushtMeridianPoints; if ( p_ptrCorners[2] > p_ptrCorners[3] ) UTIL::Swap(p_ptrCorners + 2, p_ptrCorners + 3, sizeof(float)); return true; } return false; } bool GRIB::Grid_1:: Write(UTIL::Output *, const unsigned short *) { return false; } ////////////////////////////////////////////////////////////////////////////////////////////////////////// // Grid 3 ////////////////////////////////////////////////////////////////////////////////////////////////////////// bool GRIB::Grid_3:: SetChopData(GRIB::ChopData *) { return false; } bool GRIB::Grid_3:: Read(UTIL::Input * p_ptrIn, float * p_ptrCorners, unsigned long * p_ptrGridPoints) { if ( InputNumber(p_ptrIn, m_ushtAxisPointsX) && // 7 - 8 InputNumber(p_ptrIn, m_ushtAxisPointsY) && // 9 - 10 InputNumber(p_ptrIn, m_intFirstPointLat) && // 11 - 13 InputNumber(p_ptrIn, m_intFirstPointLon) && // 14 - 16 p_ptrIn->Read(&m_uchrResolutionFlags, 1) == 0 && // 17 InputNumber(p_ptrIn, m_intOrientationLov) && // 18 - 20 InputNumber(p_ptrIn, m_intDirectionLengthX) && // 21 - 23 InputNumber(p_ptrIn, m_intDirectionLengthY) && // 24 - 26 p_ptrIn->Read(&m_uchrProjectionCenter, 1) == 0 && // 27 p_ptrIn->Read(&m_uchrScanMode, 1) == 0 && // 28 InputNumber(p_ptrIn, m_intIntersectionLat1) && // 29 - 31 InputNumber(p_ptrIn, m_intIntersectionLat2) && // 32 - 34 InputNumber(p_ptrIn, m_intSouthPoleLat) && // 35 - 37 InputNumber(p_ptrIn, m_intSouthPoleLon) && // 38 - 40 p_ptrIn->Skip(2) ) // 41 - 42 { p_ptrCorners[0] = (float)(m_intFirstPointLon) * 0.001f; p_ptrCorners[2] = (float)(m_intFirstPointLat) * 0.001f; p_ptrCorners[1] = p_ptrCorners[0] + (float)((float)(m_ushtAxisPointsX) * MetersToLongitudeSpherical(p_ptrCorners[1], (float)(m_intDirectionLengthX)); p_ptrCorners[3] = p_ptrCorners[2] + (float)((float)(m_ushtAxisPointsY) * MetersToLatitudeSpherical((float)(m_intDirectionLengthY))); *p_ptrGridPoints = m_ushtAxisPointsX * m_ushtAxisPointsY; if ( p_ptrCorners[2] > p_ptrCorners[3] ) UTIL::Swap(p_ptrCorners + 2, p_ptrCorners + 3, sizeof(float)); return true; } return false; } bool GRIB::Grid_3:: Write(UTIL::Output *, const unsigned short *) { return false; } ////////////////////////////////////////////////////////////////////////////////////////////////////////// // Grid 5 ////////////////////////////////////////////////////////////////////////////////////////////////////////// bool GRIB::Grid_5:: SetChopData(GRIB::ChopData *) { return false; } bool GRIB::Grid_5:: Read(UTIL::Input * p_ptrIn, float * p_ptrCorners, unsigned long * p_ptrGridPoints) { if ( InputNumber(p_ptrIn, m_ushtAxisPointsX) && // 7 - 8 InputNumber(p_ptrIn, m_ushtAxisPointsY) && // 9 - 10 InputNumber(p_ptrIn, m_intFirstPointLat) && // 11 - 13 InputNumber(p_ptrIn, m_intFirstPointLon) && // 14 - 16 p_ptrIn->Read(&m_uchrResolutionFlags, 1) == 0 && // 17 InputNumber(p_ptrIn, m_intLongitudeOrientation) && // 18 - 20 InputNumber(p_ptrIn, m_intDirectionLengthX) && // 21 - 23 InputNumber(p_ptrIn, m_intDirectionLengthY) && // 24 - 26 p_ptrIn->Read(&m_uchrProjectionCenterFlag, 1) == 0 && // 27 p_ptrIn->Read(&m_uchrScanMode, 1) == 0 && // 28 p_ptrIn->Skip(3) ) // 29 - 32 { p_ptrCorners[0] = (float)(m_intFirstPointLon) * 0.001f; p_ptrCorners[2] = (float)(m_intFirstPointLat) * 0.001f; p_ptrCorners[1] = p_ptrCorners[0] + (float)((float)(m_ushtAxisPointsX) * MetersToLongitudeSpherical(p_ptrCorners[1], (float)(m_intDirectionLengthX)); p_ptrCorners[3] = p_ptrCorners[1] + (float)((float)(m_ushtAxisPointsY) * MetersToLatitudeSpherical((float)(m_intDirectionLengthY))); *p_ptrGridPoints = m_ushtAxisPointsX * m_ushtAxisPointsY; if ( p_ptrCorners[2] > p_ptrCorners[3] ) UTIL::Swap(p_ptrCorners + 2, p_ptrCorners + 3, sizeof(float)); return true; } return false; } bool GRIB::Grid_5:: Write(UTIL::Output *, const unsigned short *) { return false; }