PostGIS  2.3.8dev-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 
93  rt_raster_destroy(raster);
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");
162  rt_raster_destroy(raster);
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 
172  rt_raster_destroy(raster);
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 
192 Datum RASTER_dumpAsPolygons(PG_FUNCTION_ARGS) {
193  FuncCallContext *funcctx;
194  TupleDesc tupdesc;
195  rt_geomval geomval;
196  rt_geomval geomval2;
197  int call_cntr;
198  int max_calls;
199 
200  /* stuff done only on the first call of the function */
201  if (SRF_IS_FIRSTCALL()) {
202  MemoryContext oldcontext;
203  int numbands;
204  rt_pgraster *pgraster = NULL;
205  rt_raster raster = NULL;
206  int nband;
207  bool exclude_nodata_value = TRUE;
208  int nElements;
209 
210  POSTGIS_RT_DEBUG(2, "RASTER_dumpAsPolygons first call");
211 
212  /* create a function context for cross-call persistence */
213  funcctx = SRF_FIRSTCALL_INIT();
214 
215  /* switch to memory context appropriate for multiple function calls */
216  oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
217 
218  /* Get input arguments */
219  if (PG_ARGISNULL(0)) {
220  MemoryContextSwitchTo(oldcontext);
221  SRF_RETURN_DONE(funcctx);
222  }
223  pgraster = (rt_pgraster *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
224  raster = rt_raster_deserialize(pgraster, FALSE);
225  if (!raster) {
226  PG_FREE_IF_COPY(pgraster, 0);
227  ereport(ERROR, (
228  errcode(ERRCODE_OUT_OF_MEMORY),
229  errmsg("Could not deserialize raster")
230  ));
231  MemoryContextSwitchTo(oldcontext);
232  SRF_RETURN_DONE(funcctx);
233  }
234 
235  if (!PG_ARGISNULL(1))
236  nband = PG_GETARG_UINT32(1);
237  else
238  nband = 1; /* By default, first band */
239 
240  POSTGIS_RT_DEBUGF(3, "band %d", nband);
241  numbands = rt_raster_get_num_bands(raster);
242 
243  if (nband < 1 || nband > numbands) {
244  elog(NOTICE, "Invalid band index (must use 1-based). Returning NULL");
245  rt_raster_destroy(raster);
246  PG_FREE_IF_COPY(pgraster, 0);
247  MemoryContextSwitchTo(oldcontext);
248  SRF_RETURN_DONE(funcctx);
249  }
250 
251  if (!PG_ARGISNULL(2))
252  exclude_nodata_value = PG_GETARG_BOOL(2);
253 
254  /* see if band is NODATA */
255  if (rt_band_get_isnodata_flag(rt_raster_get_band(raster, nband - 1))) {
256  POSTGIS_RT_DEBUGF(3, "Band at index %d is NODATA. Returning NULL", nband);
257  rt_raster_destroy(raster);
258  PG_FREE_IF_COPY(pgraster, 0);
259  MemoryContextSwitchTo(oldcontext);
260  SRF_RETURN_DONE(funcctx);
261  }
262 
263  /* Polygonize raster */
264 
268  geomval = rt_raster_gdal_polygonize(raster, nband - 1, exclude_nodata_value, &nElements);
269  rt_raster_destroy(raster);
270  PG_FREE_IF_COPY(pgraster, 0);
271  if (NULL == geomval) {
272  ereport(ERROR, (
273  errcode(ERRCODE_NO_DATA_FOUND),
274  errmsg("Could not polygonize raster")
275  ));
276  MemoryContextSwitchTo(oldcontext);
277  SRF_RETURN_DONE(funcctx);
278  }
279 
280  POSTGIS_RT_DEBUGF(3, "raster dump, %d elements returned", nElements);
281 
282  /* Store needed information */
283  funcctx->user_fctx = geomval;
284 
285  /* total number of tuples to be returned */
286  funcctx->max_calls = nElements;
287 
288  /* Build a tuple descriptor for our result type */
289  if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) {
290  ereport(ERROR, (
291  errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
292  errmsg("function returning record called in context that cannot accept type record")
293  ));
294  }
295 
296  BlessTupleDesc(tupdesc);
297  funcctx->tuple_desc = tupdesc;
298 
299  MemoryContextSwitchTo(oldcontext);
300  }
301 
302  /* stuff done on every call of the function */
303  funcctx = SRF_PERCALL_SETUP();
304 
305  call_cntr = funcctx->call_cntr;
306  max_calls = funcctx->max_calls;
307  tupdesc = funcctx->tuple_desc;
308  geomval2 = funcctx->user_fctx;
309 
310  /* do when there is more left to send */
311  if (call_cntr < max_calls) {
312  int values_length = 2;
313  Datum values[values_length];
314  bool nulls[values_length];
315  HeapTuple tuple;
316  Datum result;
317 
318  GSERIALIZED *gser = NULL;
319  size_t gser_size = 0;
320 
321  POSTGIS_RT_DEBUGF(3, "call number %d", call_cntr);
322 
323  memset(nulls, FALSE, sizeof(bool) * values_length);
324 
325  /* convert LWGEOM to GSERIALIZED */
326  gser = gserialized_from_lwgeom(lwpoly_as_lwgeom(geomval2[call_cntr].geom), &gser_size);
327  lwgeom_free(lwpoly_as_lwgeom(geomval2[call_cntr].geom));
328 
329  values[0] = PointerGetDatum(gser);
330  values[1] = Float8GetDatum(geomval2[call_cntr].val);
331 
332  /* build a tuple */
333  tuple = heap_form_tuple(tupdesc, values, nulls);
334 
335  /* make the tuple into a datum */
336  result = HeapTupleGetDatum(tuple);
337 
338  SRF_RETURN_NEXT(funcctx, result);
339  }
340  /* do when there is no more left */
341  else {
342  pfree(geomval2);
343  SRF_RETURN_DONE(funcctx);
344  }
345 }
346 
351 Datum RASTER_getPixelPolygons(PG_FUNCTION_ARGS)
352 {
353  FuncCallContext *funcctx;
354  TupleDesc tupdesc;
355  rt_pixel pix = NULL;
356  rt_pixel pix2;
357  int call_cntr;
358  int max_calls;
359  int i = 0;
360 
361  /* stuff done only on the first call of the function */
362  if (SRF_IS_FIRSTCALL()) {
363  MemoryContext oldcontext;
364  rt_pgraster *pgraster = NULL;
365  rt_raster raster = NULL;
366  rt_band band = NULL;
367  int nband = 1;
368  int numbands;
369  bool hasband = TRUE;
370  bool exclude_nodata_value = TRUE;
371  bool nocolumnx = FALSE;
372  bool norowy = FALSE;
373  int x = 0;
374  int y = 0;
375  int bounds[4] = {0};
376  int pixcount = 0;
377  double value = 0;
378  int isnodata = 0;
379 
380  LWPOLY *poly;
381 
382  POSTGIS_RT_DEBUG(3, "RASTER_getPixelPolygons first call");
383 
384  /* create a function context for cross-call persistence */
385  funcctx = SRF_FIRSTCALL_INIT();
386 
387  /* switch to memory context appropriate for multiple function calls */
388  oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
389 
390  if (PG_ARGISNULL(0)) {
391  MemoryContextSwitchTo(oldcontext);
392  SRF_RETURN_DONE(funcctx);
393  }
394  pgraster = (rt_pgraster *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
395 
396  /* band */
397  if (PG_ARGISNULL(1))
398  hasband = FALSE;
399  else {
400  nband = PG_GETARG_INT32(1);
401  hasband = TRUE;
402  }
403 
404  /* column */
405  if (PG_ARGISNULL(2))
406  nocolumnx = TRUE;
407  else {
408  bounds[0] = PG_GETARG_INT32(2);
409  bounds[1] = bounds[0];
410  }
411 
412  /* row */
413  if (PG_ARGISNULL(3))
414  norowy = TRUE;
415  else {
416  bounds[2] = PG_GETARG_INT32(3);
417  bounds[3] = bounds[2];
418  }
419 
420  /* exclude NODATA */
421  if (!PG_ARGISNULL(4))
422  exclude_nodata_value = PG_GETARG_BOOL(4);
423 
424  raster = rt_raster_deserialize(pgraster, FALSE);
425  if (!raster) {
426  PG_FREE_IF_COPY(pgraster, 0);
427  ereport(ERROR, (
428  errcode(ERRCODE_OUT_OF_MEMORY),
429  errmsg("Could not deserialize raster")
430  ));
431  MemoryContextSwitchTo(oldcontext);
432  SRF_RETURN_DONE(funcctx);
433  }
434 
435  /* raster empty, return NULL */
436  if (rt_raster_is_empty(raster)) {
437  elog(NOTICE, "Raster is empty. Returning NULL");
438  rt_raster_destroy(raster);
439  PG_FREE_IF_COPY(pgraster, 0);
440  MemoryContextSwitchTo(oldcontext);
441  SRF_RETURN_DONE(funcctx);
442  }
443 
444  /* band specified, load band and info */
445  if (hasband) {
446  numbands = rt_raster_get_num_bands(raster);
447  POSTGIS_RT_DEBUGF(3, "band %d", nband);
448  POSTGIS_RT_DEBUGF(3, "# of bands %d", numbands);
449 
450  if (nband < 1 || nband > numbands) {
451  elog(NOTICE, "Invalid band index (must use 1-based). Returning NULL");
452  rt_raster_destroy(raster);
453  PG_FREE_IF_COPY(pgraster, 0);
454  MemoryContextSwitchTo(oldcontext);
455  SRF_RETURN_DONE(funcctx);
456  }
457 
458  band = rt_raster_get_band(raster, nband - 1);
459  if (!band) {
460  elog(NOTICE, "Could not find band at index %d. Returning NULL", nband);
461  rt_raster_destroy(raster);
462  PG_FREE_IF_COPY(pgraster, 0);
463  MemoryContextSwitchTo(oldcontext);
464  SRF_RETURN_DONE(funcctx);
465  }
466 
467  if (!rt_band_get_hasnodata_flag(band))
468  exclude_nodata_value = FALSE;
469  }
470 
471  /* set bounds if columnx, rowy not set */
472  if (nocolumnx) {
473  bounds[0] = 1;
474  bounds[1] = rt_raster_get_width(raster);
475  }
476  if (norowy) {
477  bounds[2] = 1;
478  bounds[3] = rt_raster_get_height(raster);
479  }
480  POSTGIS_RT_DEBUGF(3, "bounds (min x, max x, min y, max y) = (%d, %d, %d, %d)",
481  bounds[0], bounds[1], bounds[2], bounds[3]);
482 
483  /* rowy */
484  pixcount = 0;
485  for (y = bounds[2]; y <= bounds[3]; y++) {
486  /* columnx */
487  for (x = bounds[0]; x <= bounds[1]; x++) {
488 
489  value = 0;
490  isnodata = TRUE;
491 
492  if (hasband) {
493  if (rt_band_get_pixel(band, x - 1, y - 1, &value, &isnodata) != ES_NONE) {
494 
495  for (i = 0; i < pixcount; i++)
496  lwgeom_free(pix[i].geom);
497  if (pixcount) pfree(pix);
498 
499  rt_band_destroy(band);
500  rt_raster_destroy(raster);
501  PG_FREE_IF_COPY(pgraster, 0);
502 
503  MemoryContextSwitchTo(oldcontext);
504  elog(ERROR, "RASTER_getPixelPolygons: Could not get pixel value");
505  SRF_RETURN_DONE(funcctx);
506  }
507 
508  /* don't continue if pixel is NODATA and to exclude NODATA */
509  if (isnodata && exclude_nodata_value) {
510  POSTGIS_RT_DEBUG(5, "pixel value is NODATA and exclude_nodata_value = TRUE");
511  continue;
512  }
513  }
514 
515  /* geometry */
516  poly = rt_raster_pixel_as_polygon(raster, x - 1, y - 1);
517  if (!poly) {
518  for (i = 0; i < pixcount; i++)
519  lwgeom_free(pix[i].geom);
520  if (pixcount) pfree(pix);
521 
522  if (hasband) rt_band_destroy(band);
523  rt_raster_destroy(raster);
524  PG_FREE_IF_COPY(pgraster, 0);
525 
526  MemoryContextSwitchTo(oldcontext);
527  elog(ERROR, "RASTER_getPixelPolygons: Could not get pixel polygon");
528  SRF_RETURN_DONE(funcctx);
529  }
530 
531  if (!pixcount)
532  pix = palloc(sizeof(struct rt_pixel_t) * (pixcount + 1));
533  else
534  pix = repalloc(pix, sizeof(struct rt_pixel_t) * (pixcount + 1));
535  if (pix == NULL) {
536 
537  lwpoly_free(poly);
538  if (hasband) rt_band_destroy(band);
539  rt_raster_destroy(raster);
540  PG_FREE_IF_COPY(pgraster, 0);
541 
542  MemoryContextSwitchTo(oldcontext);
543  elog(ERROR, "RASTER_getPixelPolygons: Could not allocate memory for storing pixel polygons");
544  SRF_RETURN_DONE(funcctx);
545  }
546  pix[pixcount].geom = (LWGEOM *) poly;
547  POSTGIS_RT_DEBUGF(5, "poly @ %p", poly);
548  POSTGIS_RT_DEBUGF(5, "geom @ %p", pix[pixcount].geom);
549 
550  /* x, y */
551  pix[pixcount].x = x;
552  pix[pixcount].y = y;
553 
554  /* value */
555  pix[pixcount].value = value;
556 
557  /* NODATA */
558  if (hasband) {
559  if (exclude_nodata_value)
560  pix[pixcount].nodata = isnodata;
561  else
562  pix[pixcount].nodata = FALSE;
563  }
564  else {
565  pix[pixcount].nodata = isnodata;
566  }
567 
568  pixcount++;
569  }
570  }
571 
572  if (hasband) rt_band_destroy(band);
573  rt_raster_destroy(raster);
574  PG_FREE_IF_COPY(pgraster, 0);
575 
576  /* shortcut if no pixcount */
577  if (pixcount < 1) {
578  elog(NOTICE, "No pixels found for band %d", nband);
579  MemoryContextSwitchTo(oldcontext);
580  SRF_RETURN_DONE(funcctx);
581  }
582 
583  /* Store needed information */
584  funcctx->user_fctx = pix;
585 
586  /* total number of tuples to be returned */
587  funcctx->max_calls = pixcount;
588  POSTGIS_RT_DEBUGF(3, "pixcount = %d", pixcount);
589 
590  /* Build a tuple descriptor for our result type */
591  if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) {
592  ereport(ERROR, (
593  errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
594  errmsg("function returning record called in context that cannot accept type record")
595  ));
596  }
597 
598  BlessTupleDesc(tupdesc);
599  funcctx->tuple_desc = tupdesc;
600 
601  MemoryContextSwitchTo(oldcontext);
602  }
603 
604  /* stuff done on every call of the function */
605  funcctx = SRF_PERCALL_SETUP();
606 
607  call_cntr = funcctx->call_cntr;
608  max_calls = funcctx->max_calls;
609  tupdesc = funcctx->tuple_desc;
610  pix2 = funcctx->user_fctx;
611 
612  /* do when there is more left to send */
613  if (call_cntr < max_calls) {
614  int values_length = 4;
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");
684  rt_raster_destroy(raster);
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");
694  rt_raster_destroy(raster);
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);
701  rt_raster_destroy(raster);
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  unsigned char *wkb;
732  size_t wkb_len = 0;
733  unsigned char variant = WKB_SFSQL;
734 
735  double scale[2] = {0};
736  double *scale_x = NULL;
737  double *scale_y = NULL;
738 
739  int dim[2] = {0};
740  int *dim_x = NULL;
741  int *dim_y = NULL;
742 
743  ArrayType *array;
744  Oid etype;
745  Datum *e;
746  bool *nulls;
747  int16 typlen;
748  bool typbyval;
749  char typalign;
750  int n = 0;
751  int i = 0;
752  int j = 0;
753  int haserr = 0;
754 
755  text *pixeltypetext = NULL;
756  char *pixeltype = NULL;
757  rt_pixtype pixtype = PT_END;
758  rt_pixtype *pixtypes = NULL;
759  int pixtypes_len = 0;
760 
761  double *values = NULL;
762  int values_len = 0;
763 
764  uint8_t *hasnodatas = NULL;
765  double *nodatavals = NULL;
766  int nodatavals_len = 0;
767 
768  double ulw[2] = {0};
769  double *ul_xw = NULL;
770  double *ul_yw = NULL;
771 
772  double gridw[2] = {0};
773  double *grid_xw = NULL;
774  double *grid_yw = NULL;
775 
776  double skew[2] = {0};
777  double *skew_x = NULL;
778  double *skew_y = NULL;
779 
780  char **options = NULL;
781  int options_len = 0;
782 
783  uint32_t num_bands = 0;
784 
785  int srid = SRID_UNKNOWN;
786  char *srs = NULL;
787 
788  POSTGIS_RT_DEBUG(3, "RASTER_asRaster: Starting");
789 
790  /* based upon LWGEOM_asBinary function in postgis/lwgeom_ogc.c */
791 
792  /* Get the geometry */
793  if (PG_ARGISNULL(0))
794  PG_RETURN_NULL();
795 
796  gser = PG_GETARG_GSERIALIZED_P(0);
797  geom = lwgeom_from_gserialized(gser);
798 
799  /* Get a 2D version of the geometry if necessary */
800  if (lwgeom_ndims(geom) > 2) {
801  LWGEOM *geom2d = lwgeom_force_2d(geom);
802  lwgeom_free(geom);
803  geom = geom2d;
804  }
805 
806  /* empty geometry, return empty raster */
807  if (lwgeom_is_empty(geom)) {
808  POSTGIS_RT_DEBUG(3, "Input geometry is empty. Returning empty raster");
809  lwgeom_free(geom);
810  PG_FREE_IF_COPY(gser, 0);
811 
812  rast = rt_raster_new(0, 0);
813  if (rast == NULL)
814  PG_RETURN_NULL();
815 
816  pgrast = rt_raster_serialize(rast);
817  rt_raster_destroy(rast);
818 
819  if (NULL == pgrast)
820  PG_RETURN_NULL();
821 
822  SET_VARSIZE(pgrast, pgrast->size);
823  PG_RETURN_POINTER(pgrast);
824  }
825 
826  /* scale x */
827  if (!PG_ARGISNULL(1)) {
828  scale[0] = PG_GETARG_FLOAT8(1);
829  if (FLT_NEQ(scale[0], 0)) 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)) scale_y = &scale[1];
836  }
837  POSTGIS_RT_DEBUGF(3, "RASTER_asRaster: scale (x, y) = %f, %f", scale[0], scale[1]);
838 
839  /* width */
840  if (!PG_ARGISNULL(3)) {
841  dim[0] = PG_GETARG_INT32(3);
842  if (dim[0] < 0) dim[0] = 0;
843  if (dim[0] != 0) dim_x = &dim[0];
844  }
845 
846  /* height */
847  if (!PG_ARGISNULL(4)) {
848  dim[1] = PG_GETARG_INT32(4);
849  if (dim[1] < 0) dim[1] = 0;
850  if (dim[1] != 0) dim_y = &dim[1];
851  }
852  POSTGIS_RT_DEBUGF(3, "RASTER_asRaster: dim (x, y) = %d, %d", dim[0], dim[1]);
853 
854  /* pixeltype */
855  if (!PG_ARGISNULL(5)) {
856  array = PG_GETARG_ARRAYTYPE_P(5);
857  etype = ARR_ELEMTYPE(array);
858  get_typlenbyvalalign(etype, &typlen, &typbyval, &typalign);
859 
860  switch (etype) {
861  case TEXTOID:
862  break;
863  default:
864 
865  lwgeom_free(geom);
866  PG_FREE_IF_COPY(gser, 0);
867 
868  elog(ERROR, "RASTER_asRaster: Invalid data type for pixeltype");
869  PG_RETURN_NULL();
870  break;
871  }
872 
873  deconstruct_array(array, etype, typlen, typbyval, typalign, &e,
874  &nulls, &n);
875 
876  if (n) {
877  pixtypes = (rt_pixtype *) palloc(sizeof(rt_pixtype) * n);
878  /* clean each pixeltype */
879  for (i = 0, j = 0; i < n; i++) {
880  if (nulls[i]) {
881  pixtypes[j++] = PT_64BF;
882  continue;
883  }
884 
885  pixeltype = NULL;
886  switch (etype) {
887  case TEXTOID:
888  pixeltypetext = (text *) DatumGetPointer(e[i]);
889  if (NULL == pixeltypetext) break;
890  pixeltype = text_to_cstring(pixeltypetext);
891 
892  /* trim string */
893  pixeltype = rtpg_trim(pixeltype);
894  POSTGIS_RT_DEBUGF(3, "RASTER_asRaster: pixeltype is '%s'", pixeltype);
895  break;
896  }
897 
898  if (strlen(pixeltype)) {
899  pixtype = rt_pixtype_index_from_name(pixeltype);
900  if (pixtype == PT_END) {
901 
902  pfree(pixtypes);
903 
904  lwgeom_free(geom);
905  PG_FREE_IF_COPY(gser, 0);
906 
907  elog(ERROR, "RASTER_asRaster: Invalid pixel type provided: %s", pixeltype);
908  PG_RETURN_NULL();
909  }
910 
911  pixtypes[j] = pixtype;
912  j++;
913  }
914  }
915 
916  if (j > 0) {
917  /* trim allocation */
918  pixtypes = repalloc(pixtypes, j * sizeof(rt_pixtype));
919  pixtypes_len = j;
920  }
921  else {
922  pfree(pixtypes);
923  pixtypes = NULL;
924  pixtypes_len = 0;
925  }
926  }
927  }
928 #if POSTGIS_DEBUG_LEVEL > 0
929  for (i = 0; i < pixtypes_len; i++)
930  POSTGIS_RT_DEBUGF(3, "RASTER_asRaster: pixtypes[%d] = %d", i, (int) pixtypes[i]);
931 #endif
932 
933  /* value */
934  if (!PG_ARGISNULL(6)) {
935  array = PG_GETARG_ARRAYTYPE_P(6);
936  etype = ARR_ELEMTYPE(array);
937  get_typlenbyvalalign(etype, &typlen, &typbyval, &typalign);
938 
939  switch (etype) {
940  case FLOAT4OID:
941  case FLOAT8OID:
942  break;
943  default:
944 
945  if (pixtypes_len) pfree(pixtypes);
946 
947  lwgeom_free(geom);
948  PG_FREE_IF_COPY(gser, 0);
949 
950  elog(ERROR, "RASTER_asRaster: Invalid data type for value");
951  PG_RETURN_NULL();
952  break;
953  }
954 
955  deconstruct_array(array, etype, typlen, typbyval, typalign, &e,
956  &nulls, &n);
957 
958  if (n) {
959  values = (double *) palloc(sizeof(double) * n);
960  for (i = 0, j = 0; i < n; i++) {
961  if (nulls[i]) {
962  values[j++] = 1;
963  continue;
964  }
965 
966  switch (etype) {
967  case FLOAT4OID:
968  values[j] = (double) DatumGetFloat4(e[i]);
969  break;
970  case FLOAT8OID:
971  values[j] = (double) DatumGetFloat8(e[i]);
972  break;
973  }
974  POSTGIS_RT_DEBUGF(3, "RASTER_asRaster: values[%d] = %f", j, values[j]);
975 
976  j++;
977  }
978 
979  if (j > 0) {
980  /* trim allocation */
981  values = repalloc(values, j * sizeof(double));
982  values_len = j;
983  }
984  else {
985  pfree(values);
986  values = NULL;
987  values_len = 0;
988  }
989  }
990  }
991 #if POSTGIS_DEBUG_LEVEL > 0
992  for (i = 0; i < values_len; i++)
993  POSTGIS_RT_DEBUGF(3, "RASTER_asRaster: values[%d] = %f", i, values[i]);
994 #endif
995 
996  /* nodataval */
997  if (!PG_ARGISNULL(7)) {
998  array = PG_GETARG_ARRAYTYPE_P(7);
999  etype = ARR_ELEMTYPE(array);
1000  get_typlenbyvalalign(etype, &typlen, &typbyval, &typalign);
1001 
1002  switch (etype) {
1003  case FLOAT4OID:
1004  case FLOAT8OID:
1005  break;
1006  default:
1007 
1008  if (pixtypes_len) pfree(pixtypes);
1009  if (values_len) pfree(values);
1010 
1011  lwgeom_free(geom);
1012  PG_FREE_IF_COPY(gser, 0);
1013 
1014  elog(ERROR, "RASTER_asRaster: Invalid data type for nodataval");
1015  PG_RETURN_NULL();
1016  break;
1017  }
1018 
1019  deconstruct_array(array, etype, typlen, typbyval, typalign, &e,
1020  &nulls, &n);
1021 
1022  if (n) {
1023  nodatavals = (double *) palloc(sizeof(double) * n);
1024  hasnodatas = (uint8_t *) palloc(sizeof(uint8_t) * n);
1025  for (i = 0, j = 0; i < n; i++) {
1026  if (nulls[i]) {
1027  hasnodatas[j] = 0;
1028  nodatavals[j] = 0;
1029  j++;
1030  continue;
1031  }
1032 
1033  hasnodatas[j] = 1;
1034  switch (etype) {
1035  case FLOAT4OID:
1036  nodatavals[j] = (double) DatumGetFloat4(e[i]);
1037  break;
1038  case FLOAT8OID:
1039  nodatavals[j] = (double) DatumGetFloat8(e[i]);
1040  break;
1041  }
1042  POSTGIS_RT_DEBUGF(3, "RASTER_asRaster: hasnodatas[%d] = %d", j, hasnodatas[j]);
1043  POSTGIS_RT_DEBUGF(3, "RASTER_asRaster: nodatavals[%d] = %f", j, nodatavals[j]);
1044 
1045  j++;
1046  }
1047 
1048  if (j > 0) {
1049  /* trim allocation */
1050  nodatavals = repalloc(nodatavals, j * sizeof(double));
1051  hasnodatas = repalloc(hasnodatas, j * sizeof(uint8_t));
1052  nodatavals_len = j;
1053  }
1054  else {
1055  pfree(nodatavals);
1056  pfree(hasnodatas);
1057  nodatavals = NULL;
1058  hasnodatas = NULL;
1059  nodatavals_len = 0;
1060  }
1061  }
1062  }
1063 #if POSTGIS_DEBUG_LEVEL > 0
1064  for (i = 0; i < nodatavals_len; i++) {
1065  POSTGIS_RT_DEBUGF(3, "RASTER_asRaster: hasnodatas[%d] = %d", i, hasnodatas[i]);
1066  POSTGIS_RT_DEBUGF(3, "RASTER_asRaster: nodatavals[%d] = %f", i, nodatavals[i]);
1067  }
1068 #endif
1069 
1070  /* upperleftx */
1071  if (!PG_ARGISNULL(8)) {
1072  ulw[0] = PG_GETARG_FLOAT8(8);
1073  ul_xw = &ulw[0];
1074  }
1075 
1076  /* upperlefty */
1077  if (!PG_ARGISNULL(9)) {
1078  ulw[1] = PG_GETARG_FLOAT8(9);
1079  ul_yw = &ulw[1];
1080  }
1081  POSTGIS_RT_DEBUGF(3, "RASTER_asRaster: upperleft (x, y) = %f, %f", ulw[0], ulw[1]);
1082 
1083  /* gridx */
1084  if (!PG_ARGISNULL(10)) {
1085  gridw[0] = PG_GETARG_FLOAT8(10);
1086  grid_xw = &gridw[0];
1087  }
1088 
1089  /* gridy */
1090  if (!PG_ARGISNULL(11)) {
1091  gridw[1] = PG_GETARG_FLOAT8(11);
1092  grid_yw = &gridw[1];
1093  }
1094  POSTGIS_RT_DEBUGF(3, "RASTER_asRaster: grid (x, y) = %f, %f", gridw[0], gridw[1]);
1095 
1096  /* check dependent variables */
1097  haserr = 0;
1098  do {
1099  /* only part of scale provided */
1100  if (
1101  (scale_x == NULL && scale_y != NULL) ||
1102  (scale_x != NULL && scale_y == NULL)
1103  ) {
1104  elog(NOTICE, "Values must be provided for both X and Y of scale if one is specified");
1105  haserr = 1;
1106  break;
1107  }
1108 
1109  /* only part of dimension provided */
1110  if (
1111  (dim_x == NULL && dim_y != NULL) ||
1112  (dim_x != NULL && dim_y == NULL)
1113  ) {
1114  elog(NOTICE, "Values must be provided for both width and height if one is specified");
1115  haserr = 1;
1116  break;
1117  }
1118 
1119  /* scale and dimension provided */
1120  if (
1121  (scale_x != NULL && scale_y != NULL) &&
1122  (dim_x != NULL && dim_y != NULL)
1123  ) {
1124  elog(NOTICE, "Values provided for X and Y of scale and width and height. Using the width and height");
1125  scale_x = NULL;
1126  scale_y = NULL;
1127  break;
1128  }
1129 
1130  /* neither scale or dimension provided */
1131  if (
1132  (scale_x == NULL && scale_y == NULL) &&
1133  (dim_x == NULL && dim_y == NULL)
1134  ) {
1135  elog(NOTICE, "Values must be provided for X and Y of scale or width and height");
1136  haserr = 1;
1137  break;
1138  }
1139 
1140  /* only part of upper-left provided */
1141  if (
1142  (ul_xw == NULL && ul_yw != NULL) ||
1143  (ul_xw != NULL && ul_yw == NULL)
1144  ) {
1145  elog(NOTICE, "Values must be provided for both X and Y when specifying the upper-left corner");
1146  haserr = 1;
1147  break;
1148  }
1149 
1150  /* only part of alignment provided */
1151  if (
1152  (grid_xw == NULL && grid_yw != NULL) ||
1153  (grid_xw != NULL && grid_yw == NULL)
1154  ) {
1155  elog(NOTICE, "Values must be provided for both X and Y when specifying the alignment");
1156  haserr = 1;
1157  break;
1158  }
1159 
1160  /* upper-left and alignment provided */
1161  if (
1162  (ul_xw != NULL && ul_yw != NULL) &&
1163  (grid_xw != NULL && grid_yw != NULL)
1164  ) {
1165  elog(NOTICE, "Values provided for both X and Y of upper-left corner and alignment. Using the values of upper-left corner");
1166  grid_xw = NULL;
1167  grid_yw = NULL;
1168  break;
1169  }
1170  }
1171  while (0);
1172 
1173  if (haserr) {
1174  if (pixtypes_len) pfree(pixtypes);
1175  if (values_len) pfree(values);
1176  if (nodatavals_len) {
1177  pfree(nodatavals);
1178  pfree(hasnodatas);
1179  }
1180 
1181  lwgeom_free(geom);
1182  PG_FREE_IF_COPY(gser, 0);
1183 
1184  PG_RETURN_NULL();
1185  }
1186 
1187  /* skewx */
1188  if (!PG_ARGISNULL(12)) {
1189  skew[0] = PG_GETARG_FLOAT8(12);
1190  if (FLT_NEQ(skew[0], 0)) skew_x = &skew[0];
1191  }
1192 
1193  /* skewy */
1194  if (!PG_ARGISNULL(13)) {
1195  skew[1] = PG_GETARG_FLOAT8(13);
1196  if (FLT_NEQ(skew[1], 0)) skew_y = &skew[1];
1197  }
1198  POSTGIS_RT_DEBUGF(3, "RASTER_asRaster: skew (x, y) = %f, %f", skew[0], skew[1]);
1199 
1200  /* all touched */
1201  if (!PG_ARGISNULL(14) && PG_GETARG_BOOL(14) == TRUE) {
1202  if (options_len < 1) {
1203  options_len = 1;
1204  options = (char **) palloc(sizeof(char *) * options_len);
1205  }
1206  else {
1207  options_len++;
1208  options = (char **) repalloc(options, sizeof(char *) * options_len);
1209  }
1210 
1211  options[options_len - 1] = palloc(sizeof(char*) * (strlen("ALL_TOUCHED=TRUE") + 1));
1212  options[options_len - 1] = "ALL_TOUCHED=TRUE";
1213  }
1214 
1215  if (options_len) {
1216  options_len++;
1217  options = (char **) repalloc(options, sizeof(char *) * options_len);
1218  options[options_len - 1] = NULL;
1219  }
1220 
1221  /* get geometry's srid */
1222  srid = gserialized_get_srid(gser);
1223 
1224  POSTGIS_RT_DEBUGF(3, "RASTER_asRaster: srid = %d", srid);
1225  if (clamp_srid(srid) != SRID_UNKNOWN) {
1226  srs = rtpg_getSR(srid);
1227  if (NULL == srs) {
1228 
1229  if (pixtypes_len) pfree(pixtypes);
1230  if (values_len) pfree(values);
1231  if (nodatavals_len) {
1232  pfree(hasnodatas);
1233  pfree(nodatavals);
1234  }
1235  if (options_len) pfree(options);
1236 
1237  lwgeom_free(geom);
1238  PG_FREE_IF_COPY(gser, 0);
1239 
1240  elog(ERROR, "RASTER_asRaster: Could not find srtext for SRID (%d)", srid);
1241  PG_RETURN_NULL();
1242  }
1243  POSTGIS_RT_DEBUGF(3, "RASTER_asRaster: srs is %s", srs);
1244  }
1245  else
1246  srs = NULL;
1247 
1248  /* determine number of bands */
1249  /* MIN macro is from GDAL's cpl_port.h */
1250  num_bands = MIN(pixtypes_len, values_len);
1251  num_bands = MIN(num_bands, nodatavals_len);
1252  POSTGIS_RT_DEBUGF(3, "RASTER_asRaster: pixtypes_len = %d", pixtypes_len);
1253  POSTGIS_RT_DEBUGF(3, "RASTER_asRaster: values_len = %d", values_len);
1254  POSTGIS_RT_DEBUGF(3, "RASTER_asRaster: nodatavals_len = %d", nodatavals_len);
1255  POSTGIS_RT_DEBUGF(3, "RASTER_asRaster: num_bands = %d", num_bands);
1256 
1257  /* warn of imbalanced number of band elements */
1258  if (!(
1259  (pixtypes_len == values_len) &&
1260  (values_len == nodatavals_len)
1261  )) {
1262  elog(
1263  NOTICE,
1264  "Imbalanced number of values provided for pixeltype (%d), value (%d) and nodataval (%d). Using the first %d values of each parameter",
1265  pixtypes_len,
1266  values_len,
1267  nodatavals_len,
1268  num_bands
1269  );
1270  }
1271 
1272  /* get wkb of geometry */
1273  POSTGIS_RT_DEBUG(3, "RASTER_asRaster: getting wkb of geometry");
1274  wkb = lwgeom_to_wkb(geom, variant, &wkb_len);
1275  lwgeom_free(geom);
1276  PG_FREE_IF_COPY(gser, 0);
1277 
1278  /* rasterize geometry */
1279  POSTGIS_RT_DEBUG(3, "RASTER_asRaster: rasterizing geometry");
1280  /* use nodatavals for the init parameter */
1281  rast = rt_raster_gdal_rasterize(wkb,
1282  (uint32_t) wkb_len, srs,
1283  num_bands, pixtypes,
1284  nodatavals, values,
1285  nodatavals, hasnodatas,
1286  dim_x, dim_y,
1287  scale_x, scale_y,
1288  ul_xw, ul_yw,
1289  grid_xw, grid_yw,
1290  skew_x, skew_y,
1291  options
1292  );
1293 
1294  if (pixtypes_len) pfree(pixtypes);
1295  if (values_len) pfree(values);
1296  if (nodatavals_len) {
1297  pfree(hasnodatas);
1298  pfree(nodatavals);
1299  }
1300  if (options_len) pfree(options);
1301 
1302  if (!rast) {
1303  elog(ERROR, "RASTER_asRaster: Could not rasterize geometry");
1304  PG_RETURN_NULL();
1305  }
1306 
1307  /* add target srid */
1308  rt_raster_set_srid(rast, srid);
1309 
1310  pgrast = rt_raster_serialize(rast);
1311  rt_raster_destroy(rast);
1312 
1313  if (NULL == pgrast) PG_RETURN_NULL();
1314 
1315  POSTGIS_RT_DEBUG(3, "RASTER_asRaster: done");
1316 
1317  SET_VARSIZE(pgrast, pgrast->size);
1318  PG_RETURN_POINTER(pgrast);
1319 }
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:378
void * rt_raster_serialize(rt_raster raster)
Return this raster in serialized form.
Definition: rt_serialize.c:521
int rt_raster_get_num_bands(rt_raster raster)
Definition: rt_raster.c:372
uint8_t variant
Definition: cu_in_twkb.c:26
LWGEOM * lwgeom_from_gserialized(const GSERIALIZED *g)
Allocate a new LWGEOM from a GSERIALIZED.
Datum RASTER_getPolygon(PG_FUNCTION_ARGS)
raster
Be careful!! Zeros function&#39;s input parameter can be a (height x width) array, not (width x height): ...
Definition: rtrowdump.py:121
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
void lwgeom_free(LWGEOM *geom)
Definition: lwgeom.c:1063
band
Definition: ovdump.py:57
LWGEOM * geom
Definition: librtcore.h:2303
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:2492
double value
Definition: librtcore.h:2301
#define MIN(a, b)
Definition: shpopen.c:283
PG_FUNCTION_INFO_V1(RASTER_envelope)
rt_pixtype
Definition: librtcore.h:197
void rt_band_destroy(rt_band band)
Destroy a raster band.
Definition: rt_band.c:242
LWGEOM * lwpoly_as_lwgeom(const LWPOLY *obj)
Definition: lwgeom.c:252
Datum RASTER_envelope(PG_FUNCTION_ARGS)
Definition: rtpg_geometry.c:66
int lwgeom_ndims(const LWGEOM *geom)
Return the number of dimensions (2, 3, 4) in a geometry.
Definition: lwgeom.c:863
#define WKB_SFSQL
Definition: liblwgeom.h:2047
int rt_raster_is_empty(rt_raster raster)
Return TRUE if the raster is empty.
Definition: rt_raster.c:1338
#define POSTGIS_RT_DEBUGF(level, msg,...)
Definition: rtpostgis.h:57
rt_errorstate rt_raster_get_convex_hull(rt_raster raster, LWGEOM **hull)
Get raster&#39;s convex hull.
Definition: rt_geometry.c:803
rt_errorstate rt_raster_surface(rt_raster raster, int nband, LWMPOLY **surface)
Get a raster as a surface (multipolygon).
Definition: rt_geometry.c:355
void lwmpoly_free(LWMPOLY *mpoly)
Definition: lwmpoly.c:53
nband
Definition: pixval.py:52
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
void lwpoly_free(LWPOLY *poly)
Definition: lwpoly.c:152
rt_errorstate rt_band_get_pixel(rt_band band, int x, int y, double *value, int *nodata)
Get pixel value.
Definition: rt_band.c:1088
rt_pixtype rt_pixtype_index_from_name(const char *pixname)
Definition: rt_pixel.c:80
#define SRID_UNKNOWN
Unknown SRID value.
Definition: liblwgeom.h:187
LWGEOM * lwgeom_force_2d(const LWGEOM *geom)
Strip out the Z/M components of an LWGEOM.
Definition: lwgeom.c:703
rt_band rt_raster_get_band(rt_raster raster, int bandNum)
Return Nth band, or NULL if unavailable.
Definition: rt_raster.c:381
#define FLT_NEQ(x, y)
Definition: librtcore.h:2196
Datum RASTER_asRaster(PG_FUNCTION_ARGS)
int rt_band_get_hasnodata_flag(rt_band band)
Get hasnodata flag value.
Definition: rt_band.c:541
LWPOLY * rt_raster_pixel_as_polygon(rt_raster raster, int x, int y)
Get a raster pixel as a polygon.
Definition: rt_geometry.c:610
char * rtpg_trim(const char *input)
int rt_raster_has_band(rt_raster raster, int nband)
Return TRUE if the raster has a band of this number.
Definition: rt_raster.c:1351
rt_errorstate rt_raster_get_envelope_geom(rt_raster raster, LWGEOM **env)
Get raster&#39;s envelope as a geometry.
Definition: rt_geometry.c:670
void rt_raster_set_srid(rt_raster raster, int32_t srid)
Set raster&#39;s SRID.
Definition: rt_raster.c:363
Datum RASTER_convex_hull(PG_FUNCTION_ARGS)
void rt_raster_destroy(rt_raster raster)
Release memory associated to a raster.
Definition: rt_raster.c:82
uint8_t nodata
Definition: librtcore.h:2300
rt_raster rt_raster_new(uint32_t width, uint32_t height)
Construct a raster with given dimensions.
Definition: rt_raster.c:48
Datum RASTER_dumpAsPolygons(PG_FUNCTION_ARGS)
uint16_t rt_raster_get_width(rt_raster raster)
Definition: rt_raster.c:121
#define FALSE
Definition: dbfopen.c:168
GSERIALIZED * geometry_serialize(LWGEOM *lwgeom)
Struct definitions.
Definition: librtcore.h:2213
Datum RASTER_getPixelPolygons(PG_FUNCTION_ARGS)
int rt_band_get_isnodata_flag(rt_band band)
Get isnodata flag value.
Definition: rt_band.c:581
char * rtpg_getSR(int srid)
int value
Definition: genraster.py:61
rt_errorstate rt_raster_get_perimeter(rt_raster raster, int nband, LWGEOM **perimeter)
Get raster perimeter.
Definition: rt_geometry.c:182
uint16_t rt_raster_get_height(rt_raster raster)
Definition: rt_raster.c:129
#define POSTGIS_RT_DEBUG(level, msg)
Definition: rtpostgis.h:53
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:1310
GSERIALIZED * gserialized_from_lwgeom(LWGEOM *geom, size_t *size)
Allocate a new GSERIALIZED from an LWGEOM.
Definition: g_serialized.c:933
#define TRUE
Definition: dbfopen.c:169
rt_raster rt_raster_deserialize(void *serialized, int header_only)
Return a raster from a serialized form.
Definition: rt_serialize.c:717
LWGEOM * lwmpoly_as_lwgeom(const LWMPOLY *obj)
Definition: lwgeom.c:217
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:83