36static double interp_angle(
double a0,
double a1,
double d,
double p) {
41 double a = (1 - d) * a0 + d * a1;
42 if (a < (p == 180. ? 0. : -p)) a += 2 * p;
47void GribRecord::print() {
49 "%d: idCenter=%d idModel=%d idGrid=%d dataType=%d levelType=%d "
50 "levelValue=%d hr=%f\n",
62 if (rec.data !=
nullptr) {
63 int size = rec.Ni * rec.Nj;
64 this->data =
new double[size];
65 for (
int i = 0; i < size; i++) this->data[i] = rec.data[i];
67 if (rec.BMSbits !=
nullptr) {
68 int size = rec.BMSsize;
69 this->BMSbits =
new zuchar[size];
70 for (
int i = 0; i < size; i++) this->BMSbits[i] = rec.BMSbits[i];
74bool GribRecord::GetInterpolatedParameters(
76 double &La2,
double &Lo2,
double &Di,
double &Dj,
int &im1,
int &jm1,
77 int &im2,
int &jm2,
int &Ni,
int &Nj,
int &rec1offi,
int &rec1offj,
78 int &rec2offi,
int &rec2offj) {
79 if (!rec1.isOk() || !rec2.isOk())
return false;
82 if (rec1.
getDj() * rec2.
getDj() <= 0)
return false;
90 La1 = wxMax(rec1.La1, rec2.La1), La2 = wxMin(rec1.La2, rec2.La2);
92 La1 = wxMin(rec1.La1, rec2.La1), La2 = wxMax(rec1.La2, rec2.La2);
101 double rec1offdi = 0, rec2offdi = 0;
102 double rec1offdj = 0., rec2offdj = 0.;
104 double iiters = rec2.Di / rec1.Di;
107 im1 = 1, im2 = iiters;
109 im1 = iiters, im2 = 1;
111 for (i = 0; i < iiters; i++) {
112 rec1offdi = (
Lo1 - rec1.
Lo1) / rec1.Di;
113 rec2offdi = (
Lo1 - rec2.
Lo1) / rec2.Di;
114 if (rec1offdi == floor(rec1offdi) && rec2offdi == floor(rec2offdi))
break;
116 Lo1 += wxMin(rec1.Di, rec2.Di);
121 double jiters = rec2.Dj / rec1.Dj;
124 jm1 = 1, jm2 = jiters;
126 jm1 = jiters, jm2 = 1;
128 for (j = 0; j < jiters; j++) {
129 rec1offdj = (La1 - rec1.La1) / rec1.Dj;
130 rec2offdj = (La1 - rec2.La1) / rec2.Dj;
131 if (rec1offdj == floor(rec1offdj) && rec2offdj == floor(rec2offdj))
break;
133 La1 += Dj < 0 ? wxMax(rec1.
getDj(), rec2.
getDj())
140 if (La1 * Dj > La2 * Dj ||
Lo1 >
Lo2)
return false;
143 Ni = (
Lo2 -
Lo1) / Di + 1, Nj = (La2 - La1) / Dj + 1;
146 Lo2 =
Lo1 + (Ni - 1) * Di, La2 = La1 + (Nj - 1) * Dj;
148 rec1offi = rec1offdi, rec2offi = rec2offdi;
149 rec1offj = rec1offdj, rec2offj = rec2offdj;
151 if (!rec1.data || !rec2.data)
return false;
162 double La1,
Lo1, La2,
Lo2, Di, Dj;
163 int im1, jm1, im2, jm2;
164 int Ni, Nj, rec1offi, rec1offj, rec2offi, rec2offj;
165 if (!GetInterpolatedParameters(rec1, rec2, La1,
Lo1, La2,
Lo2, Di, Dj, im1,
166 jm1, im2, jm2, Ni, Nj, rec1offi, rec1offj,
172 double *data =
new double[size];
174 zuchar *BMSbits =
nullptr;
175 if (rec1.BMSbits !=
nullptr && rec2.BMSbits !=
nullptr)
176 BMSbits =
new zuchar[(Ni * Nj - 1) / 8 + 1]();
178 for (
int i = 0; i < Ni; i++)
179 for (
int j = 0; j < Nj; j++) {
181 int i1 = (j * jm1 + rec1offj) * rec1.Ni + i * im1 + rec1offi;
182 int i2 = (j * jm2 + rec2offj) * rec2.Ni + i * im2 + rec2offi;
183 double data1 = rec1.data[i1], data2 = rec2.data[i2];
184 if (data1 == GRIB_NOTDEF || data2 == GRIB_NOTDEF)
185 data[in] = GRIB_NOTDEF;
188 data[in] = (1 - d) * data1 + d * data2;
190 data[in] = interp_angle(data1, data2, d, 180.);
194 int b1 = rec1.BMSbits[i1 >> 3] & 1 << (i1 & 7);
195 int b2 = rec2.BMSbits[i2 >> 3] & 1 << (i2 & 7);
197 BMSbits[in >> 3] |= 1 << (in & 7);
199 BMSbits[in >> 3] &= ~(1 << (in & 7));
208 ret->Di = Di, ret->Dj = Dj;
209 ret->Ni = Ni, ret->Nj = Nj;
211 ret->La1 = La1, ret->La2 = La2;
215 ret->BMSbits = BMSbits;
217 ret->latMin = wxMin(La1, La2), ret->latMax = wxMax(La1, La2);
218 ret->lonMin =
Lo1, ret->lonMax =
Lo2;
231 double La1,
Lo1, La2,
Lo2, Di, Dj;
232 int im1, jm1, im2, jm2;
233 int Ni, Nj, rec1offi, rec1offj, rec2offi, rec2offj;
236 if (!GetInterpolatedParameters(rec1x, rec2x, La1,
Lo1, La2,
Lo2, Di, Dj, im1,
237 jm1, im2, jm2, Ni, Nj, rec1offi, rec1offj,
241 if (!rec1y.data || !rec2y.data || !rec1y.isOk() || !rec2y.isOk() ||
242 rec1x.Di != rec1y.Di || rec1x.Dj != rec1y.Dj || rec2x.Di != rec2y.Di ||
243 rec2x.Dj != rec2y.Dj || rec1x.Ni != rec1y.Ni || rec1x.Nj != rec1y.Nj ||
244 rec2x.Ni != rec2y.Ni || rec2x.Nj != rec2y.Nj) {
253 double *datax =
new double[size], *datay =
new double[size];
254 for (
int i = 0; i < Ni; i++) {
255 for (
int j = 0; j < Nj; j++) {
257 int i1 = (j * jm1 + rec1offj) * rec1x.Ni + i * im1 + rec1offi;
258 int i2 = (j * jm2 + rec2offj) * rec2x.Ni + i * im2 + rec2offi;
259 double data1x = rec1x.data[i1], data1y = rec1y.data[i1];
260 double data2x = rec2x.data[i2], data2y = rec2y.data[i2];
261 if (data1x == GRIB_NOTDEF || data1y == GRIB_NOTDEF ||
262 data2x == GRIB_NOTDEF || data2y == GRIB_NOTDEF) {
263 datax[in] = GRIB_NOTDEF;
264 datay[in] = GRIB_NOTDEF;
266 double data1m = sqrt(pow(data1x, 2) + pow(data1y, 2));
267 double data2m = sqrt(pow(data2x, 2) + pow(data2y, 2));
268 double datam = (1 - d) * data1m + d * data2m;
270 double data1a = atan2(data1y, data1x);
271 double data2a = atan2(data2y, data2x);
272 if (data1a - data2a > M_PI)
274 else if (data2a - data1a > M_PI)
276 double dataa = (1 - d) * data1a + d * data2a;
278 datax[in] = datam * cos(dataa);
279 datay[in] = datam * sin(dataa);
290 ret->Di = Di, ret->Dj = Dj;
291 ret->Ni = Ni, ret->Nj = Nj;
293 ret->La1 = La1, ret->La2 = La2;
297 ret->BMSbits =
nullptr;
300 ret->latMin = wxMin(La1, La2), ret->latMax = wxMax(La1, La2);
301 ret->lonMin =
Lo1, ret->lonMax =
Lo2;
307 rety->BMSbits =
nullptr;
318 if (rec1.data && rec2.data && rec1.Ni == rec2.Ni && rec1.Nj == rec2.Nj) {
319 int size = rec1.Ni * rec1.Nj;
320 for (
int i = 0; i < size; i++)
321 if (rec1.data[i] == GRIB_NOTDEF || rec2.data[i] == GRIB_NOTDEF)
322 rec->data[i] = GRIB_NOTDEF;
324 rec->data[i] = sqrt(pow(rec1.data[i], 2) + pow(rec2.data[i], 2));
328 if (rec1.BMSbits !=
nullptr && rec2.BMSbits !=
nullptr) {
329 if (rec1.BMSsize == rec2.BMSsize) {
330 int size = rec1.BMSsize;
331 for (
int i = 0; i < size; i++)
332 rec->BMSbits[i] = rec1.BMSbits[i] & rec2.BMSbits[i];
341 if (pDIR->data && pSPEED->data && pDIR->Ni == pSPEED->Ni &&
342 pDIR->Nj == pSPEED->Nj) {
343 int size = pDIR->Ni * pDIR->Nj;
344 for (
int i = 0; i < size; i++) {
345 if (pDIR->data[i] != GRIB_NOTDEF && pSPEED->data[i] != GRIB_NOTDEF) {
346 double dir = pDIR->data[i];
347 double speed = pSPEED->data[i];
348 pDIR->data[i] = -speed * sin(dir * M_PI / 180.);
349 pSPEED->data[i] = -speed * cos(dir * M_PI / 180.);
352 if (pDIR->
dataType == GRB_WIND_DIR) {
362void GribRecord::Substract(
const GribRecord &rec,
bool pos) {
364 if (rec.data == 0 || !rec.isOk())
return;
366 if (data == 0 || !isOk())
return;
368 if (Ni != rec.Ni || Nj != rec.Nj)
return;
370 zuint size = Ni * Nj;
371 for (zuint i = 0; i < size; i++) {
372 if (rec.data[i] == GRIB_NOTDEF)
continue;
373 if (data[i] == GRIB_NOTDEF) {
374 data[i] = -rec.data[i];
377 BMSbits[i >> 3] |= 1 << (i & 7);
381 data[i] -= rec.data[i];
382 if (data[i] < 0. && pos) {
390void GribRecord::Average(
const GribRecord &rec) {
400 if (rec.data == 0 || !rec.isOk())
return;
402 if (data == 0 || !isOk())
return;
404 if (Ni != rec.Ni || Nj != rec.Nj)
return;
411 if (d2 <= d1)
return;
413 zuint size = Ni * Nj;
414 double diff = d2 - d1;
415 for (zuint i = 0; i < size; i++) {
416 if (rec.data[i] == GRIB_NOTDEF)
continue;
417 if (data[i] == GRIB_NOTDEF)
continue;
419 data[i] = (data[i] * d2 - rec.data[i] * d1) / diff;
424void GribRecord::setDataType(
const zuchar t) {
429std::string GribRecord::makeKey(
430 int dataType,
int levelType,
438 return std::string(k.mb_str());
441GribRecord::~GribRecord() {
456void GribRecord::multiplyAllData(
double k) {
457 if (data == 0 || !isOk())
return;
459 for (zuint j = 0; j < Nj; j++) {
460 for (zuint i = 0; i < Ni; i++) {
461 if (isDefined(i, j)) {
462 data[j * Ni + i] *= k;
469void GribRecord::setRecordCurrentDate(time_t t) {
472 struct tm *date = gmtime(&t);
474 zuint year = date->tm_year + 1900;
475 zuint month = date->tm_mon + 1;
476 zuint day = date->tm_mday;
477 zuint hour = date->tm_hour;
478 zuint minute = date->tm_min;
479 sprintf(strCurDate,
"%04d-%02d-%02d %02d:%02d", year, month, day, hour,
484static bool isleapyear(zuint y) {
485 return ((y % 4 == 0) && (y % 100 != 0)) || (y % 400 == 0);
488time_t GribRecord::makeDate(zuint year, zuint month, zuint day, zuint hour,
489 zuint min, zuint sec) {
490 if (year < 1970 || year > 2200 || month < 1 || month > 12 || day < 1)
495 for (zuint y = 1970; y < year; y++) {
496 r += 365 * 24 * 3600;
497 if (isleapyear(y)) r += 24 * 3600;
499 for (zuint m = 1; m < month; m++) {
502 if (isleapyear(year)) r += 24 * 3600;
503 }
else if (m == 1 || m == 3 || m == 5 || m == 7 || m == 8 || m == 10 ||
510 r += (day - 1) * 24 * 3600;
520 bool numericalInterpolation,
522 if (!
ok || Di == 0 || Dj == 0)
return GRIB_NOTDEF;
524 if (!isPointInMap(px, py)) {
526 if (!isPointInMap(px, py)) {
528 if (!isPointInMap(px, py)) {
534 pi = (px -
Lo1) / Di;
535 pj = (py - La1) / Dj;
542 unsigned int i1 = pi + 1, j1 = pj + 1;
544 if (i1 >= Ni) i1 = i0;
546 if (j1 >= Nj) j1 = j0;
552 if (!numericalInterpolation) {
553 if (dx >= 0.5) i0 = i1;
554 if (dy >= 0.5) j0 = j1;
571 if (
getValue(i0, j0) != GRIB_NOTDEF) nbval++;
572 if (
getValue(i1, j0) != GRIB_NOTDEF) nbval++;
573 if (
getValue(i0, j1) != GRIB_NOTDEF) nbval++;
574 if (
getValue(i1, j1) != GRIB_NOTDEF) nbval++;
576 if (nbval < 3)
return GRIB_NOTDEF;
578 dx = (3.0 - 2.0 * dx) * dx * dx;
579 dy = (3.0 - 2.0 * dy) * dy * dy;
581 double xa, xb, xc, kx, ky;
593 double x1 = (1.0 - dx) * x00 + dx * x10;
594 double x2 = (1.0 - dx) * x01 + dx * x11;
595 return (1.0 - dy) * x1 + dy * x2;
597 double x1 = interp_angle(x00, x01, dx, 180.);
598 double x2 = interp_angle(x10, x11, dx, 180.);
599 return interp_angle(x1, x2, dy, 180.);
604 if (dir)
return GRIB_NOTDEF;
607 if (
getValue(i0, j0) == GRIB_NOTDEF) {
614 }
else if (
getValue(i0, j1) == GRIB_NOTDEF) {
621 }
else if (
getValue(i1, j0) == GRIB_NOTDEF) {
638 if (k < 0 || k > 1)
return GRIB_NOTDEF;
640 if (k == 0)
return xa;
643 double vx = k * xb + (1 - k) * xa;
644 double vy = k * xc + (1 - k) * xa;
647 return k2 * vx + (1 - k2) * vy;
653 double py,
bool numericalInterpolation) {
654 if (!GRX || !GRY)
return false;
656 if (!GRX->
ok || !GRY->
ok || GRX->Di == 0 || GRX->Dj == 0)
return false;
658 if (!GRX->isPointInMap(px, py) || !GRY->isPointInMap(px, py)) {
660 if (!GRX->isPointInMap(px, py) || !GRY->isPointInMap(px, py)) {
662 if (!GRX->isPointInMap(px, py) || !GRY->isPointInMap(px, py)) {
668 pi = (px - GRX->
Lo1) / GRX->Di;
669 pj = (py - GRX->La1) / GRX->Dj;
676 unsigned int i1 = pi + 1, j1 = pj + 1;
677 if (i1 >= GRX->Ni) i1 = i0;
679 if (j1 >= GRX->Nj) j1 = j0;
685 if (!numericalInterpolation) {
687 if (dx >= 0.5) i0 = i1;
688 if (dy >= 0.5) j0 = j1;
692 if (vx == GRIB_NOTDEF || vy == GRIB_NOTDEF)
return false;
694 M = sqrt(vx * vx + vy * vy);
695 A = atan2(-vx, -vy) * 180 / M_PI;
711 if (GRY->
getValue(i0, j0) != GRIB_NOTDEF) nbval++;
712 if (GRY->
getValue(i1, j0) != GRIB_NOTDEF) nbval++;
713 if (GRY->
getValue(i0, j1) != GRIB_NOTDEF) nbval++;
714 if (GRY->
getValue(i1, j1) != GRIB_NOTDEF) nbval++;
716 if (nbval <= 3)
return false;
719 if (GRX->
getValue(i0, j0) != GRIB_NOTDEF) nbval++;
720 if (GRX->
getValue(i1, j0) != GRIB_NOTDEF) nbval++;
721 if (GRX->
getValue(i0, j1) != GRIB_NOTDEF) nbval++;
722 if (GRX->
getValue(i1, j1) != GRIB_NOTDEF) nbval++;
724 if (nbval <= 3)
return false;
726 dx = (3.0 - 2.0 * dx) * dx * dx;
727 dy = (3.0 - 2.0 * dy) * dy * dy;
736 double x00m = sqrt(x00x * x00x + x00y * x00y), x00a = atan2(x00x, x00y);
739 double x01m = sqrt(x01x * x01x + x01y * x01y), x01a = atan2(x01x, x01y);
742 double x10m = sqrt(x10x * x10x + x10y * x10y), x10a = atan2(x10x, x10y);
745 double x11m = sqrt(x11x * x11x + x11y * x11y), x11a = atan2(x11x, x11y);
747 double x0m = (1 - dx) * x00m + dx * x10m,
748 x0a = interp_angle(x00a, x10a, dx, M_PI);
750 double x1m = (1 - dx) * x01m + dx * x11m,
751 x1a = interp_angle(x01a, x11a, dx, M_PI);
753 M = (1 - dy) * x0m + dy * x1m;
754 A = interp_angle(x0a, x1a, dy, M_PI);
763 double xa, xb, xc, kx, ky;
807 double vx = k*xb + (1-k)*xa;
808 double vy = k*xc + (1-k)*xa;
811 val = k2*vx + (1-k2)*vy;
GRIB Record Base Class Implementation.
Represents a meteorological data grid from a GRIB (Gridded Binary) file.
static void Polar2UV(GribRecord *pDIR, GribRecord *pSPEED)
Converts wind or current values from polar (direction/speed) to cartesian (U/V) components.
int getPeriodP1() const
Returns the start of the period (P1) used for this record.
zuchar dataType
Parameter identifier as defined by GRIB tables.
double getDi() const
Returns the grid spacing in longitude (i) direction in degrees.
zuchar levelType
Vertical level type indicator.
double Lo2
Grid end coordinates.
double getDj() const
Returns the grid spacing in latitude (j) direction in degrees.
GribRecord(const GribRecord &rec)
Copy constructor performs a deep copy of the GribRecord.
double Lo1
Grid origin coordinates.
time_t curDate
Unix timestamp of when this forecast is valid.
int getPeriodP2() const
Returns the end of the period (P2) used for this record.
static GribRecord * Interpolated2DRecord(GribRecord *&rety, const GribRecord &rec1x, const GribRecord &rec1y, const GribRecord &rec2x, const GribRecord &rec2y, double d)
Creates temporally interpolated records for vector fields (wind, currents).
double getInterpolatedValue(double px, double py, bool numericalInterpolation=true, bool dir=false) const
Get spatially interpolated value at exact lat/lon position.
bool IsDuplicated
Indicates if this record was created through copying rather than direct reading.
zuchar idCenter
Originating center ID as defined by WMO common table C-1.
static GribRecord * InterpolatedRecord(const GribRecord &rec1, const GribRecord &rec2, double d, bool dir=false)
Creates a new GribRecord by temporally interpolating between two time points.
bool ok
Indicates record validity.
zuchar idGrid
Grid identifier used by the originating center.
time_t refDate
Unix timestamp of model initialization time.
bool hasBMS
Indicates presence of a bitmap section.
static bool getInterpolatedValues(double &M, double &A, const GribRecord *GRX, const GribRecord *GRY, double px, double py, bool numericalInterpolation=true)
Gets spatially interpolated wind or current vector values at a specific latitude/longitude point.
double getValue(int i, int j) const
Returns the data value at a specific grid point.
bool m_bfilled
Indicates whether the data array has been populated.
zuint levelValue
Numeric value associated with levelType.
zuchar idModel
Model identifier within the originating center.
std::string dataKey
Unique string identifier constructed from data type, level type, and level value.