@@ -5193,6 +5193,15 @@ GMT_LOCAL int gmtapi_export_image (struct GMTAPI_CTRL *API, int object_ID, unsig
5193
5193
return (GMT_NOERROR);
5194
5194
}
5195
5195
5196
+ unsigned int gmt_whole_earth (struct GMT_CTRL *GMT, double we_in[], double we_out[]) {
5197
+ /* Determines if this is a global geographic grid and we want the whole world, regardless of central longitude */
5198
+ if (!gmt_M_is_geographic (GMT, GMT_IN)) return 0;
5199
+ if (!gmt_M_360_range (we_in[XLO], we_in[XHI])) return 0;
5200
+ if (!gmt_M_360_range (we_out[XLO], we_out[XHI])) return 0;
5201
+ if (doubleAlmostEqualZero (we_in[XLO], we_out[XLO])) return 2; /* Both regions are the same */
5202
+ return 1; /* Different central meridians */
5203
+ }
5204
+
5196
5205
/*! . */
5197
5206
GMT_LOCAL struct GMT_GRID * gmtapi_import_grid (struct GMTAPI_CTRL *API, int object_ID, unsigned int mode, struct GMT_GRID *grid) {
5198
5207
/* Handles the reading of a 2-D grid given in one of several ways.
@@ -5207,10 +5216,10 @@ GMT_LOCAL struct GMT_GRID * gmtapi_import_grid (struct GMTAPI_CTRL *API, int obj
5207
5216
5208
5217
int item, new_item, new_ID;
5209
5218
bool done = true, new = false, row_by_row;
5210
- uint64_t row, col, kol, i0, i1, j0, j1, ij, ij_orig;
5219
+ uint64_t row, col, kol, row_out, i0, i1, j0, j1, ij, ij_orig;
5211
5220
size_t size;
5212
5221
unsigned int both_set = (GMT_CONTAINER_ONLY | GMT_DATA_ONLY);
5213
- unsigned int method;
5222
+ unsigned int method, start_over_method = 0 ;
5214
5223
double dx, dy, d;
5215
5224
p_func_uint64_t GMT_2D_to_index = NULL;
5216
5225
struct GMT_GRID *G_obj = NULL, *G_orig = NULL;
@@ -5243,6 +5252,9 @@ GMT_LOCAL struct GMT_GRID * gmtapi_import_grid (struct GMTAPI_CTRL *API, int obj
5243
5252
if (grid->header->wesn[XLO] == S_obj->wesn[XLO] && grid->header->wesn[XHI] == S_obj->wesn[XHI] && grid->header->wesn[YLO] == S_obj->wesn[YLO] && grid->header->wesn[YHI] == S_obj->wesn[YHI]) S_obj->region = false;
5244
5253
}
5245
5254
method = gmtapi_set_method (S_obj); /* Get the actual method to use since may be MATRIX or VECTOR masquerading as GRID */
5255
+
5256
+ start_over_import_grid: /* We may get here if we cannot honor a GMT_IS_REFERENCE from below */
5257
+
5246
5258
switch (method) {
5247
5259
/* Status: This case is fully tested and operational */
5248
5260
case GMT_IS_FILE: /* Name of a grid file on disk */
@@ -5332,26 +5344,32 @@ GMT_LOCAL struct GMT_GRID * gmtapi_import_grid (struct GMTAPI_CTRL *API, int obj
5332
5344
GH->alloc_mode = GMT_ALLOC_INTERNALLY;
5333
5345
if (!S_obj->region && gmt_grd_pad_status (GMT, G_obj->header, GMT->current.io.pad)) { /* Want an exact copy with no subset and same padding */
5334
5346
gmt_M_memcpy (G_obj->data, G_orig->data, G_orig->header->size, gmt_grdfloat);
5347
+ gmt_BC_init (GMT, G_obj->header); /* Initialize grid interpolation and boundary condition parameters */
5348
+ if (gmt_M_err_pass (GMT, gmt_grd_BC_set (GMT, G_obj, GMT_IN), "Grid memory"))
5349
+ return_null (API, GMT_GRID_BC_ERROR); /* Set boundary conditions */
5335
5350
break; /* Done with this grid */
5336
5351
}
5337
5352
/* Here we need to do more work: Either extract subset or add/change padding, or both. */
5338
5353
/* Get start/stop row/cols for subset (or the entire domain) */
5339
5354
/* dx,dy are needed when the grid is pixel-registered as the w/e/s/n bounds are off by 0.5 {dx,dy} relative to node coordinates */
5340
5355
dx = G_obj->header->inc[GMT_X] * G_obj->header->xy_off; dy = G_obj->header->inc[GMT_Y] * G_obj->header->xy_off;
5341
- j1 = (unsigned int)gmt_M_grd_y_to_row (GMT, G_obj->header ->wesn[YLO]+dy, G_orig->header);
5342
- j0 = (unsigned int)gmt_M_grd_y_to_row (GMT, G_obj->header ->wesn[YHI]-dy, G_orig->header);
5343
- i0 = (unsigned int)gmt_M_grd_x_to_col (GMT, G_obj->header ->wesn[XLO]+dx, G_orig->header);
5344
- i1 = (unsigned int)gmt_M_grd_x_to_col (GMT, G_obj->header ->wesn[XHI]-dx, G_orig->header);
5356
+ j1 = (unsigned int)gmt_M_grd_y_to_row (GMT, S_obj ->wesn[YLO]+dy, G_orig->header);
5357
+ j0 = (unsigned int)gmt_M_grd_y_to_row (GMT, S_obj ->wesn[YHI]-dy, G_orig->header);
5358
+ i0 = (unsigned int)gmt_M_grd_x_to_col (GMT, S_obj ->wesn[XLO]+dx, G_orig->header);
5359
+ i1 = (unsigned int)gmt_M_grd_x_to_col (GMT, S_obj ->wesn[XHI]-dx, G_orig->header);
5345
5360
gmt_M_memcpy (G_obj->header->pad, GMT->current.io.pad, 4, int); /* Set desired padding */
5361
+ gmt_M_memcpy (G_obj->header->wesn, S_obj->wesn, 4U, double); /* Update the grid header region to match subset request */
5362
+ gmt_set_grddim (GMT, G_obj->header); /* Adjust all dimensions accordingly before accessing the grid for output */
5346
5363
/* get stats */
5347
5364
HH = gmt_get_H_hidden (G_obj->header);
5348
5365
G_obj->header->z_min = DBL_MAX;
5349
5366
G_obj->header->z_max = -DBL_MAX;
5350
5367
HH->has_NaNs = GMT_GRID_NO_NANS; /* We are about to check for NaNs and if none are found we retain 1, else 2 */
5351
- for (row = j0; row <= j1; row++) {
5368
+ for (row = j0, row_out = 0; row <= j1; row++, row_out++) {
5369
+ ij = gmt_M_ijp (G_obj->header, row_out, 0); /* Position in output grid at start of current row */
5352
5370
for (col = i0; col <= i1; col++, ij++) {
5353
- ij_orig = gmt_M_ijp ( G_orig->header, row, col); /* Position of this (row,col) in original grid organization */
5354
- ij = gmt_M_ijp (G_obj ->header, row, col ); /* Position of this (row,col) in output grid organization */
5371
+ kol = col % G_orig->header->n_columns;
5372
+ ij_orig = gmt_M_ijp (G_orig ->header, row, kol ); /* Position of this (row,col) in original grid organization */
5355
5373
G_obj->data[ij] = G_orig->data[ij_orig];
5356
5374
if (gmt_M_is_fnan (G_obj->data[ij]))
5357
5375
HH->has_NaNs = GMT_GRID_HAS_NANS;
@@ -5419,34 +5437,38 @@ GMT_LOCAL struct GMT_GRID * gmtapi_import_grid (struct GMTAPI_CTRL *API, int obj
5419
5437
GMT_2D_to_index = gmtapi_get_2d_to_index (API, M_obj->shape, GMT_GRID_IS_REAL);
5420
5438
if ((api_get_val = gmtapi_select_get_function (API, M_obj->type)) == NULL)
5421
5439
return_null (API, GMT_NOT_A_VALID_TYPE);
5422
- G_obj->header->z_min = +DBL_MAX;
5423
- G_obj->header->z_max = -DBL_MAX;
5424
5440
HH = gmt_get_H_hidden (G_obj->header);
5425
- HH->has_NaNs = GMT_GRID_NO_NANS; /* We are about to check for NaNs and if none are found we retain 1, else 2 */
5426
5441
5427
5442
if (! (mode & GMT_DATA_ONLY)) { /* Must first init header and copy the header information from the matrix header */
5428
5443
gmtapi_matrixinfo_to_grdheader (GMT, G_obj->header, M_obj); /* Populate a GRD header structure */
5429
- if (mode & GMT_CONTAINER_ONLY) { /* Just needed the header */
5430
- /* Must get the full zmin/max range since not provided by the matrix header */
5444
+ /* Must get the full zmin/max range since not provided by the matrix header */
5445
+ G_obj->header->z_min = +DBL_MAX;
5446
+ G_obj->header->z_max = -DBL_MAX;
5447
+ HH->has_NaNs = GMT_GRID_NO_NANS; /* We are about to check for NaNs and if none are found we retain 1, else 2 */
5431
5448
gmt_M_grd_loop (GMT, G_obj, row, col, ij) {
5432
- ij_orig = GMT_2D_to_index (row, col, M_obj->dim);
5433
- api_get_val (&(M_obj->data), ij_orig, &d);
5434
- if (gmt_M_is_dnan (d))
5435
- HH->has_NaNs = GMT_GRID_HAS_NANS;
5436
- else {
5437
- G_obj->header->z_min = MIN (G_obj->header->z_min, (gmt_grdfloat)d);
5438
- G_obj->header->z_max = MAX (G_obj->header->z_max, (gmt_grdfloat)d);
5439
- }
5449
+ ij_orig = GMT_2D_to_index (row, col, M_obj->dim);
5450
+ api_get_val (&(M_obj->data), ij_orig, &d);
5451
+ if (gmt_M_is_dnan (d))
5452
+ HH->has_NaNs = GMT_GRID_HAS_NANS;
5453
+ else {
5454
+ G_obj->header->z_min = MIN (G_obj->header->z_min, (gmt_grdfloat)d);
5455
+ G_obj->header->z_max = MAX (G_obj->header->z_max, (gmt_grdfloat)d);
5440
5456
}
5441
- break; /* Done for now */
5442
5457
}
5458
+ if (mode & GMT_CONTAINER_ONLY) /* Just needed the header */
5459
+ break; /* Done for now */
5443
5460
}
5444
5461
5445
5462
GMT_Report (API, GMT_MSG_INFORMATION, "Importing grid data from user matrix memory location\n");
5446
5463
5447
5464
/* Get start/stop row/cols for subset (or the entire domain) */
5448
5465
/* dx,dy are needed when the grid is pixel-registered as the w/e/s/n bounds are off by 0.5 {dx,dy} relative to node coordinates */
5449
- if (S_obj->region) { /* Want a subset */
5466
+ if (!S_obj->region || gmt_whole_earth (GMT, M_obj->range, S_obj->wesn)) { /* Easy, get the whole enchilada */
5467
+ j0 = i0 = 0;
5468
+ j1 = G_obj->header->n_rows - 1; /* Minus 1 since we loop up to and including below */
5469
+ i1 = G_obj->header->n_columns - 1;
5470
+ }
5471
+ else { /* Want a subset */
5450
5472
dx = G_obj->header->inc[GMT_X] * G_obj->header->xy_off; dy = G_obj->header->inc[GMT_Y] * G_obj->header->xy_off;
5451
5473
j1 = (unsigned int)gmt_M_grd_y_to_row (GMT, S_obj->wesn[YLO]+dy, G_obj->header);
5452
5474
j0 = (unsigned int)gmt_M_grd_y_to_row (GMT, S_obj->wesn[YHI]-dy, G_obj->header);
@@ -5455,23 +5477,18 @@ GMT_LOCAL struct GMT_GRID * gmtapi_import_grid (struct GMTAPI_CTRL *API, int obj
5455
5477
gmt_M_memcpy (G_obj->header->wesn, S_obj->wesn, 4U, double); /* Update the grid header region to match subset request */
5456
5478
gmt_set_grddim (GMT, G_obj->header); /* Adjust all dimensions accordingly before allocating space */
5457
5479
}
5458
- else { /* Easy, get the whole enchilada */
5459
- j0 = i0 = 0;
5460
- j1 = G_obj->header->n_rows - 1; /* Minus 1 since we loop up to and including below */
5461
- i1 = G_obj->header->n_columns - 1;
5462
- }
5463
5480
if (G_obj->data) { /* This is an error - there cannot be a data pointer yet */
5464
5481
GMT_Report (API, GMT_MSG_ERROR, "G->data is not NULL when memory allocation is about to happen\n");
5465
5482
return_null (API, GMT_PTR_IS_NULL);
5466
5483
}
5467
5484
else
5468
5485
G_obj->data = gmt_M_memory_aligned (GMT, NULL, G_obj->header->size, gmt_grdfloat);
5469
5486
5470
- for (row = j0; row <= j1; row++) {
5487
+ for (row = j0, row_out = 0; row <= j1; row++, row_out++) {
5488
+ ij = gmt_M_ijp (G_obj->header, row_out, 0); /* Position in output grid at start of current row */
5471
5489
for (col = i0; col <= i1; col++, ij++) {
5472
5490
kol = col % M_obj->n_columns;
5473
5491
ij_orig = GMT_2D_to_index (row, kol, M_obj->dim); /* Position of this (row,col) in input matrix organization */
5474
- ij = gmt_M_ijp (G_obj->header, row, kol); /* Position of this (row,col) in output grid organization */
5475
5492
api_get_val (&(M_obj->data), ij_orig, &d); /* Get the next item from the matrix */
5476
5493
G_obj->data[ij] = (gmt_grdfloat)d;
5477
5494
if (gmt_M_is_dnan (d))
@@ -5482,7 +5499,7 @@ GMT_LOCAL struct GMT_GRID * gmtapi_import_grid (struct GMTAPI_CTRL *API, int obj
5482
5499
}
5483
5500
}
5484
5501
}
5485
- if (gmt_M_is_geographic (GMT, GMT_IN) && gmt_M_360_range ( M_obj->range[XLO], M_obj->range[XHI]) && gmt_M_360_range (G_obj->header-> wesn[XLO], G_obj->header->wesn[XHI] )) {
5502
+ if (gmt_whole_earth (GMT, M_obj->range, S_obj-> wesn)) {
5486
5503
/* Global grids passed via matrix are not rotated to fit the desired global region, so we need to correct the wesn for this grid to match the matrix */
5487
5504
gmt_M_memcpy (G_obj->header->wesn, M_obj->range, 4U, double);
5488
5505
}
@@ -5491,13 +5508,25 @@ GMT_LOCAL struct GMT_GRID * gmtapi_import_grid (struct GMTAPI_CTRL *API, int obj
5491
5508
return_null (API, GMT_GRID_BC_ERROR); /* Set boundary conditions */
5492
5509
API->object[new_item]->status = GMT_IS_USED; /* Mark as read */
5493
5510
API->object[new_item]->actual_family = GMT_IS_GRID; /* Done reading from matrix */
5511
+ if (start_over_method) API->object[new_item]->method = start_over_method; /* We changed our mind from reference to duplicate due to region */
5494
5512
GH->alloc_level = API->object[new_item]->alloc_level; /* Since allocated here */
5495
5513
break;
5496
5514
5497
5515
case GMT_IS_REFERENCE|GMT_VIA_MATRIX: /* The user's 2-D grid array of some sort, + info in the args [NOT YET FULLY TESTED] */
5498
5516
/* Getting a matrix info S_obj->resource. Create grid header and then pass the grid pointer via the matrix pointer */
5499
5517
if ((M_obj = S_obj->resource) == NULL) return_null (API, GMT_PTR_IS_NULL);
5500
- //if (S_obj->region) return_null (API, GMT_SUBSET_NOT_ALLOWED);
5518
+ /* Determine if it is possible to use the matrix given the region selected and the fact we chose GMT_IS_REFERENCE. This test will
5519
+ * only kick in after we allocate the G_obj and come back the second time (after getting header) since otherwise S_obj->wesn is not set yet */
5520
+ if (!(!S_obj->region ||
5521
+ (S_obj->wesn[XLO] >= M_obj->range[XLO] && S_obj->wesn[XHI] <= M_obj->range[XHI] && S_obj->wesn[YLO] >= M_obj->range[YLO] && S_obj->wesn[YHI] <= M_obj->range[YHI]) ||
5522
+ gmt_whole_earth (GMT, M_obj->range, S_obj->wesn))) { /* Cannot do this by reference, switch to duplication */
5523
+ method -= GMT_IS_REFERENCE;
5524
+ method += GMT_IS_DUPLICATE;
5525
+ start_over_method = GMT_IS_DUPLICATE;
5526
+ GMT_Report (API, GMT_MSG_DEBUG, "Subset selection requires GMT_IS_DUPLICATION instead of GMT_IS_REFERENCE - method has been switched\n");
5527
+ goto start_over_import_grid;
5528
+ }
5529
+
5501
5530
/* This method requires the input data to be a GMT_GRD_FORMAT matrix - otherwise we should be DUPLICATING */
5502
5531
MH = gmt_get_M_hidden (M_obj);
5503
5532
if (!(M_obj->shape == GMT_IS_ROW_FORMAT && M_obj->type == GMT_GRDFLOAT && (mode & GMT_GRID_IS_COMPLEX_MASK) == 0))
@@ -5514,27 +5543,26 @@ GMT_LOCAL struct GMT_GRID * gmtapi_import_grid (struct GMTAPI_CTRL *API, int obj
5514
5543
done = (mode & GMT_CONTAINER_ONLY) ? false : true; /* Not done until we read grid */
5515
5544
if (! (mode & GMT_DATA_ONLY)) {
5516
5545
gmtapi_matrixinfo_to_grdheader (GMT, G_obj->header, M_obj); /* Populate a GRD header structure */
5517
- if (mode & GMT_CONTAINER_ONLY) { /* Just needed the header but need to set zmin/zmax first */
5518
- /* Temporarily set data pointer for convenience; removed later */
5546
+ /* Temporarily set data pointer for convenience; removed later */
5519
5547
#ifdef DOUBLE_PRECISION_GRID
5520
- G_obj->data = M_obj->data.f8;
5548
+ G_obj->data = M_obj->data.f8;
5521
5549
#else
5522
- G_obj->data = M_obj->data.f4;
5550
+ G_obj->data = M_obj->data.f4;
5523
5551
#endif
5524
- G_obj->header->z_min = +DBL_MAX;
5525
- G_obj->header->z_max = -DBL_MAX;
5526
- HH->has_NaNs = GMT_GRID_NO_NANS; /* We are about to check for NaNs and if none are found we retain 1, else 2 */
5527
- gmt_M_grd_loop (GMT, G_obj, row, col, ij) {
5528
- if (gmt_M_is_fnan (G_obj->data[ij]))
5529
- HH->has_NaNs = GMT_GRID_HAS_NANS;
5530
- else {
5531
- G_obj->header->z_min = MIN (G_obj->header->z_min, G_obj->data[ij]);
5532
- G_obj->header->z_max = MAX (G_obj->header->z_max, G_obj->data[ij]);
5533
- }
5552
+ G_obj->header->z_min = +DBL_MAX;
5553
+ G_obj->header->z_max = -DBL_MAX;
5554
+ HH->has_NaNs = GMT_GRID_NO_NANS; /* We are about to check for NaNs and if none are found we retain 1, else 2 */
5555
+ gmt_M_grd_loop (GMT, G_obj, row, col, ij) {
5556
+ if (gmt_M_is_fnan (G_obj->data[ij]))
5557
+ HH->has_NaNs = GMT_GRID_HAS_NANS;
5558
+ else {
5559
+ G_obj->header->z_min = MIN (G_obj->header->z_min, G_obj->data[ij]);
5560
+ G_obj->header->z_max = MAX (G_obj->header->z_max, G_obj->data[ij]);
5534
5561
}
5535
- G_obj->data = NULL; /* Since data are not requested yet */
5536
- break;
5537
5562
}
5563
+ G_obj->data = NULL; /* Since data are not requested yet */
5564
+ if (mode & GMT_CONTAINER_ONLY) /* Just needed the header but had to set zmin/zmax first */
5565
+ break;
5538
5566
}
5539
5567
if ((new_ID = gmtapi_get_object (API, GMT_IS_GRID, G_obj)) == GMT_NOTSET)
5540
5568
return_null (API, GMT_OBJECT_NOT_FOUND);
@@ -5548,11 +5576,15 @@ GMT_LOCAL struct GMT_GRID * gmtapi_import_grid (struct GMTAPI_CTRL *API, int obj
5548
5576
#endif
5549
5577
GH = gmt_get_G_hidden (G_obj);
5550
5578
S_obj->alloc_mode = MH->alloc_mode; /* Pass on alloc_mode of matrix */
5551
- GH->alloc_mode = MH->alloc_mode;
5579
+ GH->alloc_mode = GMT_ALLOC_EXTERNALLY; /* Since we cannot have both M and G try to free */
5552
5580
API->object[new_item]->resource = G_obj;
5553
5581
API->object[new_item]->status = GMT_IS_USED; /* Mark as read */
5554
5582
GH->alloc_level = API->object[new_item]->alloc_level; /* Since allocated here */
5555
- if (S_obj->region) { /* Possibly adjust the pad so inner region matches wesn */
5583
+ if (gmt_whole_earth (GMT, M_obj->range, S_obj->wesn)) {
5584
+ /* Global grids passed via matrix are not rotated to fit the desired global region, so we need to correct the wesn for this grid to match the matrix */
5585
+ gmt_M_memcpy (G_obj->header->wesn, M_obj->range, 4U, double);
5586
+ }
5587
+ else if (S_obj->region) { /* Possibly adjust the pad so inner region matches wesn */
5556
5588
if (S_obj->reset_pad) { /* First undo a prior sub-region used with this memory grid */
5557
5589
gmtlib_contract_headerpad (GMT, G_obj->header, S_obj->orig_pad, S_obj->orig_wesn);
5558
5590
S_obj->reset_pad = 0;
0 commit comments