PostGIS  2.3.8dev-r@@SVN_REVISION@@

◆ RASTER_dumpValues()

Datum RASTER_dumpValues ( PG_FUNCTION_ARGS  )

Definition at line 201 of file rtpg_pixel.c.

References ovdump::band, rtpg_dumpvalues_arg_t::columns, ES_NONE, FALSE, pixval::nband, rtpg_dumpvalues_arg_t::nbands, rtpg_dumpvalues_arg_t::nodata, rtpg_dumpvalues_arg_t::numbands, PG_FUNCTION_INFO_V1(), POSTGIS_RT_DEBUG, POSTGIS_RT_DEBUGF, rtrowdump::raster, RASTER_setPixelValue(), rtpg_dumpvalues_arg_t::rows, rt_band_clamped_value_is_nodata(), rt_band_get_isnodata_flag(), rt_band_get_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_has_band(), rt_raster_is_empty(), rtpg_dumpvalues_arg_destroy(), rtpg_dumpvalues_arg_init(), TRUE, rtpg_dumpvalues_arg_t::values, pixval::x, and pixval::y.

Referenced by rtpg_dumpvalues_arg_destroy().

202 {
203  FuncCallContext *funcctx;
204  TupleDesc tupdesc;
205  int call_cntr;
206  int max_calls;
207  int i = 0;
208  int x = 0;
209  int y = 0;
210  int z = 0;
211 
212  int16 typlen;
213  bool typbyval;
214  char typalign;
215 
216  rtpg_dumpvalues_arg arg1 = NULL;
217  rtpg_dumpvalues_arg arg2 = NULL;
218 
219  /* stuff done only on the first call of the function */
220  if (SRF_IS_FIRSTCALL()) {
221  MemoryContext oldcontext;
222  rt_pgraster *pgraster = NULL;
223  rt_raster raster = NULL;
224  rt_band band = NULL;
225  int numbands = 0;
226  int j = 0;
227  bool exclude_nodata_value = TRUE;
228 
229  ArrayType *array;
230  Oid etype;
231  Datum *e;
232  bool *nulls;
233 
234  double val = 0;
235  int isnodata = 0;
236 
237  POSTGIS_RT_DEBUG(2, "RASTER_dumpValues first call");
238 
239  /* create a function context for cross-call persistence */
240  funcctx = SRF_FIRSTCALL_INIT();
241 
242  /* switch to memory context appropriate for multiple function calls */
243  oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
244 
245  /* Get input arguments */
246  if (PG_ARGISNULL(0)) {
247  MemoryContextSwitchTo(oldcontext);
248  SRF_RETURN_DONE(funcctx);
249  }
250  pgraster = (rt_pgraster *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
251 
252  raster = rt_raster_deserialize(pgraster, FALSE);
253  if (!raster) {
254  PG_FREE_IF_COPY(pgraster, 0);
255  ereport(ERROR, (
256  errcode(ERRCODE_OUT_OF_MEMORY),
257  errmsg("Could not deserialize raster")
258  ));
259  MemoryContextSwitchTo(oldcontext);
260  SRF_RETURN_DONE(funcctx);
261  }
262 
263  /* check that raster is not empty */
264  /*
265  if (rt_raster_is_empty(raster)) {
266  elog(NOTICE, "Raster provided is empty");
267  rt_raster_destroy(raster);
268  PG_FREE_IF_COPY(pgraster, 0);
269  MemoryContextSwitchTo(oldcontext);
270  SRF_RETURN_DONE(funcctx);
271  }
272  */
273 
274  /* raster has bands */
275  numbands = rt_raster_get_num_bands(raster);
276  if (!numbands) {
277  elog(NOTICE, "Raster provided has no bands");
278  rt_raster_destroy(raster);
279  PG_FREE_IF_COPY(pgraster, 0);
280  MemoryContextSwitchTo(oldcontext);
281  SRF_RETURN_DONE(funcctx);
282  }
283 
284  /* initialize arg1 */
285  arg1 = rtpg_dumpvalues_arg_init();
286  if (arg1 == NULL) {
287  rt_raster_destroy(raster);
288  PG_FREE_IF_COPY(pgraster, 0);
289  MemoryContextSwitchTo(oldcontext);
290  elog(ERROR, "RASTER_dumpValues: Could not initialize argument structure");
291  SRF_RETURN_DONE(funcctx);
292  }
293 
294  /* nband, array */
295  if (!PG_ARGISNULL(1)) {
296  array = PG_GETARG_ARRAYTYPE_P(1);
297  etype = ARR_ELEMTYPE(array);
298  get_typlenbyvalalign(etype, &typlen, &typbyval, &typalign);
299 
300  switch (etype) {
301  case INT2OID:
302  case INT4OID:
303  break;
304  default:
306  rt_raster_destroy(raster);
307  PG_FREE_IF_COPY(pgraster, 0);
308  MemoryContextSwitchTo(oldcontext);
309  elog(ERROR, "RASTER_dumpValues: Invalid data type for band indexes");
310  SRF_RETURN_DONE(funcctx);
311  break;
312  }
313 
314  deconstruct_array(array, etype, typlen, typbyval, typalign, &e, &nulls, &(arg1->numbands));
315 
316  arg1->nbands = palloc(sizeof(int) * arg1->numbands);
317  if (arg1->nbands == NULL) {
319  rt_raster_destroy(raster);
320  PG_FREE_IF_COPY(pgraster, 0);
321  MemoryContextSwitchTo(oldcontext);
322  elog(ERROR, "RASTER_dumpValues: Could not allocate memory for band indexes");
323  SRF_RETURN_DONE(funcctx);
324  }
325 
326  for (i = 0, j = 0; i < arg1->numbands; i++) {
327  if (nulls[i]) continue;
328 
329  switch (etype) {
330  case INT2OID:
331  arg1->nbands[j] = DatumGetInt16(e[i]) - 1;
332  break;
333  case INT4OID:
334  arg1->nbands[j] = DatumGetInt32(e[i]) - 1;
335  break;
336  }
337 
338  j++;
339  }
340 
341  if (j < arg1->numbands) {
342  arg1->nbands = repalloc(arg1->nbands, sizeof(int) * j);
343  if (arg1->nbands == NULL) {
345  rt_raster_destroy(raster);
346  PG_FREE_IF_COPY(pgraster, 0);
347  MemoryContextSwitchTo(oldcontext);
348  elog(ERROR, "RASTER_dumpValues: Could not reallocate memory for band indexes");
349  SRF_RETURN_DONE(funcctx);
350  }
351 
352  arg1->numbands = j;
353  }
354 
355  /* validate nbands */
356  for (i = 0; i < arg1->numbands; i++) {
357  if (!rt_raster_has_band(raster, arg1->nbands[i])) {
358  elog(NOTICE, "Band at index %d not found in raster", arg1->nbands[i] + 1);
360  rt_raster_destroy(raster);
361  PG_FREE_IF_COPY(pgraster, 0);
362  MemoryContextSwitchTo(oldcontext);
363  SRF_RETURN_DONE(funcctx);
364  }
365  }
366 
367  }
368  /* no bands specified, return all bands */
369  else {
370  arg1->numbands = numbands;
371  arg1->nbands = palloc(sizeof(int) * arg1->numbands);
372 
373  if (arg1->nbands == NULL) {
375  rt_raster_destroy(raster);
376  PG_FREE_IF_COPY(pgraster, 0);
377  MemoryContextSwitchTo(oldcontext);
378  elog(ERROR, "RASTER_dumpValues: Could not allocate memory for band indexes");
379  SRF_RETURN_DONE(funcctx);
380  }
381 
382  for (i = 0; i < arg1->numbands; i++) {
383  arg1->nbands[i] = i;
384  POSTGIS_RT_DEBUGF(4, "arg1->nbands[%d] = %d", arg1->nbands[i], i);
385  }
386  }
387 
388  arg1->rows = rt_raster_get_height(raster);
389  arg1->columns = rt_raster_get_width(raster);
390 
391  /* exclude_nodata_value */
392  if (!PG_ARGISNULL(2))
393  exclude_nodata_value = PG_GETARG_BOOL(2);
394  POSTGIS_RT_DEBUGF(4, "exclude_nodata_value = %d", exclude_nodata_value);
395 
396  /* allocate memory for each band's values and nodata flags */
397  arg1->values = palloc(sizeof(Datum *) * arg1->numbands);
398  arg1->nodata = palloc(sizeof(bool *) * arg1->numbands);
399  if (arg1->values == NULL || arg1->nodata == NULL) {
401  rt_raster_destroy(raster);
402  PG_FREE_IF_COPY(pgraster, 0);
403  MemoryContextSwitchTo(oldcontext);
404  elog(ERROR, "RASTER_dumpValues: Could not allocate memory for pixel values");
405  SRF_RETURN_DONE(funcctx);
406  }
407  memset(arg1->values, 0, sizeof(Datum *) * arg1->numbands);
408  memset(arg1->nodata, 0, sizeof(bool *) * arg1->numbands);
409 
410  /* get each band and dump data */
411  for (z = 0; z < arg1->numbands; z++) {
412  /* shortcut if raster is empty */
413  if (rt_raster_is_empty(raster))
414  break;
415 
416  band = rt_raster_get_band(raster, arg1->nbands[z]);
417  if (!band) {
418  int nband = arg1->nbands[z] + 1;
420  rt_raster_destroy(raster);
421  PG_FREE_IF_COPY(pgraster, 0);
422  MemoryContextSwitchTo(oldcontext);
423  elog(ERROR, "RASTER_dumpValues: Could not get band at index %d", nband);
424  SRF_RETURN_DONE(funcctx);
425  }
426 
427  /* allocate memory for values and nodata flags */
428  arg1->values[z] = palloc(sizeof(Datum) * arg1->rows * arg1->columns);
429  arg1->nodata[z] = palloc(sizeof(bool) * arg1->rows * arg1->columns);
430  if (arg1->values[z] == NULL || arg1->nodata[z] == NULL) {
432  rt_raster_destroy(raster);
433  PG_FREE_IF_COPY(pgraster, 0);
434  MemoryContextSwitchTo(oldcontext);
435  elog(ERROR, "RASTER_dumpValues: Could not allocate memory for pixel values");
436  SRF_RETURN_DONE(funcctx);
437  }
438  memset(arg1->values[z], 0, sizeof(Datum) * arg1->rows * arg1->columns);
439  memset(arg1->nodata[z], 0, sizeof(bool) * arg1->rows * arg1->columns);
440 
441  i = 0;
442 
443  /* shortcut if band is NODATA */
444  if (rt_band_get_isnodata_flag(band)) {
445  for (i = (arg1->rows * arg1->columns) - 1; i >= 0; i--)
446  arg1->nodata[z][i] = TRUE;
447  continue;
448  }
449 
450  for (y = 0; y < arg1->rows; y++) {
451  for (x = 0; x < arg1->columns; x++) {
452  /* get pixel */
453  if (rt_band_get_pixel(band, x, y, &val, &isnodata) != ES_NONE) {
454  int nband = arg1->nbands[z] + 1;
456  rt_raster_destroy(raster);
457  PG_FREE_IF_COPY(pgraster, 0);
458  MemoryContextSwitchTo(oldcontext);
459  elog(ERROR, "RASTER_dumpValues: Could not pixel (%d, %d) of band %d", x, y, nband);
460  SRF_RETURN_DONE(funcctx);
461  }
462 
463  arg1->values[z][i] = Float8GetDatum(val);
464  POSTGIS_RT_DEBUGF(5, "arg1->values[z][i] = %f", DatumGetFloat8(arg1->values[z][i]));
465  POSTGIS_RT_DEBUGF(5, "clamped is?: %d", rt_band_clamped_value_is_nodata(band, val));
466 
467  if (exclude_nodata_value && isnodata) {
468  arg1->nodata[z][i] = TRUE;
469  POSTGIS_RT_DEBUG(5, "nodata = 1");
470  }
471  else
472  POSTGIS_RT_DEBUG(5, "nodata = 0");
473 
474  i++;
475  }
476  }
477  }
478 
479  /* cleanup */
480  rt_raster_destroy(raster);
481  PG_FREE_IF_COPY(pgraster, 0);
482 
483  /* Store needed information */
484  funcctx->user_fctx = arg1;
485 
486  /* total number of tuples to be returned */
487  funcctx->max_calls = arg1->numbands;
488 
489  /* Build a tuple descriptor for our result type */
490  if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) {
491  MemoryContextSwitchTo(oldcontext);
492  ereport(ERROR, (
493  errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
494  errmsg(
495  "function returning record called in context "
496  "that cannot accept type record"
497  )
498  ));
499  }
500 
501  BlessTupleDesc(tupdesc);
502  funcctx->tuple_desc = tupdesc;
503 
504  MemoryContextSwitchTo(oldcontext);
505  }
506 
507  /* stuff done on every call of the function */
508  funcctx = SRF_PERCALL_SETUP();
509 
510  call_cntr = funcctx->call_cntr;
511  max_calls = funcctx->max_calls;
512  tupdesc = funcctx->tuple_desc;
513  arg2 = funcctx->user_fctx;
514 
515  /* do when there is more left to send */
516  if (call_cntr < max_calls) {
517  int values_length = 2;
518  Datum values[values_length];
519  bool nulls[values_length];
520  HeapTuple tuple;
521  Datum result;
522  ArrayType *mdValues = NULL;
523  int ndim = 2;
524  int dim[2] = {arg2->rows, arg2->columns};
525  int lbound[2] = {1, 1};
526 
527  POSTGIS_RT_DEBUGF(3, "call number %d", call_cntr);
528  POSTGIS_RT_DEBUGF(4, "dim = %d, %d", dim[0], dim[1]);
529 
530  memset(nulls, FALSE, sizeof(bool) * values_length);
531 
532  values[0] = Int32GetDatum(arg2->nbands[call_cntr] + 1);
533 
534  /* info about the type of item in the multi-dimensional array (float8). */
535  get_typlenbyvalalign(FLOAT8OID, &typlen, &typbyval, &typalign);
536 
537  /* if values is NULL, return empty array */
538  if (arg2->values[call_cntr] == NULL)
539  ndim = 0;
540 
541  /* assemble 3-dimension array of values */
542  mdValues = construct_md_array(
543  arg2->values[call_cntr], arg2->nodata[call_cntr],
544  ndim, dim, lbound,
545  FLOAT8OID,
546  typlen, typbyval, typalign
547  );
548  values[1] = PointerGetDatum(mdValues);
549 
550  /* build a tuple and datum */
551  tuple = heap_form_tuple(tupdesc, values, nulls);
552  result = HeapTupleGetDatum(tuple);
553 
554  SRF_RETURN_NEXT(funcctx, result);
555  }
556  /* do when there is no more left */
557  else {
559  SRF_RETURN_DONE(funcctx);
560  }
561 }
int rt_raster_get_num_bands(rt_raster raster)
Definition: rt_raster.c:372
raster
Be careful!! Zeros function&#39;s input parameter can be a (height x width) array, not (width x height): ...
Definition: rtrowdump.py:121
band
Definition: ovdump.py:57
int rt_raster_is_empty(rt_raster raster)
Return TRUE if the raster is empty.
Definition: rt_raster.c:1338
#define POSTGIS_RT_DEBUGF(level, msg,...)
Definition: rtpostgis.h:57
nband
Definition: pixval.py:52
static void rtpg_dumpvalues_arg_destroy(rtpg_dumpvalues_arg arg)
Definition: rtpg_pixel.c:173
static rtpg_dumpvalues_arg rtpg_dumpvalues_arg_init()
Definition: rtpg_pixel.c:153
rt_errorstate rt_band_get_pixel(rt_band band, int x, int y, double *value, int *nodata)
Get pixel value.
Definition: rt_band.c:1088
int rt_band_clamped_value_is_nodata(rt_band band, double val)
Compare clamped value to band&#39;s clamped NODATA value.
Definition: rt_band.c:1665
rt_band rt_raster_get_band(rt_raster raster, int bandNum)
Return Nth band, or NULL if unavailable.
Definition: rt_raster.c:381
int rt_raster_has_band(rt_raster raster, int nband)
Return TRUE if the raster has a band of this number.
Definition: rt_raster.c:1351
void rt_raster_destroy(rt_raster raster)
Release memory associated to a raster.
Definition: rt_raster.c:82
uint16_t rt_raster_get_width(rt_raster raster)
Definition: rt_raster.c:121
#define FALSE
Definition: dbfopen.c:168
Struct definitions.
Definition: librtcore.h:2213
int rt_band_get_isnodata_flag(rt_band band)
Get isnodata flag value.
Definition: rt_band.c:581
uint16_t rt_raster_get_height(rt_raster raster)
Definition: rt_raster.c:129
#define POSTGIS_RT_DEBUG(level, msg)
Definition: rtpostgis.h:53
#define TRUE
Definition: dbfopen.c:169
rt_raster rt_raster_deserialize(void *serialized, int header_only)
Return a raster from a serialized form.
Definition: rt_serialize.c:717
Here is the call graph for this function:
Here is the caller graph for this function: