PostGIS  2.4.9dev-r@@SVN_REVISION@@

◆ RASTER_getPixelPolygons()

Datum RASTER_getPixelPolygons ( PG_FUNCTION_ARGS  )

Definition at line 355 of file rtpg_geometry.c.

References ovdump::band, ES_NONE, FALSE, rt_pixel_t::geom, gserialized_from_lwgeom(), lwgeom_free(), lwpoly_free(), pixval::nband, rt_pixel_t::nodata, PG_FUNCTION_INFO_V1(), POSTGIS_RT_DEBUG, POSTGIS_RT_DEBUGF, rtrowdump::raster, RASTER_getPolygon(), rt_band_destroy(), rt_band_get_hasnodata_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_is_empty(), rt_raster_pixel_as_polygon(), TRUE, genraster::value, rt_pixel_t::value, VALUES_LENGTH, pixval::x, rt_pixel_t::x, pixval::y, and rt_pixel_t::y.

356 {
357  FuncCallContext *funcctx;
358  TupleDesc tupdesc;
359  rt_pixel pix = NULL;
360  rt_pixel pix2;
361  int call_cntr;
362  int max_calls;
363  int i = 0;
364 
365  /* stuff done only on the first call of the function */
366  if (SRF_IS_FIRSTCALL()) {
367  MemoryContext oldcontext;
368  rt_pgraster *pgraster = NULL;
369  rt_raster raster = NULL;
370  rt_band band = NULL;
371  int nband = 1;
372  int numbands;
373  bool hasband = TRUE;
374  bool exclude_nodata_value = TRUE;
375  bool nocolumnx = FALSE;
376  bool norowy = FALSE;
377  int x = 0;
378  int y = 0;
379  int bounds[4] = {0};
380  int pixcount = 0;
381  double value = 0;
382  int isnodata = 0;
383 
384  LWPOLY *poly;
385 
386  POSTGIS_RT_DEBUG(3, "RASTER_getPixelPolygons first call");
387 
388  /* create a function context for cross-call persistence */
389  funcctx = SRF_FIRSTCALL_INIT();
390 
391  /* switch to memory context appropriate for multiple function calls */
392  oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
393 
394  if (PG_ARGISNULL(0)) {
395  MemoryContextSwitchTo(oldcontext);
396  SRF_RETURN_DONE(funcctx);
397  }
398  pgraster = (rt_pgraster *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
399 
400  /* band */
401  if (PG_ARGISNULL(1))
402  hasband = FALSE;
403  else {
404  nband = PG_GETARG_INT32(1);
405  hasband = TRUE;
406  }
407 
408  /* column */
409  if (PG_ARGISNULL(2))
410  nocolumnx = TRUE;
411  else {
412  bounds[0] = PG_GETARG_INT32(2);
413  bounds[1] = bounds[0];
414  }
415 
416  /* row */
417  if (PG_ARGISNULL(3))
418  norowy = TRUE;
419  else {
420  bounds[2] = PG_GETARG_INT32(3);
421  bounds[3] = bounds[2];
422  }
423 
424  /* exclude NODATA */
425  if (!PG_ARGISNULL(4))
426  exclude_nodata_value = PG_GETARG_BOOL(4);
427 
428  raster = rt_raster_deserialize(pgraster, FALSE);
429  if (!raster) {
430  PG_FREE_IF_COPY(pgraster, 0);
431  ereport(ERROR, (
432  errcode(ERRCODE_OUT_OF_MEMORY),
433  errmsg("Could not deserialize raster")
434  ));
435  MemoryContextSwitchTo(oldcontext);
436  SRF_RETURN_DONE(funcctx);
437  }
438 
439  /* raster empty, return NULL */
440  if (rt_raster_is_empty(raster)) {
441  elog(NOTICE, "Raster is empty. Returning NULL");
442  rt_raster_destroy(raster);
443  PG_FREE_IF_COPY(pgraster, 0);
444  MemoryContextSwitchTo(oldcontext);
445  SRF_RETURN_DONE(funcctx);
446  }
447 
448  /* band specified, load band and info */
449  if (hasband) {
450  numbands = rt_raster_get_num_bands(raster);
451  POSTGIS_RT_DEBUGF(3, "band %d", nband);
452  POSTGIS_RT_DEBUGF(3, "# of bands %d", numbands);
453 
454  if (nband < 1 || nband > numbands) {
455  elog(NOTICE, "Invalid band index (must use 1-based). Returning NULL");
456  rt_raster_destroy(raster);
457  PG_FREE_IF_COPY(pgraster, 0);
458  MemoryContextSwitchTo(oldcontext);
459  SRF_RETURN_DONE(funcctx);
460  }
461 
462  band = rt_raster_get_band(raster, nband - 1);
463  if (!band) {
464  elog(NOTICE, "Could not find band at index %d. Returning NULL", nband);
465  rt_raster_destroy(raster);
466  PG_FREE_IF_COPY(pgraster, 0);
467  MemoryContextSwitchTo(oldcontext);
468  SRF_RETURN_DONE(funcctx);
469  }
470 
471  if (!rt_band_get_hasnodata_flag(band))
472  exclude_nodata_value = FALSE;
473  }
474 
475  /* set bounds if columnx, rowy not set */
476  if (nocolumnx) {
477  bounds[0] = 1;
478  bounds[1] = rt_raster_get_width(raster);
479  }
480  if (norowy) {
481  bounds[2] = 1;
482  bounds[3] = rt_raster_get_height(raster);
483  }
484  POSTGIS_RT_DEBUGF(3, "bounds (min x, max x, min y, max y) = (%d, %d, %d, %d)",
485  bounds[0], bounds[1], bounds[2], bounds[3]);
486 
487  /* rowy */
488  pixcount = 0;
489  for (y = bounds[2]; y <= bounds[3]; y++) {
490  /* columnx */
491  for (x = bounds[0]; x <= bounds[1]; x++) {
492 
493  value = 0;
494  isnodata = TRUE;
495 
496  if (hasband) {
497  if (rt_band_get_pixel(band, x - 1, y - 1, &value, &isnodata) != ES_NONE) {
498 
499  for (i = 0; i < pixcount; i++)
500  lwgeom_free(pix[i].geom);
501  if (pixcount) pfree(pix);
502 
503  rt_band_destroy(band);
504  rt_raster_destroy(raster);
505  PG_FREE_IF_COPY(pgraster, 0);
506 
507  MemoryContextSwitchTo(oldcontext);
508  elog(ERROR, "RASTER_getPixelPolygons: Could not get pixel value");
509  SRF_RETURN_DONE(funcctx);
510  }
511 
512  /* don't continue if pixel is NODATA and to exclude NODATA */
513  if (isnodata && exclude_nodata_value) {
514  POSTGIS_RT_DEBUG(5, "pixel value is NODATA and exclude_nodata_value = TRUE");
515  continue;
516  }
517  }
518 
519  /* geometry */
520  poly = rt_raster_pixel_as_polygon(raster, x - 1, y - 1);
521  if (!poly) {
522  for (i = 0; i < pixcount; i++)
523  lwgeom_free(pix[i].geom);
524  if (pixcount) pfree(pix);
525 
526  if (hasband) rt_band_destroy(band);
527  rt_raster_destroy(raster);
528  PG_FREE_IF_COPY(pgraster, 0);
529 
530  MemoryContextSwitchTo(oldcontext);
531  elog(ERROR, "RASTER_getPixelPolygons: Could not get pixel polygon");
532  SRF_RETURN_DONE(funcctx);
533  }
534 
535  if (!pixcount)
536  pix = palloc(sizeof(struct rt_pixel_t) * (pixcount + 1));
537  else
538  pix = repalloc(pix, sizeof(struct rt_pixel_t) * (pixcount + 1));
539  if (pix == NULL) {
540 
541  lwpoly_free(poly);
542  if (hasband) rt_band_destroy(band);
543  rt_raster_destroy(raster);
544  PG_FREE_IF_COPY(pgraster, 0);
545 
546  MemoryContextSwitchTo(oldcontext);
547  elog(ERROR, "RASTER_getPixelPolygons: Could not allocate memory for storing pixel polygons");
548  SRF_RETURN_DONE(funcctx);
549  }
550  pix[pixcount].geom = (LWGEOM *) poly;
551  POSTGIS_RT_DEBUGF(5, "poly @ %p", poly);
552  POSTGIS_RT_DEBUGF(5, "geom @ %p", pix[pixcount].geom);
553 
554  /* x, y */
555  pix[pixcount].x = x;
556  pix[pixcount].y = y;
557 
558  /* value */
559  pix[pixcount].value = value;
560 
561  /* NODATA */
562  if (hasband) {
563  if (exclude_nodata_value)
564  pix[pixcount].nodata = isnodata;
565  else
566  pix[pixcount].nodata = FALSE;
567  }
568  else {
569  pix[pixcount].nodata = isnodata;
570  }
571 
572  pixcount++;
573  }
574  }
575 
576  if (hasband) rt_band_destroy(band);
577  rt_raster_destroy(raster);
578  PG_FREE_IF_COPY(pgraster, 0);
579 
580  /* shortcut if no pixcount */
581  if (pixcount < 1) {
582  elog(NOTICE, "No pixels found for band %d", nband);
583  MemoryContextSwitchTo(oldcontext);
584  SRF_RETURN_DONE(funcctx);
585  }
586 
587  /* Store needed information */
588  funcctx->user_fctx = pix;
589 
590  /* total number of tuples to be returned */
591  funcctx->max_calls = pixcount;
592  POSTGIS_RT_DEBUGF(3, "pixcount = %d", pixcount);
593 
594  /* Build a tuple descriptor for our result type */
595  if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) {
596  ereport(ERROR, (
597  errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
598  errmsg("function returning record called in context that cannot accept type record")
599  ));
600  }
601 
602  BlessTupleDesc(tupdesc);
603  funcctx->tuple_desc = tupdesc;
604 
605  MemoryContextSwitchTo(oldcontext);
606  }
607 
608  /* stuff done on every call of the function */
609  funcctx = SRF_PERCALL_SETUP();
610 
611  call_cntr = funcctx->call_cntr;
612  max_calls = funcctx->max_calls;
613  tupdesc = funcctx->tuple_desc;
614  pix2 = funcctx->user_fctx;
615 
616  /* do when there is more left to send */
617  if (call_cntr < max_calls) {
618  Datum values[VALUES_LENGTH];
619  bool nulls[VALUES_LENGTH];
620  HeapTuple tuple;
621  Datum result;
622 
623  GSERIALIZED *gser = NULL;
624  size_t gser_size = 0;
625 
626  POSTGIS_RT_DEBUGF(3, "call number %d", call_cntr);
627 
628  memset(nulls, FALSE, sizeof(bool) * VALUES_LENGTH);
629 
630  /* convert LWGEOM to GSERIALIZED */
631  gser = gserialized_from_lwgeom(pix2[call_cntr].geom, &gser_size);
632  lwgeom_free(pix2[call_cntr].geom);
633 
634  values[0] = PointerGetDatum(gser);
635  if (pix2[call_cntr].nodata)
636  nulls[1] = TRUE;
637  else
638  values[1] = Float8GetDatum(pix2[call_cntr].value);
639  values[2] = Int32GetDatum(pix2[call_cntr].x);
640  values[3] = Int32GetDatum(pix2[call_cntr].y);
641 
642  /* build a tuple */
643  tuple = heap_form_tuple(tupdesc, values, nulls);
644 
645  /* make the tuple into a datum */
646  result = HeapTupleGetDatum(tuple);
647 
648  SRF_RETURN_NEXT(funcctx, result);
649  }
650  /* do when there is no more left */
651  else {
652  pfree(pix2);
653  SRF_RETURN_DONE(funcctx);
654  }
655 }
int rt_raster_get_num_bands(rt_raster raster)
Definition: rt_raster.c:372
#define VALUES_LENGTH
raster
Be careful!! Zeros function&#39;s input parameter can be a (height x width) array, not (width x height): ...
Definition: rtrowdump.py:121
void lwgeom_free(LWGEOM *geom)
Definition: lwgeom.c:1099
band
Definition: ovdump.py:57
LWGEOM * geom
Definition: librtcore.h:2291
double value
Definition: librtcore.h:2289
void rt_band_destroy(rt_band band)
Destroy a raster band.
Definition: rt_band.c:242
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:65
nband
Definition: pixval.py:52
void lwpoly_free(LWPOLY *poly)
Definition: lwpoly.c:174
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
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_band_get_hasnodata_flag(rt_band band)
Get hasnodata flag value.
Definition: rt_band.c:541
LWPOLY * rt_raster_pixel_as_polygon(rt_raster raster, int x, int y)
Get a raster pixel as a polygon.
Definition: rt_geometry.c:610
void rt_raster_destroy(rt_raster raster)
Release memory associated to a raster.
Definition: rt_raster.c:82
uint8_t nodata
Definition: librtcore.h:2288
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:2201
int value
Definition: genraster.py:61
uint16_t rt_raster_get_height(rt_raster raster)
Definition: rt_raster.c:129
#define POSTGIS_RT_DEBUG(level, msg)
Definition: rtpostgis.h:61
GSERIALIZED * gserialized_from_lwgeom(LWGEOM *geom, size_t *size)
Allocate a new GSERIALIZED from an LWGEOM.
#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: