PostGIS  2.5.7dev-r@@SVN_REVISION@@
rtpg_geometry.c
Go to the documentation of this file.
1 /*
2  *
3  * WKTRaster - Raster Types for PostGIS
4  * http://trac.osgeo.org/postgis/wiki/WKTRaster
5  *
6  * Copyright (C) 2011-2013 Regents of the University of California
7  * <bkpark@ucdavis.edu>
8  * Copyright (C) 2010-2011 Jorge Arevalo <jorge.arevalo@deimos-space.com>
9  * Copyright (C) 2010-2011 David Zwarg <dzwarg@azavea.com>
10  * Copyright (C) 2009-2011 Pierre Racine <pierre.racine@sbf.ulaval.ca>
11  * Copyright (C) 2009-2011 Mateusz Loskot <mateusz@loskot.net>
12  * Copyright (C) 2008-2009 Sandro Santilli <strk@kbt.io>
13  *
14  * This program is free software; you can redistribute it and/or
15  * modify it under the terms of the GNU General Public License
16  * as published by the Free Software Foundation; either version 2
17  * of the License, or (at your option) any later version.
18  *
19  * This program is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22  * GNU General Public License for more details.
23  *
24  * You should have received a copy of the GNU General Public License
25  * along with this program; if not, write to the Free Software Foundation,
26  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
27  *
28  */
29 
30 #include <postgres.h>
31 #include <fmgr.h>
32 #include <funcapi.h>
33 #include <utils/lsyscache.h> /* for get_typlenbyvalalign */
34 #include <utils/array.h> /* for ArrayType */
35 #include <catalog/pg_type.h> /* for INT2OID, INT4OID, FLOAT4OID, FLOAT8OID and TEXTOID */
36 #include <utils/builtins.h> /* for text_to_cstring() */
37 
38 #include "../../postgis_config.h"
39 
40 #if POSTGIS_PGSQL_VERSION > 92
41 #include "access/htup_details.h" /* for heap_form_tuple() */
42 #endif
43 
44 #include "lwgeom_pg.h"
45 
46 #include "rtpostgis.h"
47 #include "rtpg_internal.h"
48 
49 Datum RASTER_envelope(PG_FUNCTION_ARGS);
50 Datum RASTER_convex_hull(PG_FUNCTION_ARGS);
51 Datum RASTER_dumpAsPolygons(PG_FUNCTION_ARGS);
52 
53 /* Get pixel geographical shape */
54 Datum RASTER_getPixelPolygons(PG_FUNCTION_ARGS);
55 
56 /* Get raster band's polygon */
57 Datum RASTER_getPolygon(PG_FUNCTION_ARGS);
58 
59 /* rasterize a geometry */
60 Datum RASTER_asRaster(PG_FUNCTION_ARGS);
61 
62 /* ---------------------------------------------------------------- */
63 /* Raster envelope */
64 /* ---------------------------------------------------------------- */
66 Datum RASTER_envelope(PG_FUNCTION_ARGS)
67 {
68  rt_pgraster *pgraster;
70  LWGEOM *geom = NULL;
71  GSERIALIZED* gser = NULL;
72  size_t gser_size;
73  int err = ES_NONE;
74 
75  if (PG_ARGISNULL(0))
76  PG_RETURN_NULL();
77 
78  pgraster = (rt_pgraster *) PG_DETOAST_DATUM_SLICE(
79  PG_GETARG_DATUM(0),
80  0,
81  sizeof(struct rt_raster_serialized_t)
82  );
83  raster = rt_raster_deserialize(pgraster, TRUE);
84 
85  if (!raster) {
86  PG_FREE_IF_COPY(pgraster, 0);
87  elog(ERROR, "RASTER_envelope: Could not deserialize raster");
88  PG_RETURN_NULL();
89  }
90 
91  err = rt_raster_get_envelope_geom(raster, &geom);
92 
94  PG_FREE_IF_COPY(pgraster, 0);
95 
96  if (err != ES_NONE) {
97  elog(ERROR, "RASTER_envelope: Could not get raster's envelope");
98  PG_RETURN_NULL();
99  }
100  else if (geom == NULL) {
101  elog(NOTICE, "Raster's envelope is NULL");
102  PG_RETURN_NULL();
103  }
104 
105  gser = gserialized_from_lwgeom(geom, &gser_size);
106  lwgeom_free(geom);
107 
108  SET_VARSIZE(gser, gser_size);
109  PG_RETURN_POINTER(gser);
110 }
111 
115 /* ---------------------------------------------------------------- */
116 /* Raster convex hull */
117 /* ---------------------------------------------------------------- */
119 Datum RASTER_convex_hull(PG_FUNCTION_ARGS)
120 {
121  rt_pgraster *pgraster;
123  LWGEOM *geom = NULL;
124  GSERIALIZED* gser = NULL;
125  size_t gser_size;
126  int err = ES_NONE;
127 
128  bool minhull = FALSE;
129 
130  if (PG_ARGISNULL(0))
131  PG_RETURN_NULL();
132 
133  /* # of args */
134  if (PG_NARGS() > 1)
135  minhull = TRUE;
136 
137  if (!minhull) {
138  pgraster = (rt_pgraster *) PG_DETOAST_DATUM_SLICE(PG_GETARG_DATUM(0), 0, sizeof(struct rt_raster_serialized_t));
139  raster = rt_raster_deserialize(pgraster, TRUE);
140  }
141  else {
142  pgraster = (rt_pgraster *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
143  raster = rt_raster_deserialize(pgraster, FALSE);
144  }
145 
146  if (!raster) {
147  PG_FREE_IF_COPY(pgraster, 0);
148  elog(ERROR, "RASTER_convex_hull: Could not deserialize raster");
149  PG_RETURN_NULL();
150  }
151 
152  if (!minhull)
153  err = rt_raster_get_convex_hull(raster, &geom);
154  else {
155  int nband = -1;
156 
157  /* get arg 1 */
158  if (!PG_ARGISNULL(1)) {
159  nband = PG_GETARG_INT32(1);
160  if (!rt_raster_has_band(raster, nband - 1)) {
161  elog(NOTICE, "Invalid band index (must use 1-based). Returning NULL");
163  PG_FREE_IF_COPY(pgraster, 0);
164  PG_RETURN_NULL();
165  }
166  nband = nband - 1;
167  }
168 
169  err = rt_raster_get_perimeter(raster, nband, &geom);
170  }
171 
173  PG_FREE_IF_COPY(pgraster, 0);
174 
175  if (err != ES_NONE) {
176  elog(ERROR, "RASTER_convex_hull: Could not get raster's convex hull");
177  PG_RETURN_NULL();
178  }
179  else if (geom == NULL) {
180  elog(NOTICE, "Raster's convex hull is NULL");
181  PG_RETURN_NULL();
182  }
183 
184  gser = gserialized_from_lwgeom(geom, &gser_size);
185  lwgeom_free(geom);
186 
187  SET_VARSIZE(gser, gser_size);
188  PG_RETURN_POINTER(gser);
189 }
190 
191 #define VALUES_LENGTH 2
192 
194 Datum RASTER_dumpAsPolygons(PG_FUNCTION_ARGS) {
195  FuncCallContext *funcctx;
196  TupleDesc tupdesc;
197  rt_geomval geomval;
198  rt_geomval geomval2;
199  int call_cntr;
200  int max_calls;
201 
202  /* stuff done only on the first call of the function */
203  if (SRF_IS_FIRSTCALL()) {
204  MemoryContext oldcontext;
205  int numbands;
206  rt_pgraster *pgraster = NULL;
207  rt_raster raster = NULL;
208  int nband;
209  bool exclude_nodata_value = TRUE;
210  int nElements;
211 
212  POSTGIS_RT_DEBUG(2, "RASTER_dumpAsPolygons first call");
213 
214  /* create a function context for cross-call persistence */
215  funcctx = SRF_FIRSTCALL_INIT();
216 
217  /* switch to memory context appropriate for multiple function calls */
218  oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
219 
220  /* Get input arguments */
221  if (PG_ARGISNULL(0)) {
222  MemoryContextSwitchTo(oldcontext);
223  SRF_RETURN_DONE(funcctx);
224  }
225  pgraster = (rt_pgraster *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
226  raster = rt_raster_deserialize(pgraster, FALSE);
227  if (!raster) {
228  PG_FREE_IF_COPY(pgraster, 0);
229  ereport(ERROR, (
230  errcode(ERRCODE_OUT_OF_MEMORY),
231  errmsg("Could not deserialize raster")
232  ));
233  MemoryContextSwitchTo(oldcontext);
234  SRF_RETURN_DONE(funcctx);
235  }
236 
237  if (!PG_ARGISNULL(1))
238  nband = PG_GETARG_UINT32(1);
239  else
240  nband = 1; /* By default, first band */
241 
242  POSTGIS_RT_DEBUGF(3, "band %d", nband);
243  numbands = rt_raster_get_num_bands(raster);
244 
245  if (nband < 1 || nband > numbands) {
246  elog(NOTICE, "Invalid band index (must use 1-based). Returning NULL");
248  PG_FREE_IF_COPY(pgraster, 0);
249  MemoryContextSwitchTo(oldcontext);
250  SRF_RETURN_DONE(funcctx);
251  }
252 
253  if (!PG_ARGISNULL(2))
254  exclude_nodata_value = PG_GETARG_BOOL(2);
255 
256  /* see if band is NODATA */
258  POSTGIS_RT_DEBUGF(3, "Band at index %d is NODATA. Returning NULL", nband);
260  PG_FREE_IF_COPY(pgraster, 0);
261  MemoryContextSwitchTo(oldcontext);
262  SRF_RETURN_DONE(funcctx);
263  }
264 
265  /* Polygonize raster */
266 
270  geomval = rt_raster_gdal_polygonize(raster, nband - 1, exclude_nodata_value, &nElements);
272  PG_FREE_IF_COPY(pgraster, 0);
273  if (NULL == geomval) {
274  ereport(ERROR, (
275  errcode(ERRCODE_NO_DATA_FOUND),
276  errmsg("Could not polygonize raster")
277  ));
278  MemoryContextSwitchTo(oldcontext);
279  SRF_RETURN_DONE(funcctx);
280  }
281 
282  POSTGIS_RT_DEBUGF(3, "raster dump, %d elements returned", nElements);
283 
284  /* Store needed information */
285  funcctx->user_fctx = geomval;
286 
287  /* total number of tuples to be returned */
288  funcctx->max_calls = nElements;
289 
290  /* Build a tuple descriptor for our result type */
291  if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) {
292  ereport(ERROR, (
293  errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
294  errmsg("function returning record called in context that cannot accept type record")
295  ));
296  }
297 
298  BlessTupleDesc(tupdesc);
299  funcctx->tuple_desc = tupdesc;
300 
301  MemoryContextSwitchTo(oldcontext);
302  }
303 
304  /* stuff done on every call of the function */
305  funcctx = SRF_PERCALL_SETUP();
306 
307  call_cntr = funcctx->call_cntr;
308  max_calls = funcctx->max_calls;
309  tupdesc = funcctx->tuple_desc;
310  geomval2 = funcctx->user_fctx;
311 
312  /* do when there is more left to send */
313  if (call_cntr < max_calls) {
314  Datum values[VALUES_LENGTH];
315  bool nulls[VALUES_LENGTH];
316  HeapTuple tuple;
317  Datum result;
318 
319  GSERIALIZED *gser = NULL;
320  size_t gser_size = 0;
321 
322  POSTGIS_RT_DEBUGF(3, "call number %d", call_cntr);
323 
324  memset(nulls, FALSE, sizeof(bool) * VALUES_LENGTH);
325 
326  /* convert LWGEOM to GSERIALIZED */
327  gser = gserialized_from_lwgeom(lwpoly_as_lwgeom(geomval2[call_cntr].geom), &gser_size);
328  lwgeom_free(lwpoly_as_lwgeom(geomval2[call_cntr].geom));
329 
330  values[0] = PointerGetDatum(gser);
331  values[1] = Float8GetDatum(geomval2[call_cntr].val);
332 
333  /* build a tuple */
334  tuple = heap_form_tuple(tupdesc, values, nulls);
335 
336  /* make the tuple into a datum */
337  result = HeapTupleGetDatum(tuple);
338 
339  SRF_RETURN_NEXT(funcctx, result);
340  }
341  /* do when there is no more left */
342  else {
343  pfree(geomval2);
344  SRF_RETURN_DONE(funcctx);
345  }
346 }
347 
348 #undef VALUES_LENGTH
349 #define VALUES_LENGTH 4
350 
355 Datum RASTER_getPixelPolygons(PG_FUNCTION_ARGS)
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");
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");
457  PG_FREE_IF_COPY(pgraster, 0);
458  MemoryContextSwitchTo(oldcontext);
459  SRF_RETURN_DONE(funcctx);
460  }
461 
463  if (!band) {
464  elog(NOTICE, "Could not find band at index %d. Returning NULL", nband);
466  PG_FREE_IF_COPY(pgraster, 0);
467  MemoryContextSwitchTo(oldcontext);
468  SRF_RETURN_DONE(funcctx);
469  }
470 
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 
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);
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);
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);
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 }
656 
661 Datum RASTER_getPolygon(PG_FUNCTION_ARGS)
662 {
663  rt_pgraster *pgraster = NULL;
664  rt_raster raster = NULL;
665  int num_bands = 0;
666  int nband = 1;
667  int err;
668  LWMPOLY *surface = NULL;
669  GSERIALIZED *rtn = NULL;
670 
671  /* raster */
672  if (PG_ARGISNULL(0))
673  PG_RETURN_NULL();
674  pgraster = (rt_pgraster *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
675 
676  raster = rt_raster_deserialize(pgraster, FALSE);
677  if (!raster) {
678  PG_FREE_IF_COPY(pgraster, 0);
679  elog(ERROR, "RASTER_getPolygon: Could not deserialize raster");
680  PG_RETURN_NULL();
681  }
682 
683  /* num_bands */
684  num_bands = rt_raster_get_num_bands(raster);
685  if (num_bands < 1) {
686  elog(NOTICE, "Raster provided has no bands");
688  PG_FREE_IF_COPY(pgraster, 0);
689  PG_RETURN_NULL();
690  }
691 
692  /* band index is 1-based */
693  if (!PG_ARGISNULL(1))
694  nband = PG_GETARG_INT32(1);
695  if (nband < 1 || nband > num_bands) {
696  elog(NOTICE, "Invalid band index (must use 1-based). Returning NULL");
698  PG_FREE_IF_COPY(pgraster, 0);
699  PG_RETURN_NULL();
700  }
701 
702  /* get band surface */
703  err = rt_raster_surface(raster, nband - 1, &surface);
705  PG_FREE_IF_COPY(pgraster, 0);
706 
707  if (err != ES_NONE) {
708  elog(ERROR, "RASTER_getPolygon: Could not get raster band's surface");
709  PG_RETURN_NULL();
710  }
711  else if (surface == NULL) {
712  elog(NOTICE, "Raster is empty or all pixels of band are NODATA. Returning NULL");
713  PG_RETURN_NULL();
714  }
715 
716  rtn = geometry_serialize(lwmpoly_as_lwgeom(surface));
717  lwmpoly_free(surface);
718 
719  PG_RETURN_POINTER(rtn);
720 }
721 
726 Datum RASTER_asRaster(PG_FUNCTION_ARGS)
727 {
728  GSERIALIZED *gser = NULL;
729 
730  LWGEOM *geom = NULL;
731  rt_raster rast = NULL;
732  rt_pgraster *pgrast = NULL;
733 
734  unsigned char *wkb;
735  size_t wkb_len = 0;
736  unsigned char variant = WKB_SFSQL;
737 
738  double scale[2] = {0};
739  double *scale_x = NULL;
740  double *scale_y = NULL;
741 
742  int dim[2] = {0};
743  int *dim_x = NULL;
744  int *dim_y = NULL;
745 
746  ArrayType *array;
747  Oid etype;
748  Datum *e;
749  bool *nulls;
750  int16 typlen;
751  bool typbyval;
752  char typalign;
753  int n = 0;
754  int i = 0;
755  int j = 0;
756  int haserr = 0;
757 
758  text *pixeltypetext = NULL;
759  char *pixeltype = NULL;
760  rt_pixtype pixtype = PT_END;
761  rt_pixtype *pixtypes = NULL;
762  uint32_t pixtypes_len = 0;
763 
764  double *values = NULL;
765  uint32_t values_len = 0;
766 
767  uint8_t *hasnodatas = NULL;
768  double *nodatavals = NULL;
769  uint32_t nodatavals_len = 0;
770 
771  double ulw[2] = {0};
772  double *ul_xw = NULL;
773  double *ul_yw = NULL;
774 
775  double gridw[2] = {0};
776  double *grid_xw = NULL;
777  double *grid_yw = NULL;
778 
779  double skew[2] = {0};
780  double *skew_x = NULL;
781  double *skew_y = NULL;
782 
783  char **options = NULL;
784  int options_len = 0;
785 
786  uint32_t num_bands = 0;
787 
788  int srid = SRID_UNKNOWN;
789  char *srs = NULL;
790 
791  POSTGIS_RT_DEBUG(3, "RASTER_asRaster: Starting");
792 
793  /* based upon LWGEOM_asBinary function in postgis/lwgeom_ogc.c */
794 
795  /* Get the geometry */
796  if (PG_ARGISNULL(0))
797  PG_RETURN_NULL();
798 
799  gser = PG_GETARG_GSERIALIZED_P(0);
800  geom = lwgeom_from_gserialized(gser);
801 
802  /* Get a 2D version of the geometry if necessary */
803  if (lwgeom_ndims(geom) > 2) {
804  LWGEOM *geom2d = lwgeom_force_2d(geom);
805  lwgeom_free(geom);
806  geom = geom2d;
807  }
808 
809  /* empty geometry, return empty raster */
810  if (lwgeom_is_empty(geom)) {
811  POSTGIS_RT_DEBUG(3, "Input geometry is empty. Returning empty raster");
812  lwgeom_free(geom);
813  PG_FREE_IF_COPY(gser, 0);
814 
815  rast = rt_raster_new(0, 0);
816  if (rast == NULL)
817  PG_RETURN_NULL();
818 
819  pgrast = rt_raster_serialize(rast);
821 
822  if (NULL == pgrast)
823  PG_RETURN_NULL();
824 
825  SET_VARSIZE(pgrast, pgrast->size);
826  PG_RETURN_POINTER(pgrast);
827  }
828 
829  /* scale x */
830  if (!PG_ARGISNULL(1)) {
831  scale[0] = PG_GETARG_FLOAT8(1);
832  if (FLT_NEQ(scale[0], 0)) scale_x = &scale[0];
833  }
834 
835  /* scale y */
836  if (!PG_ARGISNULL(2)) {
837  scale[1] = PG_GETARG_FLOAT8(2);
838  if (FLT_NEQ(scale[1], 0)) scale_y = &scale[1];
839  }
840  POSTGIS_RT_DEBUGF(3, "RASTER_asRaster: scale (x, y) = %f, %f", scale[0], scale[1]);
841 
842  /* width */
843  if (!PG_ARGISNULL(3)) {
844  dim[0] = PG_GETARG_INT32(3);
845  if (dim[0] < 0) dim[0] = 0;
846  if (dim[0] != 0) dim_x = &dim[0];
847  }
848 
849  /* height */
850  if (!PG_ARGISNULL(4)) {
851  dim[1] = PG_GETARG_INT32(4);
852  if (dim[1] < 0) dim[1] = 0;
853  if (dim[1] != 0) dim_y = &dim[1];
854  }
855  POSTGIS_RT_DEBUGF(3, "RASTER_asRaster: dim (x, y) = %d, %d", dim[0], dim[1]);
856 
857  /* pixeltype */
858  if (!PG_ARGISNULL(5)) {
859  array = PG_GETARG_ARRAYTYPE_P(5);
860  etype = ARR_ELEMTYPE(array);
861  get_typlenbyvalalign(etype, &typlen, &typbyval, &typalign);
862 
863  switch (etype) {
864  case TEXTOID:
865  break;
866  default:
867 
868  lwgeom_free(geom);
869  PG_FREE_IF_COPY(gser, 0);
870 
871  elog(ERROR, "RASTER_asRaster: Invalid data type for pixeltype");
872  PG_RETURN_NULL();
873  break;
874  }
875 
876  deconstruct_array(array, etype, typlen, typbyval, typalign, &e,
877  &nulls, &n);
878 
879  if (n) {
880  pixtypes = (rt_pixtype *) palloc(sizeof(rt_pixtype) * n);
881  /* clean each pixeltype */
882  for (i = 0, j = 0; i < n; i++) {
883  if (nulls[i]) {
884  pixtypes[j++] = PT_64BF;
885  continue;
886  }
887 
888  pixeltype = NULL;
889  switch (etype) {
890  case TEXTOID:
891  pixeltypetext = (text *) DatumGetPointer(e[i]);
892  if (NULL == pixeltypetext) break;
893  pixeltype = text_to_cstring(pixeltypetext);
894 
895  /* trim string */
896  pixeltype = rtpg_trim(pixeltype);
897  POSTGIS_RT_DEBUGF(3, "RASTER_asRaster: pixeltype is '%s'", pixeltype);
898  break;
899  }
900 
901  if (strlen(pixeltype)) {
902  pixtype = rt_pixtype_index_from_name(pixeltype);
903  if (pixtype == PT_END) {
904 
905  pfree(pixtypes);
906 
907  lwgeom_free(geom);
908  PG_FREE_IF_COPY(gser, 0);
909 
910  elog(ERROR, "RASTER_asRaster: Invalid pixel type provided: %s", pixeltype);
911  PG_RETURN_NULL();
912  }
913 
914  pixtypes[j] = pixtype;
915  j++;
916  }
917  }
918 
919  if (j > 0) {
920  /* trim allocation */
921  pixtypes = repalloc(pixtypes, j * sizeof(rt_pixtype));
922  pixtypes_len = j;
923  }
924  else {
925  pfree(pixtypes);
926  pixtypes = NULL;
927  pixtypes_len = 0;
928  }
929  }
930  }
931 #if POSTGIS_DEBUG_LEVEL > 0
932  for (i = 0; i < pixtypes_len; i++)
933  POSTGIS_RT_DEBUGF(3, "RASTER_asRaster: pixtypes[%d] = %d", i, (int) pixtypes[i]);
934 #endif
935 
936  /* value */
937  if (!PG_ARGISNULL(6)) {
938  array = PG_GETARG_ARRAYTYPE_P(6);
939  etype = ARR_ELEMTYPE(array);
940  get_typlenbyvalalign(etype, &typlen, &typbyval, &typalign);
941 
942  switch (etype) {
943  case FLOAT4OID:
944  case FLOAT8OID:
945  break;
946  default:
947 
948  if (pixtypes_len) pfree(pixtypes);
949 
950  lwgeom_free(geom);
951  PG_FREE_IF_COPY(gser, 0);
952 
953  elog(ERROR, "RASTER_asRaster: Invalid data type for value");
954  PG_RETURN_NULL();
955  break;
956  }
957 
958  deconstruct_array(array, etype, typlen, typbyval, typalign, &e,
959  &nulls, &n);
960 
961  if (n) {
962  values = (double *) palloc(sizeof(double) * n);
963  for (i = 0, j = 0; i < n; i++) {
964  if (nulls[i]) {
965  values[j++] = 1;
966  continue;
967  }
968 
969  switch (etype) {
970  case FLOAT4OID:
971  values[j] = (double) DatumGetFloat4(e[i]);
972  break;
973  case FLOAT8OID:
974  values[j] = (double) DatumGetFloat8(e[i]);
975  break;
976  }
977  POSTGIS_RT_DEBUGF(3, "RASTER_asRaster: values[%d] = %f", j, values[j]);
978 
979  j++;
980  }
981 
982  if (j > 0) {
983  /* trim allocation */
984  values = repalloc(values, j * sizeof(double));
985  values_len = j;
986  }
987  else {
988  pfree(values);
989  values = NULL;
990  values_len = 0;
991  }
992  }
993  }
994 #if POSTGIS_DEBUG_LEVEL > 0
995  for (i = 0; i < values_len; i++)
996  POSTGIS_RT_DEBUGF(3, "RASTER_asRaster: values[%d] = %f", i, values[i]);
997 #endif
998 
999  /* nodataval */
1000  if (!PG_ARGISNULL(7)) {
1001  array = PG_GETARG_ARRAYTYPE_P(7);
1002  etype = ARR_ELEMTYPE(array);
1003  get_typlenbyvalalign(etype, &typlen, &typbyval, &typalign);
1004 
1005  switch (etype) {
1006  case FLOAT4OID:
1007  case FLOAT8OID:
1008  break;
1009  default:
1010 
1011  if (pixtypes_len) pfree(pixtypes);
1012  if (values_len) pfree(values);
1013 
1014  lwgeom_free(geom);
1015  PG_FREE_IF_COPY(gser, 0);
1016 
1017  elog(ERROR, "RASTER_asRaster: Invalid data type for nodataval");
1018  PG_RETURN_NULL();
1019  break;
1020  }
1021 
1022  deconstruct_array(array, etype, typlen, typbyval, typalign, &e,
1023  &nulls, &n);
1024 
1025  if (n) {
1026  nodatavals = (double *) palloc(sizeof(double) * n);
1027  hasnodatas = (uint8_t *) palloc(sizeof(uint8_t) * n);
1028  for (i = 0, j = 0; i < n; i++) {
1029  if (nulls[i]) {
1030  hasnodatas[j] = 0;
1031  nodatavals[j] = 0;
1032  j++;
1033  continue;
1034  }
1035 
1036  hasnodatas[j] = 1;
1037  switch (etype) {
1038  case FLOAT4OID:
1039  nodatavals[j] = (double) DatumGetFloat4(e[i]);
1040  break;
1041  case FLOAT8OID:
1042  nodatavals[j] = (double) DatumGetFloat8(e[i]);
1043  break;
1044  }
1045  POSTGIS_RT_DEBUGF(3, "RASTER_asRaster: hasnodatas[%d] = %d", j, hasnodatas[j]);
1046  POSTGIS_RT_DEBUGF(3, "RASTER_asRaster: nodatavals[%d] = %f", j, nodatavals[j]);
1047 
1048  j++;
1049  }
1050 
1051  if (j > 0) {
1052  /* trim allocation */
1053  nodatavals = repalloc(nodatavals, j * sizeof(double));
1054  hasnodatas = repalloc(hasnodatas, j * sizeof(uint8_t));
1055  nodatavals_len = j;
1056  }
1057  else {
1058  pfree(nodatavals);
1059  pfree(hasnodatas);
1060  nodatavals = NULL;
1061  hasnodatas = NULL;
1062  nodatavals_len = 0;
1063  }
1064  }
1065  }
1066 #if POSTGIS_DEBUG_LEVEL > 0
1067  for (i = 0; i < nodatavals_len; i++) {
1068  POSTGIS_RT_DEBUGF(3, "RASTER_asRaster: hasnodatas[%d] = %d", i, hasnodatas[i]);
1069  POSTGIS_RT_DEBUGF(3, "RASTER_asRaster: nodatavals[%d] = %f", i, nodatavals[i]);
1070  }
1071 #endif
1072 
1073  /* upperleftx */
1074  if (!PG_ARGISNULL(8)) {
1075  ulw[0] = PG_GETARG_FLOAT8(8);
1076  ul_xw = &ulw[0];
1077  }
1078 
1079  /* upperlefty */
1080  if (!PG_ARGISNULL(9)) {
1081  ulw[1] = PG_GETARG_FLOAT8(9);
1082  ul_yw = &ulw[1];
1083  }
1084  POSTGIS_RT_DEBUGF(3, "RASTER_asRaster: upperleft (x, y) = %f, %f", ulw[0], ulw[1]);
1085 
1086  /* gridx */
1087  if (!PG_ARGISNULL(10)) {
1088  gridw[0] = PG_GETARG_FLOAT8(10);
1089  grid_xw = &gridw[0];
1090  }
1091 
1092  /* gridy */
1093  if (!PG_ARGISNULL(11)) {
1094  gridw[1] = PG_GETARG_FLOAT8(11);
1095  grid_yw = &gridw[1];
1096  }
1097  POSTGIS_RT_DEBUGF(3, "RASTER_asRaster: grid (x, y) = %f, %f", gridw[0], gridw[1]);
1098 
1099  /* check dependent variables */
1100  haserr = 0;
1101  do {
1102  /* only part of scale provided */
1103  if (
1104  (scale_x == NULL && scale_y != NULL) ||
1105  (scale_x != NULL && scale_y == NULL)
1106  ) {
1107  elog(NOTICE, "Values must be provided for both X and Y of scale if one is specified");
1108  haserr = 1;
1109  break;
1110  }
1111 
1112  /* only part of dimension provided */
1113  if (
1114  (dim_x == NULL && dim_y != NULL) ||
1115  (dim_x != NULL && dim_y == NULL)
1116  ) {
1117  elog(NOTICE, "Values must be provided for both width and height if one is specified");
1118  haserr = 1;
1119  break;
1120  }
1121 
1122  /* scale and dimension provided */
1123  if (
1124  (scale_x != NULL && scale_y != NULL) &&
1125  (dim_x != NULL && dim_y != NULL)
1126  ) {
1127  elog(NOTICE, "Values provided for X and Y of scale and width and height. Using the width and height");
1128  scale_x = NULL;
1129  scale_y = NULL;
1130  break;
1131  }
1132 
1133  /* neither scale or dimension provided */
1134  if (
1135  (scale_x == NULL && scale_y == NULL) &&
1136  (dim_x == NULL && dim_y == NULL)
1137  ) {
1138  elog(NOTICE, "Values must be provided for X and Y of scale or width and height");
1139  haserr = 1;
1140  break;
1141  }
1142 
1143  /* only part of upper-left provided */
1144  if (
1145  (ul_xw == NULL && ul_yw != NULL) ||
1146  (ul_xw != NULL && ul_yw == NULL)
1147  ) {
1148  elog(NOTICE, "Values must be provided for both X and Y when specifying the upper-left corner");
1149  haserr = 1;
1150  break;
1151  }
1152 
1153  /* only part of alignment provided */
1154  if (
1155  (grid_xw == NULL && grid_yw != NULL) ||
1156  (grid_xw != NULL && grid_yw == NULL)
1157  ) {
1158  elog(NOTICE, "Values must be provided for both X and Y when specifying the alignment");
1159  haserr = 1;
1160  break;
1161  }
1162 
1163  /* upper-left and alignment provided */
1164  if (
1165  (ul_xw != NULL && ul_yw != NULL) &&
1166  (grid_xw != NULL && grid_yw != NULL)
1167  ) {
1168  elog(NOTICE, "Values provided for both X and Y of upper-left corner and alignment. Using the values of upper-left corner");
1169  grid_xw = NULL;
1170  grid_yw = NULL;
1171  break;
1172  }
1173  }
1174  while (0);
1175 
1176  if (haserr) {
1177  if (pixtypes_len) pfree(pixtypes);
1178  if (values_len) pfree(values);
1179  if (nodatavals_len) {
1180  pfree(nodatavals);
1181  pfree(hasnodatas);
1182  }
1183 
1184  lwgeom_free(geom);
1185  PG_FREE_IF_COPY(gser, 0);
1186 
1187  PG_RETURN_NULL();
1188  }
1189 
1190  /* skewx */
1191  if (!PG_ARGISNULL(12)) {
1192  skew[0] = PG_GETARG_FLOAT8(12);
1193  if (FLT_NEQ(skew[0], 0)) skew_x = &skew[0];
1194  }
1195 
1196  /* skewy */
1197  if (!PG_ARGISNULL(13)) {
1198  skew[1] = PG_GETARG_FLOAT8(13);
1199  if (FLT_NEQ(skew[1], 0)) skew_y = &skew[1];
1200  }
1201  POSTGIS_RT_DEBUGF(3, "RASTER_asRaster: skew (x, y) = %f, %f", skew[0], skew[1]);
1202 
1203  /* all touched */
1204  if (!PG_ARGISNULL(14) && PG_GETARG_BOOL(14) == TRUE) {
1205  if (options_len == 0) {
1206  options_len = 1;
1207  options = (char **) palloc(sizeof(char *) * options_len);
1208  }
1209  else {
1210  options_len++;
1211  options = (char **) repalloc(options, sizeof(char *) * options_len);
1212  }
1213 
1214  options[options_len - 1] = palloc(sizeof(char*) * (strlen("ALL_TOUCHED=TRUE") + 1));
1215  strcpy(options[options_len - 1], "ALL_TOUCHED=TRUE");
1216  }
1217 
1218  if (options_len) {
1219  options_len++;
1220  options = (char **) repalloc(options, sizeof(char *) * options_len);
1221  options[options_len - 1] = NULL;
1222  }
1223 
1224  /* get geometry's srid */
1225  srid = gserialized_get_srid(gser);
1226 
1227  POSTGIS_RT_DEBUGF(3, "RASTER_asRaster: srid = %d", srid);
1228  if (clamp_srid(srid) != SRID_UNKNOWN) {
1229  srs = rtpg_getSR(srid);
1230  if (NULL == srs) {
1231 
1232  if (pixtypes_len) pfree(pixtypes);
1233  if (values_len) pfree(values);
1234  if (nodatavals_len) {
1235  pfree(hasnodatas);
1236  pfree(nodatavals);
1237  }
1238  if (options_len) pfree(options);
1239 
1240  lwgeom_free(geom);
1241  PG_FREE_IF_COPY(gser, 0);
1242 
1243  elog(ERROR, "RASTER_asRaster: Could not find srtext for SRID (%d)", srid);
1244  PG_RETURN_NULL();
1245  }
1246  POSTGIS_RT_DEBUGF(3, "RASTER_asRaster: srs is %s", srs);
1247  }
1248  else
1249  srs = NULL;
1250 
1251  /* determine number of bands */
1252  /* MIN macro is from GDAL's cpl_port.h */
1253  num_bands = MIN(pixtypes_len, values_len);
1254  num_bands = MIN(num_bands, nodatavals_len);
1255  POSTGIS_RT_DEBUGF(3, "RASTER_asRaster: pixtypes_len = %d", pixtypes_len);
1256  POSTGIS_RT_DEBUGF(3, "RASTER_asRaster: values_len = %d", values_len);
1257  POSTGIS_RT_DEBUGF(3, "RASTER_asRaster: nodatavals_len = %d", nodatavals_len);
1258  POSTGIS_RT_DEBUGF(3, "RASTER_asRaster: num_bands = %d", num_bands);
1259 
1260  /* warn of imbalanced number of band elements */
1261  if (!(
1262  (pixtypes_len == values_len) &&
1263  (values_len == nodatavals_len)
1264  )) {
1265  elog(
1266  NOTICE,
1267  "Imbalanced number of values provided for pixeltype (%d), value (%d) and nodataval (%d). Using the first %d values of each parameter",
1268  pixtypes_len,
1269  values_len,
1270  nodatavals_len,
1271  num_bands
1272  );
1273  }
1274 
1275  /* get wkb of geometry */
1276  POSTGIS_RT_DEBUG(3, "RASTER_asRaster: getting wkb of geometry");
1277  wkb = lwgeom_to_wkb(geom, variant, &wkb_len);
1278  lwgeom_free(geom);
1279  PG_FREE_IF_COPY(gser, 0);
1280 
1281  /* rasterize geometry */
1282  POSTGIS_RT_DEBUG(3, "RASTER_asRaster: rasterizing geometry");
1283  /* use nodatavals for the init parameter */
1285  (uint32_t) wkb_len, srs,
1286  num_bands, pixtypes,
1287  nodatavals, values,
1288  nodatavals, hasnodatas,
1289  dim_x, dim_y,
1290  scale_x, scale_y,
1291  ul_xw, ul_yw,
1292  grid_xw, grid_yw,
1293  skew_x, skew_y,
1294  options
1295  );
1296 
1297  if (pixtypes_len) pfree(pixtypes);
1298  if (values_len) pfree(values);
1299  if (nodatavals_len) {
1300  pfree(hasnodatas);
1301  pfree(nodatavals);
1302  }
1303  if (options_len) pfree(options);
1304 
1305  if (!rast) {
1306  elog(ERROR, "RASTER_asRaster: Could not rasterize geometry");
1307  PG_RETURN_NULL();
1308  }
1309 
1310  /* add target srid */
1312 
1313  pgrast = rt_raster_serialize(rast);
1315 
1316  if (NULL == pgrast) PG_RETURN_NULL();
1317 
1318  POSTGIS_RT_DEBUG(3, "RASTER_asRaster: done");
1319 
1320  SET_VARSIZE(pgrast, pgrast->size);
1321  PG_RETURN_POINTER(pgrast);
1322 }
static uint8_t variant
Definition: cu_in_twkb.c:26
#define TRUE
Definition: dbfopen.c:169
#define FALSE
Definition: dbfopen.c:168
int32_t gserialized_get_srid(const GSERIALIZED *s)
Extract the SRID from the serialized form (it is packed into three bytes so this is a handy function)...
Definition: g_serialized.c:100
LWGEOM * lwgeom_from_gserialized(const GSERIALIZED *g)
Allocate a new LWGEOM from a GSERIALIZED.
GSERIALIZED * gserialized_from_lwgeom(LWGEOM *geom, size_t *size)
Allocate a new GSERIALIZED from an LWGEOM.
int lwgeom_ndims(const LWGEOM *geom)
Return the number of dimensions (2, 3, 4) in a geometry.
Definition: lwgeom.c:944
void lwgeom_free(LWGEOM *geom)
Definition: lwgeom.c:1144
void lwmpoly_free(LWMPOLY *mpoly)
Definition: lwmpoly.c:53
LWGEOM * lwpoly_as_lwgeom(const LWPOLY *obj)
Definition: lwgeom.c:320
uint8_t * lwgeom_to_wkb(const LWGEOM *geom, uint8_t variant, size_t *size_out)
Convert LWGEOM to a char* in WKB format.
Definition: lwout_wkb.c:764
LWGEOM * lwmpoly_as_lwgeom(const LWMPOLY *obj)
Definition: lwgeom.c:285
int clamp_srid(int srid)
Return a valid SRID from an arbitrary integer Raises a notice if what comes out is different from wha...
Definition: lwutil.c:347
int lwgeom_is_empty(const LWGEOM *geom)
Return true or false depending on whether a geometry is an "empty" geometry (no vertices members)
Definition: lwgeom.c:1393
void lwpoly_free(LWPOLY *poly)
Definition: lwpoly.c:175
#define SRID_UNKNOWN
Unknown SRID value.
Definition: liblwgeom.h:188
#define WKB_SFSQL
Definition: liblwgeom.h:2067
LWGEOM * lwgeom_force_2d(const LWGEOM *geom)
Strip out the Z/M components of an LWGEOM.
Definition: lwgeom.c:784
#define FLT_NEQ(x, y)
Definition: librtcore.h:2233
int rt_band_get_hasnodata_flag(rt_band band)
Get hasnodata flag value.
Definition: rt_band.c:674
rt_pixtype rt_pixtype_index_from_name(const char *pixname)
Definition: rt_pixel.c:80
rt_errorstate rt_band_get_pixel(rt_band band, int x, int y, double *value, int *nodata)
Get pixel value.
Definition: rt_band.c:1221
void rt_raster_destroy(rt_raster raster)
Release memory associated to a raster.
Definition: rt_raster.c:82
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
rt_pixtype
Definition: librtcore.h:185
@ PT_END
Definition: librtcore.h:197
@ PT_64BF
Definition: librtcore.h:196
int rt_band_get_isnodata_flag(rt_band band)
Get isnodata flag value.
Definition: rt_band.c:714
rt_errorstate rt_raster_surface(rt_raster raster, int nband, LWMPOLY **surface)
Get a raster as a surface (multipolygon).
Definition: rt_geometry.c:355
rt_raster rt_raster_new(uint32_t width, uint32_t height)
Construct a raster with given dimensions.
Definition: rt_raster.c:48
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:1347
void * rt_raster_serialize(rt_raster raster)
Return this raster in serialized form.
Definition: rt_serialize.c:521
rt_geomval rt_raster_gdal_polygonize(rt_raster raster, int nband, int exclude_nodata_value, int *pnElements)
Returns a set of "geomval" value, one for each group of pixel sharing the same value for the provided...
Definition: rt_geometry.c:940
@ ES_NONE
Definition: librtcore.h:180
rt_raster rt_raster_gdal_rasterize(const unsigned char *wkb, uint32_t wkb_len, const char *srs, uint32_t num_bands, rt_pixtype *pixtype, double *init, double *value, double *nodata, uint8_t *hasnodata, int *width, int *height, double *scale_x, double *scale_y, double *ul_xw, double *ul_yw, double *grid_xw, double *grid_yw, double *skew_x, double *skew_y, char **options)
Return a raster of the provided geometry.
Definition: rt_raster.c:2509
void rt_band_destroy(rt_band band)
Destroy a raster band.
Definition: rt_band.c:340
uint16_t rt_raster_get_num_bands(rt_raster raster)
Definition: rt_raster.c:372
rt_errorstate rt_raster_get_convex_hull(rt_raster raster, LWGEOM **hull)
Get raster's convex hull.
Definition: rt_geometry.c:803
uint16_t rt_raster_get_height(rt_raster raster)
Definition: rt_raster.c:129
void rt_raster_set_srid(rt_raster raster, int32_t srid)
Set raster's SRID.
Definition: rt_raster.c:363
uint16_t rt_raster_get_width(rt_raster raster)
Definition: rt_raster.c:121
rt_errorstate rt_raster_get_envelope_geom(rt_raster raster, LWGEOM **env)
Get raster's envelope as a geometry.
Definition: rt_geometry.c:670
rt_errorstate rt_raster_get_perimeter(rt_raster raster, int nband, LWGEOM **perimeter)
Get raster perimeter.
Definition: rt_geometry.c:182
rt_raster rt_raster_deserialize(void *serialized, int header_only)
Return a raster from a serialized form.
Definition: rt_serialize.c:725
int rt_raster_is_empty(rt_raster raster)
Return TRUE if the raster is empty.
Definition: rt_raster.c:1334
rt_band rt_raster_get_band(rt_raster raster, int bandNum)
Return Nth band, or NULL if unavailable.
Definition: rt_raster.c:381
int value
Definition: genraster.py:61
band
Definition: ovdump.py:57
nband
Definition: pixval.py:52
raster
Be careful!! Zeros function's input parameter can be a (height x width) array, not (width x height): ...
Definition: rtrowdump.py:121
char * text_to_cstring(const text *textptr)
GSERIALIZED * geometry_serialize(LWGEOM *lwgeom)
Datum RASTER_dumpAsPolygons(PG_FUNCTION_ARGS)
Datum RASTER_getPolygon(PG_FUNCTION_ARGS)
Datum RASTER_convex_hull(PG_FUNCTION_ARGS)
Datum RASTER_envelope(PG_FUNCTION_ARGS)
Definition: rtpg_geometry.c:66
Datum RASTER_asRaster(PG_FUNCTION_ARGS)
PG_FUNCTION_INFO_V1(RASTER_envelope)
#define VALUES_LENGTH
Datum RASTER_getPixelPolygons(PG_FUNCTION_ARGS)
char * rtpg_getSR(int srid)
char * rtpg_trim(const char *input)
#define POSTGIS_RT_DEBUG(level, msg)
Definition: rtpostgis.h:61
#define POSTGIS_RT_DEBUGF(level, msg,...)
Definition: rtpostgis.h:65
#define MIN(a, b)
Definition: shpopen.c:283
LWGEOM * geom
Definition: librtcore.h:2340
double value
Definition: librtcore.h:2338
uint8_t nodata
Definition: librtcore.h:2337
Struct definitions.
Definition: librtcore.h:2250
unsigned int uint32_t
Definition: uthash.h:78
unsigned char uint8_t
Definition: uthash.h:79