PostGIS  3.1.6dev-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 #include "access/htup_details.h" /* for heap_form_tuple() */
41 #include "lwgeom_pg.h"
42 
43 #include "rtpostgis.h"
44 #include "rtpg_internal.h"
45 
46 Datum RASTER_envelope(PG_FUNCTION_ARGS);
47 Datum RASTER_convex_hull(PG_FUNCTION_ARGS);
48 Datum RASTER_dumpAsPolygons(PG_FUNCTION_ARGS);
49 
50 /* Get pixel geographical shape */
51 Datum RASTER_getPixelPolygons(PG_FUNCTION_ARGS);
52 
53 /* Get raster band's polygon */
54 Datum RASTER_getPolygon(PG_FUNCTION_ARGS);
55 
56 /* rasterize a geometry */
57 Datum RASTER_asRaster(PG_FUNCTION_ARGS);
58 
59 /* ---------------------------------------------------------------- */
60 /* Raster envelope */
61 /* ---------------------------------------------------------------- */
63 Datum RASTER_envelope(PG_FUNCTION_ARGS)
64 {
65  rt_pgraster *pgraster;
67  LWGEOM *geom = NULL;
68  GSERIALIZED* gser = NULL;
69  size_t gser_size;
70  int err = ES_NONE;
71 
72  if (PG_ARGISNULL(0))
73  PG_RETURN_NULL();
74 
75  pgraster = (rt_pgraster *) PG_DETOAST_DATUM_SLICE(
76  PG_GETARG_DATUM(0),
77  0,
78  sizeof(struct rt_raster_serialized_t)
79  );
80  raster = rt_raster_deserialize(pgraster, TRUE);
81 
82  if (!raster) {
83  PG_FREE_IF_COPY(pgraster, 0);
84  elog(ERROR, "RASTER_envelope: Could not deserialize raster");
85  PG_RETURN_NULL();
86  }
87 
88  err = rt_raster_get_envelope_geom(raster, &geom);
89 
91  PG_FREE_IF_COPY(pgraster, 0);
92 
93  if (err != ES_NONE) {
94  elog(ERROR, "RASTER_envelope: Could not get raster's envelope");
95  PG_RETURN_NULL();
96  }
97  else if (geom == NULL) {
98  elog(NOTICE, "Raster's envelope is NULL");
99  PG_RETURN_NULL();
100  }
101 
102  gser = gserialized_from_lwgeom(geom, &gser_size);
103  lwgeom_free(geom);
104 
105  SET_VARSIZE(gser, gser_size);
106  PG_RETURN_POINTER(gser);
107 }
108 
112 /* ---------------------------------------------------------------- */
113 /* Raster convex hull */
114 /* ---------------------------------------------------------------- */
116 Datum RASTER_convex_hull(PG_FUNCTION_ARGS)
117 {
118  rt_pgraster *pgraster;
120  LWGEOM *geom = NULL;
121  GSERIALIZED* gser = NULL;
122  size_t gser_size;
123  int err = ES_NONE;
124 
125  bool minhull = FALSE;
126 
127  if (PG_ARGISNULL(0))
128  PG_RETURN_NULL();
129 
130  /* # of args */
131  if (PG_NARGS() > 1)
132  minhull = TRUE;
133 
134  if (!minhull) {
135  pgraster = (rt_pgraster *) PG_DETOAST_DATUM_SLICE(PG_GETARG_DATUM(0), 0, sizeof(struct rt_raster_serialized_t));
136  raster = rt_raster_deserialize(pgraster, TRUE);
137  }
138  else {
139  pgraster = (rt_pgraster *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
140  raster = rt_raster_deserialize(pgraster, FALSE);
141  }
142 
143  if (!raster) {
144  PG_FREE_IF_COPY(pgraster, 0);
145  elog(ERROR, "RASTER_convex_hull: Could not deserialize raster");
146  PG_RETURN_NULL();
147  }
148 
149  if (!minhull)
150  err = rt_raster_get_convex_hull(raster, &geom);
151  else {
152  int nband = -1;
153 
154  /* get arg 1 */
155  if (!PG_ARGISNULL(1)) {
156  nband = PG_GETARG_INT32(1);
157  if (!rt_raster_has_band(raster, nband - 1)) {
158  elog(NOTICE, "Invalid band index (must use 1-based). Returning NULL");
160  PG_FREE_IF_COPY(pgraster, 0);
161  PG_RETURN_NULL();
162  }
163  nband = nband - 1;
164  }
165 
166  err = rt_raster_get_perimeter(raster, nband, &geom);
167  }
168 
170  PG_FREE_IF_COPY(pgraster, 0);
171 
172  if (err != ES_NONE) {
173  elog(ERROR, "RASTER_convex_hull: Could not get raster's convex hull");
174  PG_RETURN_NULL();
175  }
176  else if (geom == NULL) {
177  elog(NOTICE, "Raster's convex hull is NULL");
178  PG_RETURN_NULL();
179  }
180 
181  gser = gserialized_from_lwgeom(geom, &gser_size);
182  lwgeom_free(geom);
183 
184  SET_VARSIZE(gser, gser_size);
185  PG_RETURN_POINTER(gser);
186 }
187 
188 #define VALUES_LENGTH 2
189 
191 Datum RASTER_dumpAsPolygons(PG_FUNCTION_ARGS) {
192  FuncCallContext *funcctx;
193  TupleDesc tupdesc;
194  rt_geomval geomval;
195  rt_geomval geomval2;
196  int call_cntr;
197  int max_calls;
198 
199  /* stuff done only on the first call of the function */
200  if (SRF_IS_FIRSTCALL()) {
201  MemoryContext oldcontext;
202  int numbands;
203  rt_pgraster *pgraster = NULL;
204  rt_raster raster = NULL;
205  int nband;
206  bool exclude_nodata_value = TRUE;
207  int nElements;
208 
209  POSTGIS_RT_DEBUG(2, "RASTER_dumpAsPolygons first call");
210 
211  /* create a function context for cross-call persistence */
212  funcctx = SRF_FIRSTCALL_INIT();
213 
214  /* switch to memory context appropriate for multiple function calls */
215  oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
216 
217  /* Get input arguments */
218  if (PG_ARGISNULL(0)) {
219  MemoryContextSwitchTo(oldcontext);
220  SRF_RETURN_DONE(funcctx);
221  }
222  pgraster = (rt_pgraster *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
223  raster = rt_raster_deserialize(pgraster, FALSE);
224  if (!raster) {
225  PG_FREE_IF_COPY(pgraster, 0);
226  ereport(ERROR, (
227  errcode(ERRCODE_OUT_OF_MEMORY),
228  errmsg("Could not deserialize raster")
229  ));
230  MemoryContextSwitchTo(oldcontext);
231  SRF_RETURN_DONE(funcctx);
232  }
233 
234  if (!PG_ARGISNULL(1))
235  nband = PG_GETARG_UINT32(1);
236  else
237  nband = 1; /* By default, first band */
238 
239  POSTGIS_RT_DEBUGF(3, "band %d", nband);
240  numbands = rt_raster_get_num_bands(raster);
241 
242  if (nband < 1 || nband > numbands) {
243  elog(NOTICE, "Invalid band index (must use 1-based). Returning NULL");
245  PG_FREE_IF_COPY(pgraster, 0);
246  MemoryContextSwitchTo(oldcontext);
247  SRF_RETURN_DONE(funcctx);
248  }
249 
250  if (!PG_ARGISNULL(2))
251  exclude_nodata_value = PG_GETARG_BOOL(2);
252 
253  /* see if band is NODATA */
255  POSTGIS_RT_DEBUGF(3, "Band at index %d is NODATA. Returning NULL", nband);
257  PG_FREE_IF_COPY(pgraster, 0);
258  MemoryContextSwitchTo(oldcontext);
259  SRF_RETURN_DONE(funcctx);
260  }
261 
262  /* Polygonize raster */
263 
267  geomval = rt_raster_gdal_polygonize(raster, nband - 1, exclude_nodata_value, &nElements);
269  PG_FREE_IF_COPY(pgraster, 0);
270  if (NULL == geomval) {
271  ereport(ERROR, (
272  errcode(ERRCODE_NO_DATA_FOUND),
273  errmsg("Could not polygonize raster")
274  ));
275  MemoryContextSwitchTo(oldcontext);
276  SRF_RETURN_DONE(funcctx);
277  }
278 
279  POSTGIS_RT_DEBUGF(3, "raster dump, %d elements returned", nElements);
280 
281  /* Store needed information */
282  funcctx->user_fctx = geomval;
283 
284  /* total number of tuples to be returned */
285  funcctx->max_calls = nElements;
286 
287  /* Build a tuple descriptor for our result type */
288  if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) {
289  ereport(ERROR, (
290  errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
291  errmsg("function returning record called in context that cannot accept type record")
292  ));
293  }
294 
295  BlessTupleDesc(tupdesc);
296  funcctx->tuple_desc = tupdesc;
297 
298  MemoryContextSwitchTo(oldcontext);
299  }
300 
301  /* stuff done on every call of the function */
302  funcctx = SRF_PERCALL_SETUP();
303 
304  call_cntr = funcctx->call_cntr;
305  max_calls = funcctx->max_calls;
306  tupdesc = funcctx->tuple_desc;
307  geomval2 = funcctx->user_fctx;
308 
309  /* do when there is more left to send */
310  if (call_cntr < max_calls) {
311  Datum values[VALUES_LENGTH];
312  bool nulls[VALUES_LENGTH];
313  HeapTuple tuple;
314  Datum result;
315 
316  GSERIALIZED *gser = NULL;
317  size_t gser_size = 0;
318 
319  POSTGIS_RT_DEBUGF(3, "call number %d", call_cntr);
320 
321  memset(nulls, FALSE, sizeof(bool) * VALUES_LENGTH);
322 
323  /* convert LWGEOM to GSERIALIZED */
324  gser = gserialized_from_lwgeom(lwpoly_as_lwgeom(geomval2[call_cntr].geom), &gser_size);
325  lwgeom_free(lwpoly_as_lwgeom(geomval2[call_cntr].geom));
326 
327  values[0] = PointerGetDatum(gser);
328  values[1] = Float8GetDatum(geomval2[call_cntr].val);
329 
330  /* build a tuple */
331  tuple = heap_form_tuple(tupdesc, values, nulls);
332 
333  /* make the tuple into a datum */
334  result = HeapTupleGetDatum(tuple);
335 
336  SRF_RETURN_NEXT(funcctx, result);
337  }
338  /* do when there is no more left */
339  else {
340  pfree(geomval2);
341  SRF_RETURN_DONE(funcctx);
342  }
343 }
344 
345 #undef VALUES_LENGTH
346 #define VALUES_LENGTH 4
347 
352 Datum RASTER_getPixelPolygons(PG_FUNCTION_ARGS)
353 {
354  FuncCallContext *funcctx;
355  TupleDesc tupdesc;
356  rt_pixel pix = NULL;
357  rt_pixel pix2;
358  int call_cntr;
359  int max_calls;
360  int i = 0;
361 
362  /* stuff done only on the first call of the function */
363  if (SRF_IS_FIRSTCALL()) {
364  MemoryContext oldcontext;
365  rt_pgraster *pgraster = NULL;
366  rt_raster raster = NULL;
367  rt_band band = NULL;
368  int nband = 1;
369  int numbands;
370  bool hasband = TRUE;
371  bool exclude_nodata_value = TRUE;
372  bool nocolumnx = FALSE;
373  bool norowy = FALSE;
374  int x = 0;
375  int y = 0;
376  int bounds[4] = {0};
377  int pixcount = 0;
378  double value = 0;
379  int isnodata = 0;
380 
381  LWPOLY *poly;
382 
383  POSTGIS_RT_DEBUG(3, "RASTER_getPixelPolygons first call");
384 
385  /* create a function context for cross-call persistence */
386  funcctx = SRF_FIRSTCALL_INIT();
387 
388  /* switch to memory context appropriate for multiple function calls */
389  oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
390 
391  if (PG_ARGISNULL(0)) {
392  MemoryContextSwitchTo(oldcontext);
393  SRF_RETURN_DONE(funcctx);
394  }
395  pgraster = (rt_pgraster *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
396 
397  /* band */
398  if (PG_ARGISNULL(1))
399  hasband = FALSE;
400  else {
401  nband = PG_GETARG_INT32(1);
402  hasband = TRUE;
403  }
404 
405  /* column */
406  if (PG_ARGISNULL(2))
407  nocolumnx = TRUE;
408  else {
409  bounds[0] = PG_GETARG_INT32(2);
410  bounds[1] = bounds[0];
411  }
412 
413  /* row */
414  if (PG_ARGISNULL(3))
415  norowy = TRUE;
416  else {
417  bounds[2] = PG_GETARG_INT32(3);
418  bounds[3] = bounds[2];
419  }
420 
421  /* exclude NODATA */
422  if (!PG_ARGISNULL(4))
423  exclude_nodata_value = PG_GETARG_BOOL(4);
424 
425  raster = rt_raster_deserialize(pgraster, FALSE);
426  if (!raster) {
427  PG_FREE_IF_COPY(pgraster, 0);
428  ereport(ERROR, (
429  errcode(ERRCODE_OUT_OF_MEMORY),
430  errmsg("Could not deserialize raster")
431  ));
432  MemoryContextSwitchTo(oldcontext);
433  SRF_RETURN_DONE(funcctx);
434  }
435 
436  /* raster empty, return NULL */
437  if (rt_raster_is_empty(raster)) {
438  elog(NOTICE, "Raster is empty. Returning NULL");
440  PG_FREE_IF_COPY(pgraster, 0);
441  MemoryContextSwitchTo(oldcontext);
442  SRF_RETURN_DONE(funcctx);
443  }
444 
445  /* band specified, load band and info */
446  if (hasband) {
447  numbands = rt_raster_get_num_bands(raster);
448  POSTGIS_RT_DEBUGF(3, "band %d", nband);
449  POSTGIS_RT_DEBUGF(3, "# of bands %d", numbands);
450 
451  if (nband < 1 || nband > numbands) {
452  elog(NOTICE, "Invalid band index (must use 1-based). Returning NULL");
454  PG_FREE_IF_COPY(pgraster, 0);
455  MemoryContextSwitchTo(oldcontext);
456  SRF_RETURN_DONE(funcctx);
457  }
458 
460  if (!band) {
461  elog(NOTICE, "Could not find band at index %d. Returning NULL", nband);
463  PG_FREE_IF_COPY(pgraster, 0);
464  MemoryContextSwitchTo(oldcontext);
465  SRF_RETURN_DONE(funcctx);
466  }
467 
469  exclude_nodata_value = FALSE;
470  }
471 
472  /* set bounds if columnx, rowy not set */
473  if (nocolumnx) {
474  bounds[0] = 1;
475  bounds[1] = rt_raster_get_width(raster);
476  }
477  if (norowy) {
478  bounds[2] = 1;
479  bounds[3] = rt_raster_get_height(raster);
480  }
481  POSTGIS_RT_DEBUGF(3, "bounds (min x, max x, min y, max y) = (%d, %d, %d, %d)",
482  bounds[0], bounds[1], bounds[2], bounds[3]);
483 
484  /* rowy */
485  pixcount = 0;
486  for (y = bounds[2]; y <= bounds[3]; y++) {
487  /* columnx */
488  for (x = bounds[0]; x <= bounds[1]; x++) {
489 
490  value = 0;
491  isnodata = TRUE;
492 
493  if (hasband) {
494  if (rt_band_get_pixel(band, x - 1, y - 1, &value, &isnodata) != ES_NONE) {
495 
496  for (i = 0; i < pixcount; i++)
497  lwgeom_free(pix[i].geom);
498  if (pixcount) pfree(pix);
499 
502  PG_FREE_IF_COPY(pgraster, 0);
503 
504  MemoryContextSwitchTo(oldcontext);
505  elog(ERROR, "RASTER_getPixelPolygons: Could not get pixel value");
506  SRF_RETURN_DONE(funcctx);
507  }
508 
509  /* don't continue if pixel is NODATA and to exclude NODATA */
510  if (isnodata && exclude_nodata_value) {
511  POSTGIS_RT_DEBUG(5, "pixel value is NODATA and exclude_nodata_value = TRUE");
512  continue;
513  }
514  }
515 
516  /* geometry */
517  poly = rt_raster_pixel_as_polygon(raster, x - 1, y - 1);
518  if (!poly) {
519  for (i = 0; i < pixcount; i++)
520  lwgeom_free(pix[i].geom);
521  if (pixcount) pfree(pix);
522 
523  if (hasband) rt_band_destroy(band);
525  PG_FREE_IF_COPY(pgraster, 0);
526 
527  MemoryContextSwitchTo(oldcontext);
528  elog(ERROR, "RASTER_getPixelPolygons: Could not get pixel polygon");
529  SRF_RETURN_DONE(funcctx);
530  }
531 
532  if (!pixcount)
533  pix = palloc(sizeof(struct rt_pixel_t) * (pixcount + 1));
534  else
535  pix = repalloc(pix, sizeof(struct rt_pixel_t) * (pixcount + 1));
536  if (pix == NULL) {
537 
538  lwpoly_free(poly);
539  if (hasband) rt_band_destroy(band);
541  PG_FREE_IF_COPY(pgraster, 0);
542 
543  MemoryContextSwitchTo(oldcontext);
544  elog(ERROR, "RASTER_getPixelPolygons: Could not allocate memory for storing pixel polygons");
545  SRF_RETURN_DONE(funcctx);
546  }
547  pix[pixcount].geom = (LWGEOM *) poly;
548  POSTGIS_RT_DEBUGF(5, "poly @ %p", poly);
549  POSTGIS_RT_DEBUGF(5, "geom @ %p", pix[pixcount].geom);
550 
551  /* x, y */
552  pix[pixcount].x = x;
553  pix[pixcount].y = y;
554 
555  /* value */
556  pix[pixcount].value = value;
557 
558  /* NODATA */
559  if (hasband) {
560  if (exclude_nodata_value)
561  pix[pixcount].nodata = isnodata;
562  else
563  pix[pixcount].nodata = FALSE;
564  }
565  else {
566  pix[pixcount].nodata = isnodata;
567  }
568 
569  pixcount++;
570  }
571  }
572 
573  if (hasband) rt_band_destroy(band);
575  PG_FREE_IF_COPY(pgraster, 0);
576 
577  /* shortcut if no pixcount */
578  if (pixcount < 1) {
579  elog(NOTICE, "No pixels found for band %d", nband);
580  MemoryContextSwitchTo(oldcontext);
581  SRF_RETURN_DONE(funcctx);
582  }
583 
584  /* Store needed information */
585  funcctx->user_fctx = pix;
586 
587  /* total number of tuples to be returned */
588  funcctx->max_calls = pixcount;
589  POSTGIS_RT_DEBUGF(3, "pixcount = %d", pixcount);
590 
591  /* Build a tuple descriptor for our result type */
592  if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) {
593  ereport(ERROR, (
594  errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
595  errmsg("function returning record called in context that cannot accept type record")
596  ));
597  }
598 
599  BlessTupleDesc(tupdesc);
600  funcctx->tuple_desc = tupdesc;
601 
602  MemoryContextSwitchTo(oldcontext);
603  }
604 
605  /* stuff done on every call of the function */
606  funcctx = SRF_PERCALL_SETUP();
607 
608  call_cntr = funcctx->call_cntr;
609  max_calls = funcctx->max_calls;
610  tupdesc = funcctx->tuple_desc;
611  pix2 = funcctx->user_fctx;
612 
613  /* do when there is more left to send */
614  if (call_cntr < max_calls) {
615  Datum values[VALUES_LENGTH];
616  bool nulls[VALUES_LENGTH];
617  HeapTuple tuple;
618  Datum result;
619 
620  GSERIALIZED *gser = NULL;
621  size_t gser_size = 0;
622 
623  POSTGIS_RT_DEBUGF(3, "call number %d", call_cntr);
624 
625  memset(nulls, FALSE, sizeof(bool) * VALUES_LENGTH);
626 
627  /* convert LWGEOM to GSERIALIZED */
628  gser = gserialized_from_lwgeom(pix2[call_cntr].geom, &gser_size);
629  lwgeom_free(pix2[call_cntr].geom);
630 
631  values[0] = PointerGetDatum(gser);
632  if (pix2[call_cntr].nodata)
633  nulls[1] = TRUE;
634  else
635  values[1] = Float8GetDatum(pix2[call_cntr].value);
636  values[2] = Int32GetDatum(pix2[call_cntr].x);
637  values[3] = Int32GetDatum(pix2[call_cntr].y);
638 
639  /* build a tuple */
640  tuple = heap_form_tuple(tupdesc, values, nulls);
641 
642  /* make the tuple into a datum */
643  result = HeapTupleGetDatum(tuple);
644 
645  SRF_RETURN_NEXT(funcctx, result);
646  }
647  /* do when there is no more left */
648  else {
649  pfree(pix2);
650  SRF_RETURN_DONE(funcctx);
651  }
652 }
653 
658 Datum RASTER_getPolygon(PG_FUNCTION_ARGS)
659 {
660  rt_pgraster *pgraster = NULL;
661  rt_raster raster = NULL;
662  int num_bands = 0;
663  int nband = 1;
664  int err;
665  LWMPOLY *surface = NULL;
666  GSERIALIZED *rtn = NULL;
667 
668  /* raster */
669  if (PG_ARGISNULL(0))
670  PG_RETURN_NULL();
671  pgraster = (rt_pgraster *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
672 
673  raster = rt_raster_deserialize(pgraster, FALSE);
674  if (!raster) {
675  PG_FREE_IF_COPY(pgraster, 0);
676  elog(ERROR, "RASTER_getPolygon: Could not deserialize raster");
677  PG_RETURN_NULL();
678  }
679 
680  /* num_bands */
681  num_bands = rt_raster_get_num_bands(raster);
682  if (num_bands < 1) {
683  elog(NOTICE, "Raster provided has no bands");
685  PG_FREE_IF_COPY(pgraster, 0);
686  PG_RETURN_NULL();
687  }
688 
689  /* band index is 1-based */
690  if (!PG_ARGISNULL(1))
691  nband = PG_GETARG_INT32(1);
692  if (nband < 1 || nband > num_bands) {
693  elog(NOTICE, "Invalid band index (must use 1-based). Returning NULL");
695  PG_FREE_IF_COPY(pgraster, 0);
696  PG_RETURN_NULL();
697  }
698 
699  /* get band surface */
700  err = rt_raster_surface(raster, nband - 1, &surface);
702  PG_FREE_IF_COPY(pgraster, 0);
703 
704  if (err != ES_NONE) {
705  elog(ERROR, "RASTER_getPolygon: Could not get raster band's surface");
706  PG_RETURN_NULL();
707  }
708  else if (surface == NULL) {
709  elog(NOTICE, "Raster is empty or all pixels of band are NODATA. Returning NULL");
710  PG_RETURN_NULL();
711  }
712 
713  rtn = geometry_serialize(lwmpoly_as_lwgeom(surface));
714  lwmpoly_free(surface);
715 
716  PG_RETURN_POINTER(rtn);
717 }
718 
723 Datum RASTER_asRaster(PG_FUNCTION_ARGS)
724 {
725  GSERIALIZED *gser = NULL;
726 
727  LWGEOM *geom = NULL;
728  rt_raster rast = NULL;
729  rt_pgraster *pgrast = NULL;
730 
731  lwvarlena_t *wkb;
732  unsigned char variant = WKB_SFSQL;
733 
734  double scale[2] = {0};
735  double *scale_x = NULL;
736  double *scale_y = NULL;
737 
738  int dim[2] = {0};
739  int *dim_x = NULL;
740  int *dim_y = NULL;
741 
742  ArrayType *array;
743  Oid etype;
744  Datum *e;
745  bool *nulls;
746  int16 typlen;
747  bool typbyval;
748  char typalign;
749  int n = 0;
750  int i = 0;
751  int j = 0;
752  int haserr = 0;
753 
754  text *pixeltypetext = NULL;
755  char *pixeltype = NULL;
756  rt_pixtype pixtype = PT_END;
757  rt_pixtype *pixtypes = NULL;
758  uint32_t pixtypes_len = 0;
759 
760  double *values = NULL;
761  uint32_t values_len = 0;
762 
763  uint8_t *hasnodatas = NULL;
764  double *nodatavals = NULL;
765  uint32_t nodatavals_len = 0;
766 
767  double ulw[2] = {0};
768  double *ul_xw = NULL;
769  double *ul_yw = NULL;
770 
771  double gridw[2] = {0};
772  double *grid_xw = NULL;
773  double *grid_yw = NULL;
774 
775  double skew[2] = {0};
776  double *skew_x = NULL;
777  double *skew_y = NULL;
778 
779  char **options = NULL;
780  int options_len = 0;
781 
782  uint32_t num_bands = 0;
783 
784  int32_t srid = SRID_UNKNOWN;
785  char *srs = NULL;
786 
787  POSTGIS_RT_DEBUG(3, "RASTER_asRaster: Starting");
788 
789  /* based upon LWGEOM_asBinary function in postgis/lwgeom_ogc.c */
790 
791  /* Get the geometry */
792  if (PG_ARGISNULL(0))
793  PG_RETURN_NULL();
794 
795  gser = PG_GETARG_GSERIALIZED_P(0);
796  geom = lwgeom_from_gserialized(gser);
797 
798  /* Get a 2D version of the geometry if necessary */
799  if (lwgeom_ndims(geom) > 2) {
800  LWGEOM *geom2d = lwgeom_force_2d(geom);
801  lwgeom_free(geom);
802  geom = geom2d;
803  }
804 
805  /* empty geometry, return empty raster */
806  if (lwgeom_is_empty(geom)) {
807  POSTGIS_RT_DEBUG(3, "Input geometry is empty. Returning empty raster");
808  lwgeom_free(geom);
809  PG_FREE_IF_COPY(gser, 0);
810 
811  rast = rt_raster_new(0, 0);
812  if (rast == NULL)
813  PG_RETURN_NULL();
814 
815  pgrast = rt_raster_serialize(rast);
817 
818  if (NULL == pgrast)
819  PG_RETURN_NULL();
820 
821  SET_VARSIZE(pgrast, pgrast->size);
822  PG_RETURN_POINTER(pgrast);
823  }
824 
825  /* scale x */
826  if (!PG_ARGISNULL(1)) {
827  scale[0] = PG_GETARG_FLOAT8(1);
828  if (FLT_NEQ(scale[0], 0.0))
829  scale_x = &scale[0];
830  }
831 
832  /* scale y */
833  if (!PG_ARGISNULL(2)) {
834  scale[1] = PG_GETARG_FLOAT8(2);
835  if (FLT_NEQ(scale[1], 0.0))
836  scale_y = &scale[1];
837  }
838  POSTGIS_RT_DEBUGF(3, "RASTER_asRaster: scale (x, y) = %f, %f", scale[0], scale[1]);
839 
840  /* width */
841  if (!PG_ARGISNULL(3)) {
842  dim[0] = PG_GETARG_INT32(3);
843  if (dim[0] < 0) dim[0] = 0;
844  if (dim[0] != 0) dim_x = &dim[0];
845  }
846 
847  /* height */
848  if (!PG_ARGISNULL(4)) {
849  dim[1] = PG_GETARG_INT32(4);
850  if (dim[1] < 0) dim[1] = 0;
851  if (dim[1] != 0) dim_y = &dim[1];
852  }
853  POSTGIS_RT_DEBUGF(3, "RASTER_asRaster: dim (x, y) = %d, %d", dim[0], dim[1]);
854 
855  /* pixeltype */
856  if (!PG_ARGISNULL(5)) {
857  array = PG_GETARG_ARRAYTYPE_P(5);
858  etype = ARR_ELEMTYPE(array);
859  get_typlenbyvalalign(etype, &typlen, &typbyval, &typalign);
860 
861  switch (etype) {
862  case TEXTOID:
863  break;
864  default:
865 
866  lwgeom_free(geom);
867  PG_FREE_IF_COPY(gser, 0);
868 
869  elog(ERROR, "RASTER_asRaster: Invalid data type for pixeltype");
870  PG_RETURN_NULL();
871  break;
872  }
873 
874  deconstruct_array(array, etype, typlen, typbyval, typalign, &e,
875  &nulls, &n);
876 
877  if (n) {
878  pixtypes = (rt_pixtype *) palloc(sizeof(rt_pixtype) * n);
879  /* clean each pixeltype */
880  for (i = 0, j = 0; i < n; i++) {
881  if (nulls[i]) {
882  pixtypes[j++] = PT_64BF;
883  continue;
884  }
885 
886  pixeltype = NULL;
887  switch (etype) {
888  case TEXTOID:
889  pixeltypetext = (text *) DatumGetPointer(e[i]);
890  if (NULL == pixeltypetext) break;
891  pixeltype = text_to_cstring(pixeltypetext);
892 
893  /* trim string */
894  pixeltype = rtpg_trim(pixeltype);
895  POSTGIS_RT_DEBUGF(3, "RASTER_asRaster: pixeltype is '%s'", pixeltype);
896  break;
897  }
898 
899  if (strlen(pixeltype)) {
900  pixtype = rt_pixtype_index_from_name(pixeltype);
901  if (pixtype == PT_END) {
902 
903  pfree(pixtypes);
904 
905  lwgeom_free(geom);
906  PG_FREE_IF_COPY(gser, 0);
907 
908  elog(ERROR, "RASTER_asRaster: Invalid pixel type provided: %s", pixeltype);
909  PG_RETURN_NULL();
910  }
911 
912  pixtypes[j] = pixtype;
913  j++;
914  }
915  }
916 
917  if (j > 0) {
918  /* trim allocation */
919  pixtypes = repalloc(pixtypes, j * sizeof(rt_pixtype));
920  pixtypes_len = j;
921  }
922  else {
923  pfree(pixtypes);
924  pixtypes = NULL;
925  pixtypes_len = 0;
926  }
927  }
928  }
929 #if POSTGIS_DEBUG_LEVEL > 0
930  for (uint32_t u = 0; u < pixtypes_len; u++)
931  POSTGIS_RT_DEBUGF(3, "RASTER_asRaster: pixtypes[%u] = %u", i, pixtypes[i]);
932 #endif
933 
934  /* value */
935  if (!PG_ARGISNULL(6)) {
936  array = PG_GETARG_ARRAYTYPE_P(6);
937  etype = ARR_ELEMTYPE(array);
938  get_typlenbyvalalign(etype, &typlen, &typbyval, &typalign);
939 
940  switch (etype) {
941  case FLOAT4OID:
942  case FLOAT8OID:
943  break;
944  default:
945 
946  if (pixtypes_len) pfree(pixtypes);
947 
948  lwgeom_free(geom);
949  PG_FREE_IF_COPY(gser, 0);
950 
951  elog(ERROR, "RASTER_asRaster: Invalid data type for value");
952  PG_RETURN_NULL();
953  break;
954  }
955 
956  deconstruct_array(array, etype, typlen, typbyval, typalign, &e,
957  &nulls, &n);
958 
959  if (n) {
960  values = (double *) palloc(sizeof(double) * n);
961  for (i = 0, j = 0; i < n; i++) {
962  if (nulls[i]) {
963  values[j++] = 1;
964  continue;
965  }
966 
967  switch (etype) {
968  case FLOAT4OID:
969  values[j] = (double) DatumGetFloat4(e[i]);
970  break;
971  case FLOAT8OID:
972  values[j] = (double) DatumGetFloat8(e[i]);
973  break;
974  }
975  POSTGIS_RT_DEBUGF(3, "RASTER_asRaster: values[%d] = %f", j, values[j]);
976 
977  j++;
978  }
979 
980  if (j > 0) {
981  /* trim allocation */
982  values = repalloc(values, j * sizeof(double));
983  values_len = j;
984  }
985  else {
986  pfree(values);
987  values = NULL;
988  values_len = 0;
989  }
990  }
991  }
992 #if POSTGIS_DEBUG_LEVEL > 0
993  for (uint32_t u = 0; u < values_len; u++)
994  POSTGIS_RT_DEBUGF(3, "RASTER_asRaster: values[%u] = %f", i, values[i]);
995 #endif
996 
997  /* nodataval */
998  if (!PG_ARGISNULL(7)) {
999  array = PG_GETARG_ARRAYTYPE_P(7);
1000  etype = ARR_ELEMTYPE(array);
1001  get_typlenbyvalalign(etype, &typlen, &typbyval, &typalign);
1002 
1003  switch (etype) {
1004  case FLOAT4OID:
1005  case FLOAT8OID:
1006  break;
1007  default:
1008 
1009  if (pixtypes_len) pfree(pixtypes);
1010  if (values_len) pfree(values);
1011 
1012  lwgeom_free(geom);
1013  PG_FREE_IF_COPY(gser, 0);
1014 
1015  elog(ERROR, "RASTER_asRaster: Invalid data type for nodataval");
1016  PG_RETURN_NULL();
1017  break;
1018  }
1019 
1020  deconstruct_array(array, etype, typlen, typbyval, typalign, &e,
1021  &nulls, &n);
1022 
1023  if (n) {
1024  nodatavals = (double *) palloc(sizeof(double) * n);
1025  hasnodatas = (uint8_t *) palloc(sizeof(uint8_t) * n);
1026  for (i = 0, j = 0; i < n; i++) {
1027  if (nulls[i]) {
1028  hasnodatas[j] = 0;
1029  nodatavals[j] = 0;
1030  j++;
1031  continue;
1032  }
1033 
1034  hasnodatas[j] = 1;
1035  switch (etype) {
1036  case FLOAT4OID:
1037  nodatavals[j] = (double) DatumGetFloat4(e[i]);
1038  break;
1039  case FLOAT8OID:
1040  nodatavals[j] = (double) DatumGetFloat8(e[i]);
1041  break;
1042  }
1043  POSTGIS_RT_DEBUGF(3, "RASTER_asRaster: hasnodatas[%d] = %d", j, hasnodatas[j]);
1044  POSTGIS_RT_DEBUGF(3, "RASTER_asRaster: nodatavals[%d] = %f", j, nodatavals[j]);
1045 
1046  j++;
1047  }
1048 
1049  if (j > 0) {
1050  /* trim allocation */
1051  nodatavals = repalloc(nodatavals, j * sizeof(double));
1052  hasnodatas = repalloc(hasnodatas, j * sizeof(uint8_t));
1053  nodatavals_len = j;
1054  }
1055  else {
1056  pfree(nodatavals);
1057  pfree(hasnodatas);
1058  nodatavals = NULL;
1059  hasnodatas = NULL;
1060  nodatavals_len = 0;
1061  }
1062  }
1063  }
1064 #if POSTGIS_DEBUG_LEVEL > 0
1065  for (uint32_t u = 0; u < nodatavals_len; u++)
1066  {
1067  POSTGIS_RT_DEBUGF(3, "RASTER_asRaster: hasnodatas[%u] = %d", u, hasnodatas[u]);
1068  POSTGIS_RT_DEBUGF(3, "RASTER_asRaster: nodatavals[%u] = %f", u, nodatavals[u]);
1069  }
1070 #endif
1071 
1072  /* upperleftx */
1073  if (!PG_ARGISNULL(8)) {
1074  ulw[0] = PG_GETARG_FLOAT8(8);
1075  ul_xw = &ulw[0];
1076  }
1077 
1078  /* upperlefty */
1079  if (!PG_ARGISNULL(9)) {
1080  ulw[1] = PG_GETARG_FLOAT8(9);
1081  ul_yw = &ulw[1];
1082  }
1083  POSTGIS_RT_DEBUGF(3, "RASTER_asRaster: upperleft (x, y) = %f, %f", ulw[0], ulw[1]);
1084 
1085  /* gridx */
1086  if (!PG_ARGISNULL(10)) {
1087  gridw[0] = PG_GETARG_FLOAT8(10);
1088  grid_xw = &gridw[0];
1089  }
1090 
1091  /* gridy */
1092  if (!PG_ARGISNULL(11)) {
1093  gridw[1] = PG_GETARG_FLOAT8(11);
1094  grid_yw = &gridw[1];
1095  }
1096  POSTGIS_RT_DEBUGF(3, "RASTER_asRaster: grid (x, y) = %f, %f", gridw[0], gridw[1]);
1097 
1098  /* check dependent variables */
1099  haserr = 0;
1100  do {
1101  /* only part of scale provided */
1102  if (
1103  (scale_x == NULL && scale_y != NULL) ||
1104  (scale_x != NULL && scale_y == NULL)
1105  ) {
1106  elog(NOTICE, "Values must be provided for both X and Y of scale if one is specified");
1107  haserr = 1;
1108  break;
1109  }
1110 
1111  /* only part of dimension provided */
1112  if (
1113  (dim_x == NULL && dim_y != NULL) ||
1114  (dim_x != NULL && dim_y == NULL)
1115  ) {
1116  elog(NOTICE, "Values must be provided for both width and height if one is specified");
1117  haserr = 1;
1118  break;
1119  }
1120 
1121  /* scale and dimension provided */
1122  if (
1123  (scale_x != NULL && scale_y != NULL) &&
1124  (dim_x != NULL && dim_y != NULL)
1125  ) {
1126  elog(NOTICE, "Values provided for X and Y of scale and width and height. Using the width and height");
1127  scale_x = NULL;
1128  scale_y = NULL;
1129  break;
1130  }
1131 
1132  /* neither scale or dimension provided */
1133  if (
1134  (scale_x == NULL && scale_y == NULL) &&
1135  (dim_x == NULL && dim_y == NULL)
1136  ) {
1137  elog(NOTICE, "Values must be provided for X and Y of scale or width and height");
1138  haserr = 1;
1139  break;
1140  }
1141 
1142  /* only part of upper-left provided */
1143  if (
1144  (ul_xw == NULL && ul_yw != NULL) ||
1145  (ul_xw != NULL && ul_yw == NULL)
1146  ) {
1147  elog(NOTICE, "Values must be provided for both X and Y when specifying the upper-left corner");
1148  haserr = 1;
1149  break;
1150  }
1151 
1152  /* only part of alignment provided */
1153  if (
1154  (grid_xw == NULL && grid_yw != NULL) ||
1155  (grid_xw != NULL && grid_yw == NULL)
1156  ) {
1157  elog(NOTICE, "Values must be provided for both X and Y when specifying the alignment");
1158  haserr = 1;
1159  break;
1160  }
1161 
1162  /* upper-left and alignment provided */
1163  if (
1164  (ul_xw != NULL && ul_yw != NULL) &&
1165  (grid_xw != NULL && grid_yw != NULL)
1166  ) {
1167  elog(NOTICE, "Values provided for both X and Y of upper-left corner and alignment. Using the values of upper-left corner");
1168  grid_xw = NULL;
1169  grid_yw = NULL;
1170  break;
1171  }
1172  }
1173  while (0);
1174 
1175  if (haserr) {
1176  if (pixtypes_len) pfree(pixtypes);
1177  if (values_len) pfree(values);
1178  if (nodatavals_len) {
1179  pfree(nodatavals);
1180  pfree(hasnodatas);
1181  }
1182 
1183  lwgeom_free(geom);
1184  PG_FREE_IF_COPY(gser, 0);
1185 
1186  PG_RETURN_NULL();
1187  }
1188 
1189  /* skewx */
1190  if (!PG_ARGISNULL(12)) {
1191  skew[0] = PG_GETARG_FLOAT8(12);
1192  if (FLT_NEQ(skew[0], 0.0))
1193  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.0))
1200  skew_y = &skew[1];
1201  }
1202  POSTGIS_RT_DEBUGF(3, "RASTER_asRaster: skew (x, y) = %f, %f", skew[0], skew[1]);
1203 
1204  /* all touched */
1205  if (!PG_ARGISNULL(14) && PG_GETARG_BOOL(14) == TRUE) {
1206  if (options_len == 0) {
1207  options_len = 1;
1208  options = (char **) palloc(sizeof(char *) * options_len);
1209  }
1210  else {
1211  options_len++;
1212  options = (char **) repalloc(options, sizeof(char *) * options_len);
1213  }
1214 
1215  options[options_len - 1] = palloc(sizeof(char*) * (strlen("ALL_TOUCHED=TRUE") + 1));
1216  strcpy(options[options_len - 1], "ALL_TOUCHED=TRUE");
1217  }
1218 
1219  if (options_len) {
1220  options_len++;
1221  options = (char **) repalloc(options, sizeof(char *) * options_len);
1222  options[options_len - 1] = NULL;
1223  }
1224 
1225  /* get geometry's srid */
1226  srid = gserialized_get_srid(gser);
1227 
1228  POSTGIS_RT_DEBUGF(3, "RASTER_asRaster: srid = %d", srid);
1229  if (clamp_srid(srid) != SRID_UNKNOWN) {
1230  srs = rtpg_getSR(srid);
1231  if (NULL == srs) {
1232 
1233  if (pixtypes_len) pfree(pixtypes);
1234  if (values_len) pfree(values);
1235  if (nodatavals_len) {
1236  pfree(hasnodatas);
1237  pfree(nodatavals);
1238  }
1239  if (options_len) pfree(options);
1240 
1241  lwgeom_free(geom);
1242  PG_FREE_IF_COPY(gser, 0);
1243 
1244  elog(ERROR, "RASTER_asRaster: Could not find srtext for SRID (%d)", srid);
1245  PG_RETURN_NULL();
1246  }
1247  POSTGIS_RT_DEBUGF(3, "RASTER_asRaster: srs is %s", srs);
1248  }
1249  else
1250  srs = NULL;
1251 
1252  /* determine number of bands */
1253  /* MIN macro is from GDAL's cpl_port.h */
1254  num_bands = MIN(pixtypes_len, values_len);
1255  num_bands = MIN(num_bands, nodatavals_len);
1256  POSTGIS_RT_DEBUGF(3, "RASTER_asRaster: pixtypes_len = %d", pixtypes_len);
1257  POSTGIS_RT_DEBUGF(3, "RASTER_asRaster: values_len = %d", values_len);
1258  POSTGIS_RT_DEBUGF(3, "RASTER_asRaster: nodatavals_len = %d", nodatavals_len);
1259  POSTGIS_RT_DEBUGF(3, "RASTER_asRaster: num_bands = %d", num_bands);
1260 
1261  /* warn of imbalanced number of band elements */
1262  if (!(
1263  (pixtypes_len == values_len) &&
1264  (values_len == nodatavals_len)
1265  )) {
1266  elog(
1267  NOTICE,
1268  "Imbalanced number of values provided for pixeltype (%d), value (%d) and nodataval (%d). Using the first %d values of each parameter",
1269  pixtypes_len,
1270  values_len,
1271  nodatavals_len,
1272  num_bands
1273  );
1274  }
1275 
1276  /* get wkb of geometry */
1277  POSTGIS_RT_DEBUG(3, "RASTER_asRaster: getting wkb of geometry");
1278  wkb = lwgeom_to_wkb_varlena(geom, variant);
1279  lwgeom_free(geom);
1280  PG_FREE_IF_COPY(gser, 0);
1281 
1282  /* rasterize geometry */
1283  POSTGIS_RT_DEBUG(3, "RASTER_asRaster: rasterizing geometry");
1284  /* use nodatavals for the init parameter */
1285  rast = rt_raster_gdal_rasterize((unsigned char *)wkb->data,
1286  LWSIZE_GET(wkb->size) - LWVARHDRSZ,
1287  srs,
1288  num_bands,
1289  pixtypes,
1290  nodatavals,
1291  values,
1292  nodatavals,
1293  hasnodatas,
1294  dim_x,
1295  dim_y,
1296  scale_x,
1297  scale_y,
1298  ul_xw,
1299  ul_yw,
1300  grid_xw,
1301  grid_yw,
1302  skew_x,
1303  skew_y,
1304  options);
1305 
1306  if (pixtypes_len) pfree(pixtypes);
1307  if (values_len) pfree(values);
1308  if (nodatavals_len) {
1309  pfree(hasnodatas);
1310  pfree(nodatavals);
1311  }
1312  if (options_len) pfree(options);
1313 
1314  if (!rast) {
1315  elog(ERROR, "RASTER_asRaster: Could not rasterize geometry");
1316  PG_RETURN_NULL();
1317  }
1318 
1319  /* add target srid */
1321 
1322  pgrast = rt_raster_serialize(rast);
1324 
1325  if (NULL == pgrast) PG_RETURN_NULL();
1326 
1327  POSTGIS_RT_DEBUG(3, "RASTER_asRaster: done");
1328 
1329  SET_VARSIZE(pgrast, pgrast->size);
1330  PG_RETURN_POINTER(pgrast);
1331 }
static uint8_t variant
Definition: cu_in_twkb.c:26
char result[OUT_DOUBLE_BUFFER_SIZE]
Definition: cu_print.c:267
#define TRUE
Definition: dbfopen.c:73
#define FALSE
Definition: dbfopen.c:72
int32_t gserialized_get_srid(const GSERIALIZED *g)
Extract the SRID from the serialized form (it is packed into three bytes so this is a handy function)...
Definition: gserialized.c:126
LWGEOM * lwgeom_from_gserialized(const GSERIALIZED *g)
Allocate a new LWGEOM from a GSERIALIZED.
Definition: gserialized.c:239
GSERIALIZED * gserialized_from_lwgeom(LWGEOM *geom, size_t *size)
Allocate a new GSERIALIZED from an LWGEOM.
Definition: gserialized.c:222
int lwgeom_ndims(const LWGEOM *geom)
Return the number of dimensions (2, 3, 4) in a geometry.
Definition: lwgeom.c:938
#define LWVARHDRSZ
Definition: liblwgeom.h:325
void lwgeom_free(LWGEOM *geom)
Definition: lwgeom.c:1138
void lwmpoly_free(LWMPOLY *mpoly)
Definition: lwmpoly.c:53
#define LWSIZE_GET(varsize)
Macro for reading the size from the GSERIALIZED size attribute.
Definition: liblwgeom.h:338
LWGEOM * lwpoly_as_lwgeom(const LWPOLY *obj)
Definition: lwgeom.c:312
LWGEOM * lwmpoly_as_lwgeom(const LWMPOLY *obj)
Definition: lwgeom.c:277
void lwpoly_free(LWPOLY *poly)
Definition: lwpoly.c:175
#define SRID_UNKNOWN
Unknown SRID value.
Definition: liblwgeom.h:229
lwvarlena_t * lwgeom_to_wkb_varlena(const LWGEOM *geom, uint8_t variant)
Definition: lwout_wkb.c:851
#define WKB_SFSQL
Definition: liblwgeom.h:2147
int32_t clamp_srid(int32_t srid)
Return a valid SRID from an arbitrary integer Raises a notice if what comes out is different from wha...
Definition: lwutil.c:333
LWGEOM * lwgeom_force_2d(const LWGEOM *geom)
Strip out the Z/M components of an LWGEOM.
Definition: lwgeom.c:776
#define FLT_NEQ(x, y)
Definition: librtcore.h:2234
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:1342
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:2491
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:1329
rt_band rt_raster_get_band(rt_raster raster, int bandNum)
Return Nth band, or NULL if unavailable.
Definition: rt_raster.c:381
static int lwgeom_is_empty(const LWGEOM *geom)
Return true or false depending on whether a geometry is an "empty" geometry (no vertices members)
Definition: lwinline.h:203
int value
Definition: genraster.py:62
band
Definition: ovdump.py:58
nband
Definition: pixval.py:53
raster
Be careful!! Zeros function's input parameter can be a (height x width) array, not (width x height): ...
Definition: rtrowdump.py:121
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:63
Datum RASTER_asRaster(PG_FUNCTION_ARGS)
PG_FUNCTION_INFO_V1(RASTER_envelope)
#define VALUES_LENGTH
Datum RASTER_getPixelPolygons(PG_FUNCTION_ARGS)
char * rtpg_getSR(int32_t 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:64
uint32_t size
Definition: liblwgeom.h:321
char data[]
Definition: liblwgeom.h:322
LWGEOM * geom
Definition: librtcore.h:2341
double value
Definition: librtcore.h:2339
uint8_t nodata
Definition: librtcore.h:2338
Struct definitions.
Definition: librtcore.h:2251