/// <summary> /// Constructor /// </summary> /// <param name="br">binary reader</param> public GRIB1BitMapSection(BinaryReader br) { byte[] bytes = br.ReadBytes(3); Length = Bytes2Number.Uint3(bytes[0], bytes[1], bytes[2]); int unUsed = Convert.ToInt32(br.ReadByte()); bytes = br.ReadBytes(2); int bm = Bytes2Number.Int2(bytes[0], bytes[1]); if (bm != 0) { if ((Length - 6) == 0) { return; } br.ReadBytes(Length - 6); return; } byte[] data = br.ReadBytes(Length - 6); Bitmap = new bool[(Length - 6) * 8 - unUsed]; int[] bitmask = { 128, 64, 32, 16, 8, 4, 2, 1 }; for (int i = 0; i < Bitmap.Length; i++) { Bitmap[i] = (data[i / 8] & bitmask[i % 8]) != 0; } }
/// <summary> /// Constructor /// </summary> /// <param name="br">binary reader</param> public GRIB1IndicatorSection(BinaryReader br) { Length = 8; Title = ASCIIEncoding.ASCII.GetString(br.ReadBytes(4)); byte[] bytes = br.ReadBytes(3); RecordLength = Bytes2Number.Uint3(bytes[0], bytes[1], bytes[2]); Edition = Convert.ToInt32(br.ReadByte()); }
/// <summary> /// Constructor /// </summary> /// <param name="br">binary reader</param> public GRIB1ProductDefineSection(BinaryReader br) { byte[] bytes = br.ReadBytes(3); Length = Bytes2Number.Uint3(bytes[0], bytes[1], bytes[2]); br.BaseStream.Seek(-3, SeekOrigin.Current); bytes = br.ReadBytes(Length); TableVersion = Convert.ToInt32(bytes[3]); CenterID = Convert.ToInt32(bytes[4]); TypeGenProcess = Convert.ToInt32(bytes[5]); GridID = Convert.ToInt32(bytes[6]); int ifExists = Convert.ToInt32(bytes[7]); GDSExist = (ifExists & 128) == 128; BMSExist = (ifExists & 64) == 64; ParameterIndicator = Convert.ToInt32(bytes[8]); Parameter = GRIBParameterTable.GetDefaultParameter(ParameterIndicator); LevelType = Convert.ToInt32(bytes[9]); LevelValue = Bytes2Number.Uint2(bytes[10], bytes[11]); int year = Convert.ToInt32(bytes[12]); int month = Convert.ToInt32(bytes[13]); int day = Convert.ToInt32(bytes[14]); int hour = Convert.ToInt32(bytes[15]); int minute = Convert.ToInt32(bytes[16]); ForecastTimeUnit = Convert.ToInt32(bytes[17]); P1 = Convert.ToInt32(bytes[18]); P2 = Convert.ToInt32(bytes[19]); TimeRangeIndicator = Convert.ToInt32(bytes[20]); AveInclude = Bytes2Number.Int2(bytes[21], bytes[22]); NumMissing = Convert.ToInt32(bytes[23]); InitialCentral = Convert.ToInt32(bytes[24]); BaseTime = new DateTime((InitialCentral - 1) * 100 + year, month, day, hour, minute, 0); SubCenterID = Convert.ToInt32(bytes[25]); DecimalScale = Bytes2Number.Int2(bytes[26], bytes[27]); //octets 27-28 }
/// <summary> /// Constructor /// </summary> /// <param name="br">binary reader</param> /// <param name="decimalscale">decimal scale</param> /// <param name="bms">GRIB 1 BMS</param> /// <param name="scanMode">scan mode</param> /// <param name="Xlength">X coordinate number</param> /// <param name="Ylength">Y coordinate number</param> public GRIB1BinaryDataSection(BinaryReader br, int decimalscale, GRIB1BitMapSection bms, int scanMode, int Xlength, int Ylength) { byte[] bytes = br.ReadBytes(3); Length = Bytes2Number.Uint3(bytes[0], bytes[1], bytes[2]); br.BaseStream.Seek(-3, SeekOrigin.Current); bytes = br.ReadBytes(11); //Read before the data array. // octet 4, 1st half (packing flag) int unusedbits = Convert.ToInt32(bytes[3]); if ((unusedbits & 192) != 0) { throw new NotSupportedException( "Grib1BinaryDataSection: (octet 4, 1st half) not grid point data and simple packing "); } // octet 4, 2nd half (number of unused bits at end of this section) unusedbits = unusedbits & 15; BinScale = Bytes2Number.Int2(bytes[4], bytes[5]); RefValue = Bytes2Number.Float4(bytes[6], bytes[7], bytes[8], bytes[9]); NumBits = Convert.ToInt32(bytes[10]); if (NumBits == 0) { IsConstant = true; } // *** read values ************************************************************ float refd = (float)(Math.Pow(10.0, -decimalscale) * RefValue); float scale = (float)(Math.Pow(10.0, -decimalscale) * Math.Pow(2.0, BinScale)); if (bms != null) { bool[] bitmap = bms.Bitmap; Data = new double[bitmap.Length]; for (int i = 0; i < bitmap.Length; i++) { if (bitmap[i]) { if (!IsConstant) { Data[i] = refd + scale * Bits2UInt(NumBits, br); if (Data[i] > MaxValue) { MaxValue = Data[i]; } if (Data[i] < MinValue) { MinValue = Data[i]; } } else {// rdg - added this to handle a constant valued parameter Data[i] = refd; } } else { Data[i] = UNDEF; } } ScanningModeCheck(scanMode, Xlength); } else { if (!IsConstant) { Data = new double[((Length - 11) * 8 - unusedbits) / NumBits]; for (int i = 0; i < Data.Length; i++) { Data[i] = refd + scale * Bits2UInt(NumBits, br); if (Data[i] > MaxValue) { MaxValue = this.Data[i]; } if (Data[i] < MinValue) { MinValue = this.Data[i]; } } ScanningModeCheck(scanMode, Xlength); } else { // constant valued - same min and max Data = new double[Xlength * Ylength]; MaxValue = refd; MinValue = refd; for (int i = 0; i < Data.Length; i++) { Data[i] = refd; } } } }
/// <summary> /// Constructor /// </summary> /// <param name="br">binary reader</param> public GRIB1GridDefineSection(BinaryReader br) { byte[] bytes = br.ReadBytes(3); Length = Bytes2Number.Uint3(bytes[0], bytes[1], bytes[2]); br.BaseStream.Seek(-3, SeekOrigin.Current); bytes = br.ReadBytes(Length); NV = Convert.ToInt32(bytes[3]); P_VorL = Convert.ToInt32(bytes[4]); GridType = Convert.ToInt32(bytes[5]); double checkSum = GridType; if (GridType != 50) //Values same up to resolution { NX = Bytes2Number.Uint2(bytes[6], bytes[7]); if (NX >= 65535) { ThinnedGrid = true; } checkSum = 7 * checkSum + NX; NY = Bytes2Number.Uint2(bytes[8], bytes[9]); checkSum = 7 * checkSum + NY; Lat1 = Bytes2Number.Int3(bytes[10], bytes[11], bytes[12]) / 1000.0; checkSum = 7 * checkSum + Lat1; Lon1 = Bytes2Number.Int3(bytes[13], bytes[14], bytes[15]) / 1000.0; checkSum = 7 * checkSum + Lon1; Resolution = Convert.ToInt32(bytes[16]); } switch (GridType) { case 0: // Standard Lat/Lon grid, no rotation case 4: //Gaussian Lat/Lon grid case 10: // Rotated Lat/Lon grid case 201: //Arkawa semi-staggered E-grid on rotated lat/lon grid case 202: //Arakawa filled E -grid on rotated lat/lon grid Lat2 = Bytes2Number.Int3(bytes[17], bytes[18], bytes[19]) / 1000.0; checkSum = 7 * checkSum + Lat2; Lon2 = Bytes2Number.Int3(bytes[20], bytes[21], bytes[22]) / 1000.0; checkSum = 7 * checkSum + Lon2; //Increments given if (Resolution == 128) { DX = Bytes2Number.Uint2(bytes[23], bytes[24]) / 1000.0; //if (ThinnedGrid) //{ // NX = 73; // DX = 1.25; //} if (GridType == 4) { NP = Bytes2Number.Uint2(bytes[25], bytes[26]); DY = NP / 1000.0; //try for error data } else { DY = Bytes2Number.Uint2(bytes[25], bytes[26]) / 1000.0; } ScanMode = Convert.ToInt32(bytes[27]); if ((ScanMode & 128) != 0) { DX = -DX; } //if ((ScanMode & 64) != 64 && Lat2 < Lat1) // DY = -DY; //if ((ScanMode & 64) != 64 || Lat2 < Lat1) // DY = -DY; if (Lat2 < Lat1) { DY = -DY; } } else { //Calculate increments DX = (Lon2 - Lon1) / (NX - 1); DY = (Lat2 - Lat1) / (NY - 1); } if (DX < 0) { XReverse = true; } if (DY < 0) { YReverse = true; } if (ThinnedGrid) { ThinnedXNums = new int[NY]; ThinnedGridNum = 0; for (int i = 0; i < NY; i++) { ThinnedXNums[i] = Bytes2Number.Int2(bytes[32 + i * 2], bytes[33 + i * 2]); ThinnedGridNum += ThinnedXNums[i]; if (i == 0) { NX = ThinnedXNums[i]; } else { if (NX < ThinnedXNums[i]) { NX = ThinnedXNums[i]; } } } DX = Math.Abs(Lon2 - Lon1) / (NX - 1); } if (GridType == 10) { // Rotated Lat/Lon grid, Lat (octets 33-35), Lon (octets 36-38), rotang (octets 39-42) Latsp = Bytes2Number.Int3(bytes[32], bytes[33], bytes[34]) / 1000.0; Lonsp = Bytes2Number.Int3(bytes[35], bytes[36], bytes[37]) / 1000.0; Rotang = Bytes2Number.Int4(bytes[38], bytes[39], bytes[40], bytes[41]) / 1000.0; } break; case 1: //Mercator projection Lat2 = Bytes2Number.Int3(bytes[17], bytes[18], bytes[19]) / 1000.0; checkSum = 7 * checkSum + Lat2; Lon2 = Bytes2Number.Int3(bytes[20], bytes[21], bytes[22]) / 1000.0; checkSum = 7 * checkSum + Lon2; Latin1 = Bytes2Number.Int3(bytes[23], bytes[24], bytes[25]) / 1000.0; checkSum = 7 * checkSum + Latin1; ScanMode = bytes[27]; DX = Bytes2Number.Int3(bytes[28], bytes[29], bytes[30]); DY = Bytes2Number.Int3(bytes[31], bytes[32], bytes[33]); break; case 3: //Lambert projection Lov = Bytes2Number.Int3(bytes[17], bytes[18], bytes[19]) / 1000.0; checkSum = 7 * checkSum + Lov; DX = Bytes2Number.Int3(bytes[20], bytes[21], bytes[22]); DY = Bytes2Number.Int3(bytes[23], bytes[24], bytes[25]); Proj_Center = bytes[26]; ScanMode = bytes[27]; Latin1 = Bytes2Number.Int3(bytes[28], bytes[29], bytes[30]) / 1000.0; checkSum = 7 * checkSum + Latin1; Latin2 = Bytes2Number.Int3(bytes[31], bytes[32], bytes[33]) / 1000.0; checkSum = 7 * checkSum + Latin2; Latsp = Bytes2Number.Int3(bytes[34], bytes[35], bytes[36]) / 1000.0; checkSum = 7 * checkSum + Latsp; Lonsp = Bytes2Number.Int3(bytes[37], bytes[38], bytes[39]) / 1000.0; checkSum = 7 * checkSum + Lonsp; break; case 5: //Polar stereographic projection case 87: Lov = Bytes2Number.Int3(bytes[17], bytes[18], bytes[19]) / 1000.0; checkSum = 7 * checkSum + Lov; if (GridType == 87) { Lon2 = Bytes2Number.Int3(bytes[20], bytes[21], bytes[22]) / 1000.0; checkSum = 7 * checkSum + Lon2; } DX = Bytes2Number.Int3(bytes[20], bytes[21], bytes[22]); DY = Bytes2Number.Int3(bytes[23], bytes[24], bytes[25]); Proj_Center = bytes[26]; ScanMode = bytes[27]; break; default: break; } // This switch uses the grid_type to define how to handle the // southpole information. switch (GridType) { case 0: // Standard Lat/Lon grid, no rotation Latsp = -90.0; Lonsp = 0.0; Rotang = 0.0; break; default: // No knowledge yet // NEED to fix this later, if supporting other grid types Latsp = Double.NaN; Lonsp = Double.NaN; Rotang = Double.NaN; break; } }