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

Definition at line 4258 of file rt_pg.c.

References ovdump::band, ES_NONE, FALSE, rt_pixel_t::geom, gserialized_from_lwgeom(), lwgeom_free(), lwpoly_free(), pixval::nband, rt_pixel_t::nodata, POSTGIS_RT_DEBUG, POSTGIS_RT_DEBUGF, rtrowdump::raster, result, 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, pixval::x, rt_pixel_t::x, pixval::y, and rt_pixel_t::y.

4259 {
4260  FuncCallContext *funcctx;
4261  TupleDesc tupdesc;
4262  rt_pixel pix = NULL;
4263  rt_pixel pix2;
4264  int call_cntr;
4265  int max_calls;
4266  int i = 0;
4267 
4268  /* stuff done only on the first call of the function */
4269  if (SRF_IS_FIRSTCALL()) {
4270  MemoryContext oldcontext;
4271  rt_pgraster *pgraster = NULL;
4272  rt_raster raster = NULL;
4273  rt_band band = NULL;
4274  int nband = 1;
4275  int numbands;
4276  bool hasband = TRUE;
4277  bool exclude_nodata_value = TRUE;
4278  bool nocolumnx = FALSE;
4279  bool norowy = FALSE;
4280  int x = 0;
4281  int y = 0;
4282  int bounds[4] = {0};
4283  int pixcount = 0;
4284  double value = 0;
4285  int isnodata = 0;
4286 
4287  LWPOLY *poly;
4288 
4289  POSTGIS_RT_DEBUG(3, "RASTER_getPixelPolygons first call");
4290 
4291  /* create a function context for cross-call persistence */
4292  funcctx = SRF_FIRSTCALL_INIT();
4293 
4294  /* switch to memory context appropriate for multiple function calls */
4295  oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
4296 
4297  if (PG_ARGISNULL(0)) {
4298  MemoryContextSwitchTo(oldcontext);
4299  SRF_RETURN_DONE(funcctx);
4300  }
4301  pgraster = (rt_pgraster *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
4302 
4303  /* band */
4304  if (PG_ARGISNULL(1))
4305  hasband = FALSE;
4306  else {
4307  nband = PG_GETARG_INT32(1);
4308  hasband = TRUE;
4309  }
4310 
4311  /* column */
4312  if (PG_ARGISNULL(2))
4313  nocolumnx = TRUE;
4314  else {
4315  bounds[0] = PG_GETARG_INT32(2);
4316  bounds[1] = bounds[0];
4317  }
4318 
4319  /* row */
4320  if (PG_ARGISNULL(3))
4321  norowy = TRUE;
4322  else {
4323  bounds[2] = PG_GETARG_INT32(3);
4324  bounds[3] = bounds[2];
4325  }
4326 
4327  /* exclude NODATA */
4328  if (!PG_ARGISNULL(4))
4329  exclude_nodata_value = PG_GETARG_BOOL(4);
4330 
4331  raster = rt_raster_deserialize(pgraster, FALSE);
4332  if (!raster) {
4333  PG_FREE_IF_COPY(pgraster, 0);
4334  ereport(ERROR, (
4335  errcode(ERRCODE_OUT_OF_MEMORY),
4336  errmsg("Could not deserialize raster")
4337  ));
4338  MemoryContextSwitchTo(oldcontext);
4339  SRF_RETURN_DONE(funcctx);
4340  }
4341 
4342  /* raster empty, return NULL */
4343  if (rt_raster_is_empty(raster)) {
4344  elog(NOTICE, "Raster is empty. Returning NULL");
4345  rt_raster_destroy(raster);
4346  PG_FREE_IF_COPY(pgraster, 0);
4347  MemoryContextSwitchTo(oldcontext);
4348  SRF_RETURN_DONE(funcctx);
4349  }
4350 
4351  /* band specified, load band and info */
4352  if (hasband) {
4353  numbands = rt_raster_get_num_bands(raster);
4354  POSTGIS_RT_DEBUGF(3, "band %d", nband);
4355  POSTGIS_RT_DEBUGF(3, "# of bands %d", numbands);
4356 
4357  if (nband < 1 || nband > numbands) {
4358  elog(NOTICE, "Invalid band index (must use 1-based). Returning NULL");
4359  rt_raster_destroy(raster);
4360  PG_FREE_IF_COPY(pgraster, 0);
4361  MemoryContextSwitchTo(oldcontext);
4362  SRF_RETURN_DONE(funcctx);
4363  }
4364 
4365  band = rt_raster_get_band(raster, nband - 1);
4366  if (!band) {
4367  elog(NOTICE, "Could not find band at index %d. Returning NULL", nband);
4368  rt_raster_destroy(raster);
4369  PG_FREE_IF_COPY(pgraster, 0);
4370  MemoryContextSwitchTo(oldcontext);
4371  SRF_RETURN_DONE(funcctx);
4372  }
4373 
4374  if (!rt_band_get_hasnodata_flag(band))
4375  exclude_nodata_value = FALSE;
4376  }
4377 
4378  /* set bounds if columnx, rowy not set */
4379  if (nocolumnx) {
4380  bounds[0] = 1;
4381  bounds[1] = rt_raster_get_width(raster);
4382  }
4383  if (norowy) {
4384  bounds[2] = 1;
4385  bounds[3] = rt_raster_get_height(raster);
4386  }
4387  POSTGIS_RT_DEBUGF(3, "bounds (min x, max x, min y, max y) = (%d, %d, %d, %d)",
4388  bounds[0], bounds[1], bounds[2], bounds[3]);
4389 
4390  /* rowy */
4391  pixcount = 0;
4392  for (y = bounds[2]; y <= bounds[3]; y++) {
4393  /* columnx */
4394  for (x = bounds[0]; x <= bounds[1]; x++) {
4395 
4396  value = 0;
4397  isnodata = TRUE;
4398 
4399  if (hasband) {
4400  if (rt_band_get_pixel(band, x - 1, y - 1, &value, &isnodata) != ES_NONE) {
4401 
4402  for (i = 0; i < pixcount; i++)
4403  lwgeom_free(pix[i].geom);
4404  if (pixcount) pfree(pix);
4405 
4406  rt_band_destroy(band);
4407  rt_raster_destroy(raster);
4408  PG_FREE_IF_COPY(pgraster, 0);
4409 
4410  MemoryContextSwitchTo(oldcontext);
4411  elog(ERROR, "RASTER_getPixelPolygons: Could not get pixel value");
4412  SRF_RETURN_DONE(funcctx);
4413  }
4414 
4415  /* don't continue if pixel is NODATA and to exclude NODATA */
4416  if (isnodata && exclude_nodata_value) {
4417  POSTGIS_RT_DEBUG(5, "pixel value is NODATA and exclude_nodata_value = TRUE");
4418  continue;
4419  }
4420  }
4421 
4422  /* geometry */
4423  poly = rt_raster_pixel_as_polygon(raster, x - 1, y - 1);
4424  if (!poly) {
4425  for (i = 0; i < pixcount; i++)
4426  lwgeom_free(pix[i].geom);
4427  if (pixcount) pfree(pix);
4428 
4429  if (hasband) rt_band_destroy(band);
4430  rt_raster_destroy(raster);
4431  PG_FREE_IF_COPY(pgraster, 0);
4432 
4433  MemoryContextSwitchTo(oldcontext);
4434  elog(ERROR, "RASTER_getPixelPolygons: Could not get pixel polygon");
4435  SRF_RETURN_DONE(funcctx);
4436  }
4437 
4438  if (!pixcount)
4439  pix = palloc(sizeof(struct rt_pixel_t) * (pixcount + 1));
4440  else
4441  pix = repalloc(pix, sizeof(struct rt_pixel_t) * (pixcount + 1));
4442  if (pix == NULL) {
4443 
4444  lwpoly_free(poly);
4445  if (hasband) rt_band_destroy(band);
4446  rt_raster_destroy(raster);
4447  PG_FREE_IF_COPY(pgraster, 0);
4448 
4449  MemoryContextSwitchTo(oldcontext);
4450  elog(ERROR, "RASTER_getPixelPolygons: Could not allocate memory for storing pixel polygons");
4451  SRF_RETURN_DONE(funcctx);
4452  }
4453  pix[pixcount].geom = (LWGEOM *) poly;
4454  POSTGIS_RT_DEBUGF(5, "poly @ %p", poly);
4455  POSTGIS_RT_DEBUGF(5, "geom @ %p", pix[pixcount].geom);
4456 
4457  /* x, y */
4458  pix[pixcount].x = x;
4459  pix[pixcount].y = y;
4460 
4461  /* value */
4462  pix[pixcount].value = value;
4463 
4464  /* NODATA */
4465  if (hasband) {
4466  if (exclude_nodata_value)
4467  pix[pixcount].nodata = isnodata;
4468  else
4469  pix[pixcount].nodata = FALSE;
4470  }
4471  else {
4472  pix[pixcount].nodata = isnodata;
4473  }
4474 
4475  pixcount++;
4476  }
4477  }
4478 
4479  if (hasband) rt_band_destroy(band);
4480  rt_raster_destroy(raster);
4481  PG_FREE_IF_COPY(pgraster, 0);
4482 
4483  /* shortcut if no pixcount */
4484  if (pixcount < 1) {
4485  elog(NOTICE, "No pixels found for band %d", nband);
4486  MemoryContextSwitchTo(oldcontext);
4487  SRF_RETURN_DONE(funcctx);
4488  }
4489 
4490  /* Store needed information */
4491  funcctx->user_fctx = pix;
4492 
4493  /* total number of tuples to be returned */
4494  funcctx->max_calls = pixcount;
4495  POSTGIS_RT_DEBUGF(3, "pixcount = %d", pixcount);
4496 
4497  /* Build a tuple descriptor for our result type */
4498  if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) {
4499  ereport(ERROR, (
4500  errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4501  errmsg("function returning record called in context that cannot accept type record")
4502  ));
4503  }
4504 
4505  BlessTupleDesc(tupdesc);
4506  funcctx->tuple_desc = tupdesc;
4507 
4508  MemoryContextSwitchTo(oldcontext);
4509  }
4510 
4511  /* stuff done on every call of the function */
4512  funcctx = SRF_PERCALL_SETUP();
4513 
4514  call_cntr = funcctx->call_cntr;
4515  max_calls = funcctx->max_calls;
4516  tupdesc = funcctx->tuple_desc;
4517  pix2 = funcctx->user_fctx;
4518 
4519  /* do when there is more left to send */
4520  if (call_cntr < max_calls) {
4521  int values_length = 4;
4522  Datum values[values_length];
4523  bool nulls[values_length];
4524  HeapTuple tuple;
4525  Datum result;
4526 
4527  GSERIALIZED *gser = NULL;
4528  size_t gser_size = 0;
4529 
4530  POSTGIS_RT_DEBUGF(3, "call number %d", call_cntr);
4531 
4532  memset(nulls, FALSE, sizeof(bool) * values_length);
4533 
4534  /* convert LWGEOM to GSERIALIZED */
4535  gser = gserialized_from_lwgeom(pix2[call_cntr].geom, 0, &gser_size);
4536  lwgeom_free(pix2[call_cntr].geom);
4537 
4538  values[0] = PointerGetDatum(gser);
4539  if (pix2[call_cntr].nodata)
4540  nulls[1] = TRUE;
4541  else
4542  values[1] = Float8GetDatum(pix2[call_cntr].value);
4543  values[2] = Int32GetDatum(pix2[call_cntr].x);
4544  values[3] = Int32GetDatum(pix2[call_cntr].y);
4545 
4546  /* build a tuple */
4547  tuple = heap_form_tuple(tupdesc, values, nulls);
4548 
4549  /* make the tuple into a datum */
4550  result = HeapTupleGetDatum(tuple);
4551 
4552  SRF_RETURN_NEXT(funcctx, result);
4553  }
4554  /* do when there is no more left */
4555  else {
4556  pfree(pix2);
4557  SRF_RETURN_DONE(funcctx);
4558  }
4559 }
LWPOLY * rt_raster_pixel_as_polygon(rt_raster rast, int x, int y)
Get a raster pixel as a polygon.
Definition: rt_api.c:13182
int rt_raster_get_num_bands(rt_raster raster)
Definition: rt_api.c:5677
void rt_raster_destroy(rt_raster raster)
Release memory associated to a raster.
Definition: rt_api.c:5387
void lwgeom_free(LWGEOM *geom)
Definition: lwgeom.c:1006
LWGEOM * geom
Definition: rt_api.h:2265
tuple band
Definition: ovdump.py:57
double value
Definition: rt_api.h:2263
tuple raster
Be careful!! Zeros function's input parameter can be a (height x width) array, not (width x height): ...
Definition: rtrowdump.py:123
char ** result
Definition: liblwgeom.h:218
#define POSTGIS_RT_DEBUG(level, msg)
Definition: rt_pg.h:58
void lwpoly_free(LWPOLY *poly)
Definition: lwpoly.c:79
tuple nband
Definition: pixval.py:52
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
GSERIALIZED * gserialized_from_lwgeom(LWGEOM *geom, int is_geodetic, size_t *size)
Allocate a new GSERIALIZED from an LWGEOM.
Definition: g_serialized.c:908
uint8_t nodata
Definition: rt_api.h:2262
tuple x
Definition: pixval.py:53
void rt_band_destroy(rt_band band)
Destroy a raster band.
Definition: rt_api.c:1650
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
int rt_raster_is_empty(rt_raster raster)
Return TRUE if the raster is empty.
Definition: rt_api.c:8550
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

Here is the call graph for this function: