PostGIS  2.1.10dev-r@@SVN_REVISION@@
Datum RASTER_setPixelValuesArray ( PG_FUNCTION_ARGS  )

Definition at line 3315 of file rt_pg.c.

References ovdump::band, ES_NONE, FALSE, FLT_EQ, pixval::nband, POSTGIS_RT_DEBUGF, rtrowdump::raster, rt_band_get_hasnodata_flag(), rt_band_get_min_value(), rt_band_get_nodata(), rt_band_get_pixel(), rt_band_set_pixel(), rt_raster_deserialize(), rt_raster_destroy(), rt_raster_get_band(), rt_raster_get_height(), rt_raster_get_num_bands(), rt_raster_get_width(), rt_raster_serialize(), rt_raster_serialized_t::size, TRUE, genraster::value, pixval::x, and pixval::y.

3316 {
3317  rt_pgraster *pgraster = NULL;
3318  rt_pgraster *pgrtn = NULL;
3319  rt_raster raster = NULL;
3320  rt_band band = NULL;
3321  int numbands = 0;
3322 
3323  int nband = 0;
3324  int width = 0;
3325  int height = 0;
3326 
3327  ArrayType *array;
3328  Oid etype;
3329  Datum *elements;
3330  bool *nulls;
3331  int16 typlen;
3332  bool typbyval;
3333  char typalign;
3334  int ndims = 1;
3335  int *dims;
3336  int num = 0;
3337 
3338  int ul[2] = {0};
3339  struct pixelvalue {
3340  int x;
3341  int y;
3342 
3343  bool noset;
3344  bool nodata;
3345  double value;
3346  };
3347  struct pixelvalue *pixval = NULL;
3348  int numpixval = 0;
3349  int dimpixval[2] = {1, 1};
3350  int dimnoset[2] = {1, 1};
3351  int hasnodata = FALSE;
3352  double nodataval = 0;
3353  bool keepnodata = FALSE;
3354  bool hasnosetval = FALSE;
3355  bool nosetvalisnull = FALSE;
3356  double nosetval = 0;
3357 
3358  int rtn = 0;
3359  double val = 0;
3360  int isnodata = 0;
3361 
3362  int i = 0;
3363  int j = 0;
3364  int x = 0;
3365  int y = 0;
3366 
3367  /* pgraster is null, return null */
3368  if (PG_ARGISNULL(0))
3369  PG_RETURN_NULL();
3370  pgraster = (rt_pgraster *) PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(0));
3371 
3372  /* raster */
3373  raster = rt_raster_deserialize(pgraster, FALSE);
3374  if (!raster) {
3375  PG_FREE_IF_COPY(pgraster, 0);
3376  elog(ERROR, "RASTER_setPixelValuesArray: Could not deserialize raster");
3377  PG_RETURN_NULL();
3378  }
3379 
3380  /* raster attributes */
3381  numbands = rt_raster_get_num_bands(raster);
3382  width = rt_raster_get_width(raster);
3383  height = rt_raster_get_height(raster);
3384 
3385  /* nband */
3386  if (PG_ARGISNULL(1)) {
3387  elog(NOTICE, "Band index cannot be NULL. Value must be 1-based. Returning original raster");
3388  rt_raster_destroy(raster);
3389  PG_RETURN_POINTER(pgraster);
3390  }
3391 
3392  nband = PG_GETARG_INT32(1);
3393  if (nband < 1 || nband > numbands) {
3394  elog(NOTICE, "Band index is invalid. Value must be 1-based. Returning original raster");
3395  rt_raster_destroy(raster);
3396  PG_RETURN_POINTER(pgraster);
3397  }
3398 
3399  /* x, y */
3400  for (i = 2, j = 0; i < 4; i++, j++) {
3401  if (PG_ARGISNULL(i)) {
3402  elog(NOTICE, "%s cannot be NULL. Value must be 1-based. Returning original raster", j < 1 ? "X" : "Y");
3403  rt_raster_destroy(raster);
3404  PG_RETURN_POINTER(pgraster);
3405  }
3406 
3407  ul[j] = PG_GETARG_INT32(i);
3408  if (
3409  (ul[j] < 1) || (
3410  (j < 1 && ul[j] > width) ||
3411  (j > 0 && ul[j] > height)
3412  )
3413  ) {
3414  elog(NOTICE, "%s is invalid. Value must be 1-based. Returning original raster", j < 1 ? "X" : "Y");
3415  rt_raster_destroy(raster);
3416  PG_RETURN_POINTER(pgraster);
3417  }
3418 
3419  /* force 0-based from 1-based */
3420  ul[j] -= 1;
3421  }
3422 
3423  /* new value set */
3424  if (PG_ARGISNULL(4)) {
3425  elog(NOTICE, "No values to set. Returning original raster");
3426  rt_raster_destroy(raster);
3427  PG_RETURN_POINTER(pgraster);
3428  }
3429 
3430  array = PG_GETARG_ARRAYTYPE_P(4);
3431  etype = ARR_ELEMTYPE(array);
3432  get_typlenbyvalalign(etype, &typlen, &typbyval, &typalign);
3433 
3434  switch (etype) {
3435  case FLOAT4OID:
3436  case FLOAT8OID:
3437  break;
3438  default:
3439  rt_raster_destroy(raster);
3440  PG_FREE_IF_COPY(pgraster, 0);
3441  elog(ERROR, "RASTER_setPixelValuesArray: Invalid data type for new values");
3442  PG_RETURN_NULL();
3443  break;
3444  }
3445 
3446  ndims = ARR_NDIM(array);
3447  dims = ARR_DIMS(array);
3448  POSTGIS_RT_DEBUGF(4, "ndims = %d", ndims);
3449 
3450  if (ndims < 1 || ndims > 2) {
3451  elog(NOTICE, "New values array must be of 1 or 2 dimensions. Returning original raster");
3452  rt_raster_destroy(raster);
3453  PG_RETURN_POINTER(pgraster);
3454  }
3455  /* outer element, then inner element */
3456  /* i = 0, y */
3457  /* i = 1, x */
3458  if (ndims != 2)
3459  dimpixval[1] = dims[0];
3460  else {
3461  dimpixval[0] = dims[0];
3462  dimpixval[1] = dims[1];
3463  }
3464  POSTGIS_RT_DEBUGF(4, "dimpixval = (%d, %d)", dimpixval[0], dimpixval[1]);
3465 
3466  deconstruct_array(
3467  array,
3468  etype,
3469  typlen, typbyval, typalign,
3470  &elements, &nulls, &num
3471  );
3472 
3473  /* # of elements doesn't match dims */
3474  if (num < 1 || num != (dimpixval[0] * dimpixval[1])) {
3475  if (num) {
3476  pfree(elements);
3477  pfree(nulls);
3478  }
3479  rt_raster_destroy(raster);
3480  PG_FREE_IF_COPY(pgraster, 0);
3481  elog(ERROR, "RASTER_setPixelValuesArray: Could not deconstruct new values array");
3482  PG_RETURN_NULL();
3483  }
3484 
3485  /* allocate memory for pixval */
3486  numpixval = num;
3487  pixval = palloc(sizeof(struct pixelvalue) * numpixval);
3488  if (pixval == NULL) {
3489  pfree(elements);
3490  pfree(nulls);
3491  rt_raster_destroy(raster);
3492  PG_FREE_IF_COPY(pgraster, 0);
3493  elog(ERROR, "RASTER_setPixelValuesArray: Could not allocate memory for new pixel values");
3494  PG_RETURN_NULL();
3495  }
3496 
3497  /* load new values into pixval */
3498  i = 0;
3499  for (y = 0; y < dimpixval[0]; y++) {
3500  for (x = 0; x < dimpixval[1]; x++) {
3501  /* 0-based */
3502  pixval[i].x = ul[0] + x;
3503  pixval[i].y = ul[1] + y;
3504 
3505  pixval[i].noset = FALSE;
3506  pixval[i].nodata = FALSE;
3507  pixval[i].value = 0;
3508 
3509  if (nulls[i])
3510  pixval[i].nodata = TRUE;
3511  else {
3512  switch (etype) {
3513  case FLOAT4OID:
3514  pixval[i].value = DatumGetFloat4(elements[i]);
3515  break;
3516  case FLOAT8OID:
3517  pixval[i].value = DatumGetFloat8(elements[i]);
3518  break;
3519  }
3520  }
3521 
3522  i++;
3523  }
3524  }
3525 
3526  pfree(elements);
3527  pfree(nulls);
3528 
3529  /* now load noset flags */
3530  if (!PG_ARGISNULL(5)) {
3531  array = PG_GETARG_ARRAYTYPE_P(5);
3532  etype = ARR_ELEMTYPE(array);
3533  get_typlenbyvalalign(etype, &typlen, &typbyval, &typalign);
3534 
3535  switch (etype) {
3536  case BOOLOID:
3537  break;
3538  default:
3539  pfree(pixval);
3540  rt_raster_destroy(raster);
3541  PG_FREE_IF_COPY(pgraster, 0);
3542  elog(ERROR, "RASTER_setPixelValuesArray: Invalid data type for noset flags");
3543  PG_RETURN_NULL();
3544  break;
3545  }
3546 
3547  ndims = ARR_NDIM(array);
3548  dims = ARR_DIMS(array);
3549  POSTGIS_RT_DEBUGF(4, "ndims = %d", ndims);
3550 
3551  if (ndims < 1 || ndims > 2) {
3552  elog(NOTICE, "Noset flags array must be of 1 or 2 dimensions. Returning original raster");
3553  pfree(pixval);
3554  rt_raster_destroy(raster);
3555  PG_RETURN_POINTER(pgraster);
3556  }
3557  /* outer element, then inner element */
3558  /* i = 0, y */
3559  /* i = 1, x */
3560  if (ndims != 2)
3561  dimnoset[1] = dims[0];
3562  else {
3563  dimnoset[0] = dims[0];
3564  dimnoset[1] = dims[1];
3565  }
3566  POSTGIS_RT_DEBUGF(4, "dimnoset = (%d, %d)", dimnoset[0], dimnoset[1]);
3567 
3568  deconstruct_array(
3569  array,
3570  etype,
3571  typlen, typbyval, typalign,
3572  &elements, &nulls, &num
3573  );
3574 
3575  /* # of elements doesn't match dims */
3576  if (num < 1 || num != (dimnoset[0] * dimnoset[1])) {
3577  pfree(pixval);
3578  if (num) {
3579  pfree(elements);
3580  pfree(nulls);
3581  }
3582  rt_raster_destroy(raster);
3583  PG_FREE_IF_COPY(pgraster, 0);
3584  elog(ERROR, "RASTER_setPixelValuesArray: Could not deconstruct noset flags array");
3585  PG_RETURN_NULL();
3586  }
3587 
3588  i = 0;
3589  j = 0;
3590  for (y = 0; y < dimnoset[0]; y++) {
3591  if (y >= dimpixval[0]) break;
3592 
3593  for (x = 0; x < dimnoset[1]; x++) {
3594  /* fast forward noset elements */
3595  if (x >= dimpixval[1]) {
3596  i += (dimnoset[1] - dimpixval[1]);
3597  break;
3598  }
3599 
3600  if (!nulls[i] && DatumGetBool(elements[i]))
3601  pixval[j].noset = TRUE;
3602 
3603  i++;
3604  j++;
3605  }
3606 
3607  /* fast forward pixval */
3608  if (x < dimpixval[1])
3609  j += (dimpixval[1] - dimnoset[1]);
3610  }
3611 
3612  pfree(elements);
3613  pfree(nulls);
3614  }
3615  /* hasnosetvalue and nosetvalue */
3616  else if (!PG_ARGISNULL(6) && PG_GETARG_BOOL(6)) {
3617  hasnosetval = TRUE;
3618  if (PG_ARGISNULL(7))
3619  nosetvalisnull = TRUE;
3620  else
3621  nosetval = PG_GETARG_FLOAT8(7);
3622  }
3623 
3624 #if POSTGIS_DEBUG_LEVEL > 0
3625  for (i = 0; i < numpixval; i++) {
3626  POSTGIS_RT_DEBUGF(4, "pixval[%d](x, y, noset, nodata, value) = (%d, %d, %d, %d, %f)",
3627  i,
3628  pixval[i].x,
3629  pixval[i].y,
3630  pixval[i].noset,
3631  pixval[i].nodata,
3632  pixval[i].value
3633  );
3634  }
3635 #endif
3636 
3637  /* keepnodata flag */
3638  if (!PG_ARGISNULL(8))
3639  keepnodata = PG_GETARG_BOOL(8);
3640 
3641  /* get band */
3642  band = rt_raster_get_band(raster, nband - 1);
3643  if (!band) {
3644  elog(NOTICE, "Could not find band at index %d. Returning original raster", nband);
3645  pfree(pixval);
3646  rt_raster_destroy(raster);
3647  PG_RETURN_POINTER(pgraster);
3648  }
3649 
3650  /* get band nodata info */
3651  /* has NODATA, use NODATA */
3652  hasnodata = rt_band_get_hasnodata_flag(band);
3653  if (hasnodata)
3654  rt_band_get_nodata(band, &nodataval);
3655  /* no NODATA, use min possible value */
3656  else
3657  nodataval = rt_band_get_min_value(band);
3658 
3659  /* set pixels */
3660  for (i = 0; i < numpixval; i++) {
3661  /* noset = true, skip */
3662  if (pixval[i].noset)
3663  continue;
3664  /* check against nosetval */
3665  else if (hasnosetval) {
3666  /* pixel = NULL AND nosetval = NULL */
3667  if (pixval[i].nodata && nosetvalisnull)
3668  continue;
3669  /* pixel value = nosetval */
3670  else if (!pixval[i].nodata && !nosetvalisnull && FLT_EQ(pixval[i].value, nosetval))
3671  continue;
3672  }
3673 
3674  /* if pixel is outside bounds, skip */
3675  if (
3676  (pixval[i].x < 0 || pixval[i].x >= width) ||
3677  (pixval[i].y < 0 || pixval[i].y >= height)
3678  ) {
3679  elog(NOTICE, "Cannot set value for pixel (%d, %d) outside raster bounds: %d x %d",
3680  pixval[i].x + 1, pixval[i].y + 1,
3681  width, height
3682  );
3683  continue;
3684  }
3685 
3686  /* if hasnodata = TRUE and keepnodata = TRUE, inspect pixel value */
3687  if (hasnodata && keepnodata) {
3688  rtn = rt_band_get_pixel(band, pixval[i].x, pixval[i].y, &val, &isnodata);
3689  if (rtn != ES_NONE) {
3690  pfree(pixval);
3691  rt_raster_destroy(raster);
3692  PG_FREE_IF_COPY(pgraster, 0);
3693  elog(ERROR, "Cannot get value of pixel");
3694  PG_RETURN_NULL();
3695  }
3696 
3697  /* pixel value = NODATA, skip */
3698  if (isnodata) {
3699  continue;
3700  }
3701  }
3702 
3703  if (pixval[i].nodata)
3704  rt_band_set_pixel(band, pixval[i].x, pixval[i].y, nodataval, NULL);
3705  else
3706  rt_band_set_pixel(band, pixval[i].x, pixval[i].y, pixval[i].value, NULL);
3707  }
3708 
3709  pfree(pixval);
3710 
3711  /* serialize new raster */
3712  pgrtn = rt_raster_serialize(raster);
3713  rt_raster_destroy(raster);
3714  PG_FREE_IF_COPY(pgraster, 0);
3715  if (!pgrtn)
3716  PG_RETURN_NULL();
3717 
3718  SET_VARSIZE(pgrtn, pgrtn->size);
3719  PG_RETURN_POINTER(pgrtn);
3720 }
int rt_raster_get_num_bands(rt_raster raster)
Definition: rt_api.c:5677
void * rt_raster_serialize(rt_raster raster)
Return this raster in serialized form.
Definition: rt_api.c:8158
void rt_raster_destroy(rt_raster raster)
Release memory associated to a raster.
Definition: rt_api.c:5387
tuple band
Definition: ovdump.py:57
tuple raster
Be careful!! Zeros function's input parameter can be a (height x width) array, not (width x height): ...
Definition: rtrowdump.py:123
Definition: pixval.py:1
tuple nband
Definition: pixval.py:52
double rt_band_get_min_value(rt_band band)
Returns the minimal possible value for the band according to the pixel type.
Definition: rt_api.c:3073
rt_errorstate rt_band_get_nodata(rt_band band, double *nodata)
Get NODATA value.
Definition: rt_api.c:3058
rt_errorstate rt_band_get_pixel(rt_band band, int x, int y, double *value, int *nodata)
Get pixel value.
Definition: rt_api.c:2549
#define FLT_EQ(x, y)
Definition: rt_api.h:2159
tuple x
Definition: pixval.py:53
uint16_t rt_raster_get_height(rt_raster raster)
Definition: rt_api.c:5434
rt_band rt_raster_get_band(rt_raster raster, int n)
Return Nth band, or NULL if unavailable.
Definition: rt_api.c:5686
#define FALSE
Definition: dbfopen.c:169
Struct definitions.
Definition: rt_api.h:2175
#define POSTGIS_RT_DEBUGF(level, msg,...)
Definition: rt_pg.h:62
rt_raster rt_raster_deserialize(void *serialized, int header_only)
Return a raster from a serialized form.
Definition: rt_api.c:8350
#define TRUE
Definition: dbfopen.c:170
int rt_band_get_hasnodata_flag(rt_band band)
Get hasnodata flag value.
Definition: rt_api.c:2002
tuple y
Definition: pixval.py:54
uint16_t rt_raster_get_width(rt_raster raster)
Definition: rt_api.c:5426
rt_errorstate rt_band_set_pixel(rt_band band, int x, int y, double val, int *converted)
Set single pixel's value.
Definition: rt_api.c:2302

Here is the call graph for this function: