PostGIS 3.0.6dev-r@@SVN_REVISION@@
Loading...
Searching...
No Matches
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
46Datum RASTER_envelope(PG_FUNCTION_ARGS);
47Datum RASTER_convex_hull(PG_FUNCTION_ARGS);
48Datum RASTER_dumpAsPolygons(PG_FUNCTION_ARGS);
49
50/* Get pixel geographical shape */
51Datum RASTER_getPixelPolygons(PG_FUNCTION_ARGS);
52
53/* Get raster band's polygon */
54Datum RASTER_getPolygon(PG_FUNCTION_ARGS);
55
56/* rasterize a geometry */
57Datum RASTER_asRaster(PG_FUNCTION_ARGS);
58
59/* ---------------------------------------------------------------- */
60/* Raster envelope */
61/* ---------------------------------------------------------------- */
63Datum RASTER_envelope(PG_FUNCTION_ARGS)
64{
65 rt_pgraster *pgraster;
66 rt_raster raster;
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
90 rt_raster_destroy(raster);
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/* ---------------------------------------------------------------- */
116Datum RASTER_convex_hull(PG_FUNCTION_ARGS)
117{
118 rt_pgraster *pgraster;
119 rt_raster raster;
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");
159 rt_raster_destroy(raster);
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
169 rt_raster_destroy(raster);
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
191Datum 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");
244 rt_raster_destroy(raster);
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 */
254 if (rt_band_get_isnodata_flag(rt_raster_get_band(raster, nband - 1))) {
255 POSTGIS_RT_DEBUGF(3, "Band at index %d is NODATA. Returning NULL", nband);
256 rt_raster_destroy(raster);
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);
268 rt_raster_destroy(raster);
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
352Datum 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");
439 rt_raster_destroy(raster);
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");
453 rt_raster_destroy(raster);
454 PG_FREE_IF_COPY(pgraster, 0);
455 MemoryContextSwitchTo(oldcontext);
456 SRF_RETURN_DONE(funcctx);
457 }
458
459 band = rt_raster_get_band(raster, nband - 1);
460 if (!band) {
461 elog(NOTICE, "Could not find band at index %d. Returning NULL", nband);
462 rt_raster_destroy(raster);
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
500 rt_band_destroy(band);
501 rt_raster_destroy(raster);
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);
524 rt_raster_destroy(raster);
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);
540 rt_raster_destroy(raster);
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);
574 rt_raster_destroy(raster);
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
658Datum 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
714 lwmpoly_free(surface);
715
716 PG_RETURN_POINTER(rtn);
717}
718
723Datum 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 uint32_t pixtypes_len = 0;
760
761 double *values = NULL;
762 uint32_t values_len = 0;
763
764 uint8_t *hasnodatas = NULL;
765 double *nodatavals = NULL;
766 uint32_t 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 int32_t 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.0))
830 scale_x = &scale[0];
831 }
832
833 /* scale y */
834 if (!PG_ARGISNULL(2)) {
835 scale[1] = PG_GETARG_FLOAT8(2);
836 if (FLT_NEQ(scale[1], 0.0))
837 scale_y = &scale[1];
838 }
839 POSTGIS_RT_DEBUGF(3, "RASTER_asRaster: scale (x, y) = %f, %f", scale[0], scale[1]);
840
841 /* width */
842 if (!PG_ARGISNULL(3)) {
843 dim[0] = PG_GETARG_INT32(3);
844 if (dim[0] < 0) dim[0] = 0;
845 if (dim[0] != 0) dim_x = &dim[0];
846 }
847
848 /* height */
849 if (!PG_ARGISNULL(4)) {
850 dim[1] = PG_GETARG_INT32(4);
851 if (dim[1] < 0) dim[1] = 0;
852 if (dim[1] != 0) dim_y = &dim[1];
853 }
854 POSTGIS_RT_DEBUGF(3, "RASTER_asRaster: dim (x, y) = %d, %d", dim[0], dim[1]);
855
856 /* pixeltype */
857 if (!PG_ARGISNULL(5)) {
858 array = PG_GETARG_ARRAYTYPE_P(5);
859 etype = ARR_ELEMTYPE(array);
860 get_typlenbyvalalign(etype, &typlen, &typbyval, &typalign);
861
862 switch (etype) {
863 case TEXTOID:
864 break;
865 default:
866
867 lwgeom_free(geom);
868 PG_FREE_IF_COPY(gser, 0);
869
870 elog(ERROR, "RASTER_asRaster: Invalid data type for pixeltype");
871 PG_RETURN_NULL();
872 break;
873 }
874
875 deconstruct_array(array, etype, typlen, typbyval, typalign, &e,
876 &nulls, &n);
877
878 if (n) {
879 pixtypes = (rt_pixtype *) palloc(sizeof(rt_pixtype) * n);
880 /* clean each pixeltype */
881 for (i = 0, j = 0; i < n; i++) {
882 if (nulls[i]) {
883 pixtypes[j++] = PT_64BF;
884 continue;
885 }
886
887 pixeltype = NULL;
888 switch (etype) {
889 case TEXTOID:
890 pixeltypetext = (text *) DatumGetPointer(e[i]);
891 if (NULL == pixeltypetext) break;
892 pixeltype = text_to_cstring(pixeltypetext);
893
894 /* trim string */
895 pixeltype = rtpg_trim(pixeltype);
896 POSTGIS_RT_DEBUGF(3, "RASTER_asRaster: pixeltype is '%s'", pixeltype);
897 break;
898 }
899
900 if (strlen(pixeltype)) {
901 pixtype = rt_pixtype_index_from_name(pixeltype);
902 if (pixtype == PT_END) {
903
904 pfree(pixtypes);
905
906 lwgeom_free(geom);
907 PG_FREE_IF_COPY(gser, 0);
908
909 elog(ERROR, "RASTER_asRaster: Invalid pixel type provided: %s", pixeltype);
910 PG_RETURN_NULL();
911 }
912
913 pixtypes[j] = pixtype;
914 j++;
915 }
916 }
917
918 if (j > 0) {
919 /* trim allocation */
920 pixtypes = repalloc(pixtypes, j * sizeof(rt_pixtype));
921 pixtypes_len = j;
922 }
923 else {
924 pfree(pixtypes);
925 pixtypes = NULL;
926 pixtypes_len = 0;
927 }
928 }
929 }
930#if POSTGIS_DEBUG_LEVEL > 0
931 for (uint32_t u = 0; u < pixtypes_len; u++)
932 POSTGIS_RT_DEBUGF(3, "RASTER_asRaster: pixtypes[%u] = %u", i, pixtypes[i]);
933#endif
934
935 /* value */
936 if (!PG_ARGISNULL(6)) {
937 array = PG_GETARG_ARRAYTYPE_P(6);
938 etype = ARR_ELEMTYPE(array);
939 get_typlenbyvalalign(etype, &typlen, &typbyval, &typalign);
940
941 switch (etype) {
942 case FLOAT4OID:
943 case FLOAT8OID:
944 break;
945 default:
946
947 if (pixtypes_len) pfree(pixtypes);
948
949 lwgeom_free(geom);
950 PG_FREE_IF_COPY(gser, 0);
951
952 elog(ERROR, "RASTER_asRaster: Invalid data type for value");
953 PG_RETURN_NULL();
954 break;
955 }
956
957 deconstruct_array(array, etype, typlen, typbyval, typalign, &e,
958 &nulls, &n);
959
960 if (n) {
961 values = (double *) palloc(sizeof(double) * n);
962 for (i = 0, j = 0; i < n; i++) {
963 if (nulls[i]) {
964 values[j++] = 1;
965 continue;
966 }
967
968 switch (etype) {
969 case FLOAT4OID:
970 values[j] = (double) DatumGetFloat4(e[i]);
971 break;
972 case FLOAT8OID:
973 values[j] = (double) DatumGetFloat8(e[i]);
974 break;
975 }
976 POSTGIS_RT_DEBUGF(3, "RASTER_asRaster: values[%d] = %f", j, values[j]);
977
978 j++;
979 }
980
981 if (j > 0) {
982 /* trim allocation */
983 values = repalloc(values, j * sizeof(double));
984 values_len = j;
985 }
986 else {
987 pfree(values);
988 values = NULL;
989 values_len = 0;
990 }
991 }
992 }
993#if POSTGIS_DEBUG_LEVEL > 0
994 for (uint32_t u = 0; u < values_len; u++)
995 POSTGIS_RT_DEBUGF(3, "RASTER_asRaster: values[%u] = %f", i, values[i]);
996#endif
997
998 /* nodataval */
999 if (!PG_ARGISNULL(7)) {
1000 array = PG_GETARG_ARRAYTYPE_P(7);
1001 etype = ARR_ELEMTYPE(array);
1002 get_typlenbyvalalign(etype, &typlen, &typbyval, &typalign);
1003
1004 switch (etype) {
1005 case FLOAT4OID:
1006 case FLOAT8OID:
1007 break;
1008 default:
1009
1010 if (pixtypes_len) pfree(pixtypes);
1011 if (values_len) pfree(values);
1012
1013 lwgeom_free(geom);
1014 PG_FREE_IF_COPY(gser, 0);
1015
1016 elog(ERROR, "RASTER_asRaster: Invalid data type for nodataval");
1017 PG_RETURN_NULL();
1018 break;
1019 }
1020
1021 deconstruct_array(array, etype, typlen, typbyval, typalign, &e,
1022 &nulls, &n);
1023
1024 if (n) {
1025 nodatavals = (double *) palloc(sizeof(double) * n);
1026 hasnodatas = (uint8_t *) palloc(sizeof(uint8_t) * n);
1027 for (i = 0, j = 0; i < n; i++) {
1028 if (nulls[i]) {
1029 hasnodatas[j] = 0;
1030 nodatavals[j] = 0;
1031 j++;
1032 continue;
1033 }
1034
1035 hasnodatas[j] = 1;
1036 switch (etype) {
1037 case FLOAT4OID:
1038 nodatavals[j] = (double) DatumGetFloat4(e[i]);
1039 break;
1040 case FLOAT8OID:
1041 nodatavals[j] = (double) DatumGetFloat8(e[i]);
1042 break;
1043 }
1044 POSTGIS_RT_DEBUGF(3, "RASTER_asRaster: hasnodatas[%d] = %d", j, hasnodatas[j]);
1045 POSTGIS_RT_DEBUGF(3, "RASTER_asRaster: nodatavals[%d] = %f", j, nodatavals[j]);
1046
1047 j++;
1048 }
1049
1050 if (j > 0) {
1051 /* trim allocation */
1052 nodatavals = repalloc(nodatavals, j * sizeof(double));
1053 hasnodatas = repalloc(hasnodatas, j * sizeof(uint8_t));
1054 nodatavals_len = j;
1055 }
1056 else {
1057 pfree(nodatavals);
1058 pfree(hasnodatas);
1059 nodatavals = NULL;
1060 hasnodatas = NULL;
1061 nodatavals_len = 0;
1062 }
1063 }
1064 }
1065#if POSTGIS_DEBUG_LEVEL > 0
1066 for (uint32_t u = 0; u < nodatavals_len; u++)
1067 {
1068 POSTGIS_RT_DEBUGF(3, "RASTER_asRaster: hasnodatas[%u] = %d", u, hasnodatas[u]);
1069 POSTGIS_RT_DEBUGF(3, "RASTER_asRaster: nodatavals[%u] = %f", u, nodatavals[u]);
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.0))
1194 skew_x = &skew[0];
1195 }
1196
1197 /* skewy */
1198 if (!PG_ARGISNULL(13)) {
1199 skew[1] = PG_GETARG_FLOAT8(13);
1200 if (FLT_NEQ(skew[1], 0.0))
1201 skew_y = &skew[1];
1202 }
1203 POSTGIS_RT_DEBUGF(3, "RASTER_asRaster: skew (x, y) = %f, %f", skew[0], skew[1]);
1204
1205 /* all touched */
1206 if (!PG_ARGISNULL(14) && PG_GETARG_BOOL(14) == TRUE) {
1207 if (options_len == 0) {
1208 options_len = 1;
1209 options = (char **) palloc(sizeof(char *) * options_len);
1210 }
1211 else {
1212 options_len++;
1213 options = (char **) repalloc(options, sizeof(char *) * options_len);
1214 }
1215
1216 options[options_len - 1] = palloc(sizeof(char*) * (strlen("ALL_TOUCHED=TRUE") + 1));
1217 strcpy(options[options_len - 1], "ALL_TOUCHED=TRUE");
1218 }
1219
1220 if (options_len) {
1221 options_len++;
1222 options = (char **) repalloc(options, sizeof(char *) * options_len);
1223 options[options_len - 1] = NULL;
1224 }
1225
1226 /* get geometry's srid */
1227 srid = gserialized_get_srid(gser);
1228
1229 POSTGIS_RT_DEBUGF(3, "RASTER_asRaster: srid = %d", srid);
1230 if (clamp_srid(srid) != SRID_UNKNOWN) {
1231 srs = rtpg_getSR(srid);
1232 if (NULL == srs) {
1233
1234 if (pixtypes_len) pfree(pixtypes);
1235 if (values_len) pfree(values);
1236 if (nodatavals_len) {
1237 pfree(hasnodatas);
1238 pfree(nodatavals);
1239 }
1240 if (options_len) pfree(options);
1241
1242 lwgeom_free(geom);
1243 PG_FREE_IF_COPY(gser, 0);
1244
1245 elog(ERROR, "RASTER_asRaster: Could not find srtext for SRID (%d)", srid);
1246 PG_RETURN_NULL();
1247 }
1248 POSTGIS_RT_DEBUGF(3, "RASTER_asRaster: srs is %s", srs);
1249 }
1250 else
1251 srs = NULL;
1252
1253 /* determine number of bands */
1254 /* MIN macro is from GDAL's cpl_port.h */
1255 num_bands = MIN(pixtypes_len, values_len);
1256 num_bands = MIN(num_bands, nodatavals_len);
1257 POSTGIS_RT_DEBUGF(3, "RASTER_asRaster: pixtypes_len = %d", pixtypes_len);
1258 POSTGIS_RT_DEBUGF(3, "RASTER_asRaster: values_len = %d", values_len);
1259 POSTGIS_RT_DEBUGF(3, "RASTER_asRaster: nodatavals_len = %d", nodatavals_len);
1260 POSTGIS_RT_DEBUGF(3, "RASTER_asRaster: num_bands = %d", num_bands);
1261
1262 /* warn of imbalanced number of band elements */
1263 if (!(
1264 (pixtypes_len == values_len) &&
1265 (values_len == nodatavals_len)
1266 )) {
1267 elog(
1268 NOTICE,
1269 "Imbalanced number of values provided for pixeltype (%d), value (%d) and nodataval (%d). Using the first %d values of each parameter",
1270 pixtypes_len,
1271 values_len,
1272 nodatavals_len,
1273 num_bands
1274 );
1275 }
1276
1277 /* get wkb of geometry */
1278 POSTGIS_RT_DEBUG(3, "RASTER_asRaster: getting wkb of geometry");
1279 wkb = lwgeom_to_wkb(geom, variant, &wkb_len);
1280 lwgeom_free(geom);
1281 PG_FREE_IF_COPY(gser, 0);
1282
1283 /* rasterize geometry */
1284 POSTGIS_RT_DEBUG(3, "RASTER_asRaster: rasterizing geometry");
1285 /* use nodatavals for the init parameter */
1286 rast = rt_raster_gdal_rasterize(wkb,
1287 (uint32_t) wkb_len, srs,
1288 num_bands, pixtypes,
1289 nodatavals, values,
1290 nodatavals, hasnodatas,
1291 dim_x, dim_y,
1292 scale_x, scale_y,
1293 ul_xw, ul_yw,
1294 grid_xw, grid_yw,
1295 skew_x, skew_y,
1296 options
1297 );
1298
1299 if (pixtypes_len) pfree(pixtypes);
1300 if (values_len) pfree(values);
1301 if (nodatavals_len) {
1302 pfree(hasnodatas);
1303 pfree(nodatavals);
1304 }
1305 if (options_len) pfree(options);
1306
1307 if (!rast) {
1308 elog(ERROR, "RASTER_asRaster: Could not rasterize geometry");
1309 PG_RETURN_NULL();
1310 }
1311
1312 /* add target srid */
1313 rt_raster_set_srid(rast, srid);
1314
1315 pgrast = rt_raster_serialize(rast);
1316 rt_raster_destroy(rast);
1317
1318 if (NULL == pgrast) PG_RETURN_NULL();
1319
1320 POSTGIS_RT_DEBUG(3, "RASTER_asRaster: done");
1321
1322 SET_VARSIZE(pgrast, pgrast->size);
1323 PG_RETURN_POINTER(pgrast);
1324}
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 *g)
Extract the SRID from the serialized form (it is packed into three bytes so this is a handy function)...
GSERIALIZED * gserialized_from_lwgeom(LWGEOM *geom, size_t *size)
Allocate a new GSERIALIZED from an LWGEOM.
LWGEOM * lwgeom_from_gserialized(const GSERIALIZED *g)
Allocate a new LWGEOM from a GSERIALIZED.
int lwgeom_ndims(const LWGEOM *geom)
Return the number of dimensions (2, 3, 4) in a geometry.
Definition lwgeom.c:937
void lwgeom_free(LWGEOM *geom)
Definition lwgeom.c:1138
void lwmpoly_free(LWMPOLY *mpoly)
Definition lwmpoly.c:53
LWGEOM * lwgeom_force_2d(const LWGEOM *geom)
Strip out the Z/M components of an LWGEOM.
Definition lwgeom.c:775
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:790
void lwpoly_free(LWPOLY *poly)
Definition lwpoly.c:175
#define SRID_UNKNOWN
Unknown SRID value.
Definition liblwgeom.h:229
LWGEOM * lwmpoly_as_lwgeom(const LWMPOLY *obj)
Definition lwgeom.c:276
LWGEOM * lwpoly_as_lwgeom(const LWPOLY *obj)
Definition lwgeom.c:311
#define WKB_SFSQL
Definition liblwgeom.h:2122
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
#define FLT_NEQ(x, y)
Definition librtcore.h:2234
LWPOLY * rt_raster_pixel_as_polygon(rt_raster raster, int x, int y)
Get a raster pixel as a polygon.
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
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).
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
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...
@ 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:2504
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.
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.
void * rt_raster_serialize(rt_raster raster)
Return this raster in serialized form.
rt_errorstate rt_raster_get_perimeter(rt_raster raster, int nband, LWGEOM **perimeter)
Get raster perimeter.
rt_raster rt_raster_deserialize(void *serialized, int header_only)
Return a raster from a serialized form.
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:193
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)
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:283
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