PostGIS 3.7.0dev-r@@SVN_REVISION@@
Loading...
Searching...
No Matches
rt_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 * Copyright (C) 2025 Darafei Praliaskouski <me@komzpa.net>
14 *
15 * This program is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU General Public License
17 * as published by the Free Software Foundation; either version 2
18 * of the License, or (at your option) any later version.
19 *
20 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
24 *
25 * You should have received a copy of the GNU General Public License
26 * along with this program; if not, write to the Free Software Foundation,
27 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
28 *
29 */
30
31#include "librtcore.h"
32#include "librtcore_internal.h"
33#include "rt_serialize.h"
34
35/******************************************************************************
36* rt_raster_perimeter()
37******************************************************************************/
38
39static rt_errorstate
41 uint16_t width = 0;
42 uint16_t height = 0;
43 int x = 0;
44 int y = 0;
45 int offset = 0;
46 int done[4] = {0};
47 double value = 0;
48 int nodata = 0;
49
50 assert(band != NULL);
51 assert(band->raster != NULL);
52 assert(trim != NULL);
53
54 memset(trim, 0, sizeof(uint16_t) * 4);
55
56 width = rt_band_get_width(band);
57 height = rt_band_get_height(band);
58
59 /* top */
60 for (y = 0; y < height; y++) {
61 for (offset = 0; offset < 3; offset++) {
62 /* every third pixel */
63 for (x = offset; x < width; x += 3) {
64 if (rt_band_get_pixel(band, x, y, &value, &nodata) != ES_NONE) {
65 rterror("_rti_raster_get_band_perimeter: Could not get band pixel");
66 return ES_ERROR;
67 }
68
69 RASTER_DEBUGF(4, "top (x, y, value, nodata) = (%d, %d, %f, %d)", x, y, value, nodata);
70 if (!nodata) {
71 trim[0] = y;
72 done[0] = 1;
73 break;
74 }
75 }
76
77 if (done[0])
78 break;
79 }
80
81 if (done[0])
82 break;
83 }
84
85 /* right */
86 for (x = width - 1; x >= 0; x--) {
87 for (offset = 0; offset < 3; offset++) {
88 /* every third pixel */
89 for (y = offset; y < height; y += 3) {
90 if (rt_band_get_pixel(band, x, y, &value, &nodata) != ES_NONE) {
91 rterror("_rti_raster_get_band_perimeter: Could not get band pixel");
92 return ES_ERROR;
93 }
94
95 RASTER_DEBUGF(4, "right (x, y, value, nodata) = (%d, %d, %f, %d)", x, y, value, nodata);
96 if (!nodata) {
97 trim[1] = width - (x + 1);
98 done[1] = 1;
99 break;
100 }
101 }
102
103 if (done[1])
104 break;
105 }
106
107 if (done[1])
108 break;
109 }
110
111 /* bottom */
112 for (y = height - 1; y >= 0; y--) {
113 for (offset = 0; offset < 3; offset++) {
114 /* every third pixel */
115 for (x = offset; x < width; x += 3) {
116 if (rt_band_get_pixel(band, x, y, &value, &nodata) != ES_NONE) {
117 rterror("_rti_raster_get_band_perimeter: Could not get band pixel");
118 return ES_ERROR;
119 }
120
121 RASTER_DEBUGF(4, "bottom (x, y, value, nodata) = (%d, %d, %f, %d)", x, y, value, nodata);
122 if (!nodata) {
123 trim[2] = height - (y + 1);
124 done[2] = 1;
125 break;
126 }
127 }
128
129 if (done[2])
130 break;
131 }
132
133 if (done[2])
134 break;
135 }
136
137 /* left */
138 for (x = 0; x < width; x++) {
139 for (offset = 0; offset < 3; offset++) {
140 /* every third pixel */
141 for (y = offset; y < height; y += 3) {
142 if (rt_band_get_pixel(band, x, y, &value, &nodata) != ES_NONE) {
143 rterror("_rti_raster_get_band_perimeter: Could not get band pixel");
144 return ES_ERROR;
145 }
146
147 RASTER_DEBUGF(4, "left (x, , value, nodata) = (%d, %d, %f, %d)", x, y, value, nodata);
148 if (!nodata) {
149 trim[3] = x;
150 done[3] = 1;
151 break;
152 }
153 }
154
155 if (done[3])
156 break;
157 }
158
159 if (done[3])
160 break;
161 }
162
163 RASTER_DEBUGF(4, "trim = (%d, %d, %d, %d)",
164 trim[0], trim[1], trim[2], trim[3]);
165
166 return ES_NONE;
167}
168
184 rt_raster raster, int nband,
185 LWGEOM **perimeter
186) {
187 rt_band band = NULL;
188 int numband = 0;
189 uint16_t *_nband = NULL;
190 int i = 0;
191 int j = 0;
192 uint16_t _trim[4] = {0};
193 uint16_t trim[4] = {0}; /* top, right, bottom, left */
194 int isset[4] = {0};
195 double gt[6] = {0.0};
196 int32_t srid = SRID_UNKNOWN;
197
198 POINTARRAY *pts = NULL;
199 POINT4D p4d;
200 POINTARRAY **rings = NULL;
201 LWPOLY* poly = NULL;
202
203 assert(perimeter != NULL);
204
205 *perimeter = NULL;
206
207 /* empty raster, no perimeter */
208 if (rt_raster_is_empty(raster))
209 return ES_NONE;
210
211 /* raster metadata */
212 srid = rt_raster_get_srid(raster);
214 numband = rt_raster_get_num_bands(raster);
215
216 RASTER_DEBUGF(3, "rt_raster_get_perimeter: raster is %dx%d", raster->width, raster->height);
217
218 /* nband < 0 means all bands */
219 if (nband >= 0) {
220 if (nband >= numband) {
221 rterror("rt_raster_get_boundary: Band %d not found for raster", nband);
222 return ES_ERROR;
223 }
224
225 numband = 1;
226 }
227 else
228 nband = -1;
229
230 RASTER_DEBUGF(3, "rt_raster_get_perimeter: nband, numband = %d, %d", nband, numband);
231
232 _nband = rtalloc(sizeof(uint16_t) * numband);
233 if (_nband == NULL) {
234 rterror("rt_raster_get_boundary: Could not allocate memory for band indices");
235 return ES_ERROR;
236 }
237
238 if (nband < 0) {
239 for (i = 0; i < numband; i++)
240 _nband[i] = i;
241 }
242 else
243 _nband[0] = nband;
244
245 for (i = 0; i < numband; i++) {
246 band = rt_raster_get_band(raster, _nband[i]);
247 if (band == NULL) {
248 rterror("rt_raster_get_boundary: Could not get band at index %d", _nband[i]);
249 rtdealloc(_nband);
250 return ES_ERROR;
251 }
252
253 /* band is nodata */
254 if (rt_band_get_isnodata_flag(band) != 0)
255 continue;
256
258 rterror("rt_raster_get_boundary: Could not get band perimeter");
259 rtdealloc(_nband);
260 return ES_ERROR;
261 }
262
263 for (j = 0; j < 4; j++) {
264 if (!isset[j] || trim[j] < _trim[j]) {
265 _trim[j] = trim[j];
266 isset[j] = 1;
267 }
268 }
269 }
270
271 /* no longer needed */
272 rtdealloc(_nband);
273
274 /* check isset, just need to check one element */
275 if (!isset[0]) {
276 /* return NULL as bands are empty */
277 return ES_NONE;
278 }
279
280 RASTER_DEBUGF(4, "trim = (%d, %d, %d, %d)",
281 trim[0], trim[1], trim[2], trim[3]);
282
283 /* only one ring */
284 rings = (POINTARRAY **) rtalloc(sizeof (POINTARRAY*));
285 if (!rings) {
286 rterror("rt_raster_get_perimeter: Could not allocate memory for polygon ring");
287 return ES_ERROR;
288 }
289 rings[0] = ptarray_construct(0, 0, 5);
290 if (!rings[0]) {
291 rterror("rt_raster_get_perimeter: Could not construct point array");
292 return ES_ERROR;
293 }
294 pts = rings[0];
295
296 /* Upper-left corner (first and last points) */
298 raster,
299 _trim[3], _trim[0],
300 &p4d.x, &p4d.y,
301 gt
302 );
303 ptarray_set_point4d(pts, 0, &p4d);
304 ptarray_set_point4d(pts, 4, &p4d);
305
306 /* Upper-right corner (we go clockwise) */
308 raster,
309 raster->width - _trim[1], _trim[0],
310 &p4d.x, &p4d.y,
311 gt
312 );
313 ptarray_set_point4d(pts, 1, &p4d);
314
315 /* Lower-right corner */
317 raster,
318 raster->width - _trim[1], raster->height - _trim[2],
319 &p4d.x, &p4d.y,
320 gt
321 );
322 ptarray_set_point4d(pts, 2, &p4d);
323
324 /* Lower-left corner */
326 raster,
327 _trim[3], raster->height - _trim[2],
328 &p4d.x, &p4d.y,
329 gt
330 );
331 ptarray_set_point4d(pts, 3, &p4d);
332
333 poly = lwpoly_construct(srid, 0, 1, rings);
334 *perimeter = lwpoly_as_lwgeom(poly);
335
336 return ES_NONE;
337}
338
339/******************************************************************************
340* rt_raster_surface()
341******************************************************************************/
342
356rt_errorstate rt_raster_surface(rt_raster raster, int nband, LWMPOLY **surface) {
357 rt_band band = NULL;
358 LWGEOM *mpoly = NULL;
359 LWGEOM *tmp = NULL;
360 LWGEOM *clone = NULL;
361 rt_geomval gv = NULL;
362 int gvcount = 0;
363 GEOSGeometry *gc = NULL;
364 GEOSGeometry *gunion = NULL;
365 GEOSGeometry **geoms = NULL;
366 int geomscount = 0;
367 int i = 0;
368
369 assert(surface != NULL);
370
371 /* init *surface to NULL */
372 *surface = NULL;
373
374 /* raster is empty, surface = NULL */
375 if (rt_raster_is_empty(raster))
376 return ES_NONE;
377
378 /* if nband < 0, return the convex hull as a multipolygon */
379 if (nband < 0) {
380 /*
381 lwgeom_as_multi() only does a shallow clone internally
382 so input and output geometries may share memory
383 hence the deep clone of the output geometry for returning
384 is the only way to guarantee the memory isn't shared
385 */
386 if (rt_raster_get_convex_hull(raster, &tmp) != ES_NONE) {
387 rterror("rt_raster_surface: Could not get convex hull of raster");
388 return ES_ERROR;
389 }
390 mpoly = lwgeom_as_multi(tmp);
391 clone = lwgeom_clone_deep(mpoly);
392 lwgeom_free(tmp);
393 lwgeom_free(mpoly);
394
395 *surface = lwgeom_as_lwmpoly(clone);
396 return ES_NONE;
397 }
398 /* check that nband is valid */
399 else if (nband >= rt_raster_get_num_bands(raster)) {
400 rterror("rt_raster_surface: The band index %d is invalid", nband);
401 return ES_ERROR;
402 }
403
404 /* get band */
405 band = rt_raster_get_band(raster, nband);
406 if (band == NULL) {
407 rterror("rt_raster_surface: Error getting band %d from raster", nband);
408 return ES_ERROR;
409 }
410
411 /* band does not have a NODATA flag, return convex hull */
412 if (!rt_band_get_hasnodata_flag(band)) {
413 /*
414 lwgeom_as_multi() only does a shallow clone internally
415 so input and output geometries may share memory
416 hence the deep clone of the output geometry for returning
417 is the only way to guarantee the memory isn't shared
418 */
419 if (rt_raster_get_convex_hull(raster, &tmp) != ES_NONE) {
420 rterror("rt_raster_surface: Could not get convex hull of raster");
421 return ES_ERROR;
422 }
423 mpoly = lwgeom_as_multi(tmp);
424 clone = lwgeom_clone_deep(mpoly);
425 lwgeom_free(tmp);
426 lwgeom_free(mpoly);
427
428 *surface = lwgeom_as_lwmpoly(clone);
429 return ES_NONE;
430 }
431 /* band is NODATA, return NULL */
432 else if (rt_band_get_isnodata_flag(band)) {
433 RASTER_DEBUG(3, "Band is NODATA. Returning NULL");
434 return ES_NONE;
435 }
436
437 /* use gdal polygonize */
438 gv = rt_raster_gdal_polygonize(raster, nband, 1, &gvcount);
439 /* no polygons returned */
440 if (gvcount < 1) {
441 RASTER_DEBUG(3, "All pixels of band are NODATA. Returning NULL");
442 if (gv != NULL) rtdealloc(gv);
443 return ES_NONE;
444 }
445 /* more than 1 polygon */
446 else if (gvcount > 1) {
447 /* convert LWPOLY to GEOSGeometry */
448 geomscount = gvcount;
449 geoms = rtalloc(sizeof(GEOSGeometry *) * geomscount);
450 if (geoms == NULL) {
451 rterror("rt_raster_surface: Could not allocate memory for pixel polygons as GEOSGeometry");
452 for (i = 0; i < gvcount; i++) lwpoly_free(gv[i].geom);
453 rtdealloc(gv);
454 return ES_ERROR;
455 }
456 for (i = 0; i < gvcount; i++) {
457#if POSTGIS_DEBUG_LEVEL > 3
458 {
459 char *wkt = lwgeom_to_wkt(lwpoly_as_lwgeom(gv[i].geom), WKT_ISO, DBL_DIG, NULL);
460 RASTER_DEBUGF(4, "geom %d = %s", i, wkt);
461 rtdealloc(wkt);
462 }
463#endif
464
465 geoms[i] = LWGEOM2GEOS(lwpoly_as_lwgeom(gv[i].geom), 0);
466 lwpoly_free(gv[i].geom);
467 }
468 rtdealloc(gv);
469
470 /* create geometry collection */
471 gc = GEOSGeom_createCollection(GEOS_GEOMETRYCOLLECTION, geoms, geomscount);
472
473 if (gc == NULL) {
474 rterror("rt_raster_surface: Could not create GEOS GEOMETRYCOLLECTION from set of pixel polygons");
475
476 for (i = 0; i < geomscount; i++)
477 GEOSGeom_destroy(geoms[i]);
478 rtdealloc(geoms);
479 return ES_ERROR;
480 }
481
482 /* run the union */
483 gunion = GEOSUnaryUnion(gc);
484
485 GEOSGeom_destroy(gc);
486 rtdealloc(geoms);
487
488 if (gunion == NULL) {
489 rterror("rt_raster_surface: Could not union the pixel polygons using GEOSUnaryUnion()");
490 return ES_ERROR;
491 }
492
493 /* convert union result from GEOSGeometry to LWGEOM */
494 mpoly = GEOS2LWGEOM(gunion, 0);
495
496 /*
497 is geometry valid?
498 if not, try to make valid
499 */
500 do {
501 LWGEOM *mpolyValid = NULL;
502
503 if (GEOSisValid(gunion))
504 break;
505
506 /* make geometry valid */
507 mpolyValid = lwgeom_make_valid(mpoly);
508 if (mpolyValid == NULL) {
509 rtwarn("Cannot fix invalid geometry");
510 break;
511 }
512
513 lwgeom_free(mpoly);
514 mpoly = mpolyValid;
515 }
516 while (0);
517
518 GEOSGeom_destroy(gunion);
519 }
520 else {
521 mpoly = lwpoly_as_lwgeom(gv[0].geom);
522 rtdealloc(gv);
523
524#if POSTGIS_DEBUG_LEVEL > 3
525 {
526 char *wkt = lwgeom_to_wkt(mpoly, WKT_ISO, DBL_DIG, NULL);
527 RASTER_DEBUGF(4, "geom 0 = %s", wkt);
528 rtdealloc(wkt);
529 }
530#endif
531 }
532
533 /* specify SRID */
534 lwgeom_set_srid(mpoly, rt_raster_get_srid(raster));
535
536 if (mpoly != NULL) {
537 /* convert to multi */
538 if (!lwgeom_is_collection(mpoly)) {
539 tmp = mpoly;
540
541#if POSTGIS_DEBUG_LEVEL > 3
542 {
543 char *wkt = lwgeom_to_wkt(mpoly, WKT_ISO, DBL_DIG, NULL);
544 RASTER_DEBUGF(4, "before multi = %s", wkt);
545 rtdealloc(wkt);
546 }
547#endif
548
549 RASTER_DEBUGF(4, "mpoly @ %p", mpoly);
550
551 /*
552 lwgeom_as_multi() only does a shallow clone internally
553 so input and output geometries may share memory
554 hence the deep clone of the output geometry for returning
555 is the only way to guarantee the memory isn't shared
556 */
557 mpoly = lwgeom_as_multi(tmp);
558 clone = lwgeom_clone_deep(mpoly);
559 lwgeom_free(tmp);
560 lwgeom_free(mpoly);
561 mpoly = clone;
562
563 RASTER_DEBUGF(4, "mpoly @ %p", mpoly);
564
565#if POSTGIS_DEBUG_LEVEL > 3
566 {
567 char *wkt = lwgeom_to_wkt(mpoly, WKT_ISO, DBL_DIG, NULL);
568 RASTER_DEBUGF(4, "after multi = %s", wkt);
569 rtdealloc(wkt);
570 }
571#endif
572 }
573
574#if POSTGIS_DEBUG_LEVEL > 3
575 {
576 char *wkt = lwgeom_to_wkt(mpoly, WKT_ISO, DBL_DIG, NULL);
577 RASTER_DEBUGF(4, "returning geometry = %s", wkt);
578 rtdealloc(wkt);
579 }
580#endif
581
582 *surface = lwgeom_as_lwmpoly(mpoly);
583 return ES_NONE;
584 }
585
586 return ES_NONE;
587}
588
589/******************************************************************************
590* rt_raster_pixel_as_polygon()
591******************************************************************************/
592
607LWPOLY*
609{
610 double scale_x, scale_y;
611 double skew_x, skew_y;
612 double ul_x, ul_y;
613 int32_t srid;
614 POINTARRAY **points;
615 POINT4D p, p0;
616 LWPOLY *poly;
617
618 assert(rast != NULL);
619
620 scale_x = rt_raster_get_x_scale(rast);
621 scale_y = rt_raster_get_y_scale(rast);
622 skew_x = rt_raster_get_x_skew(rast);
623 skew_y = rt_raster_get_y_skew(rast);
624 ul_x = rt_raster_get_x_offset(rast);
625 ul_y = rt_raster_get_y_offset(rast);
626 srid = rt_raster_get_srid(rast);
627
628 points = rtalloc(sizeof(POINTARRAY *)*1);
629 points[0] = ptarray_construct(0, 0, 5);
630
631 p0.x = scale_x * x + skew_x * y + ul_x;
632 p0.y = scale_y * y + skew_y * x + ul_y;
633 ptarray_set_point4d(points[0], 0, &p0);
634
635 p.x = p0.x + scale_x;
636 p.y = p0.y + skew_y;
637 ptarray_set_point4d(points[0], 1, &p);
638
639 p.x = p0.x + scale_x + skew_x;
640 p.y = p0.y + scale_y + skew_y;
641 ptarray_set_point4d(points[0], 2, &p);
642
643 p.x = p0.x + skew_x;
644 p.y = p0.y + scale_y;
645 ptarray_set_point4d(points[0], 3, &p);
646
647 /* close it */
648 ptarray_set_point4d(points[0], 4, &p0);
649
650 poly = lwpoly_construct(srid, NULL, 1, points);
651
652 return poly;
653}
654
655/******************************************************************************
656* rt_raster_pixel_as_centroid_point()
657******************************************************************************/
658
668LWPOINT*
670{
671 double scale_x, scale_y;
672 double skew_x, skew_y;
673 double ul_x, ul_y;
674 int32_t srid;
675 double center_x, center_y;
676 LWPOINT* point;
677
678 scale_x = rt_raster_get_x_scale(rast);
679 scale_y = rt_raster_get_y_scale(rast);
680 skew_x = rt_raster_get_x_skew(rast);
681 skew_y = rt_raster_get_y_skew(rast);
682 ul_x = rt_raster_get_x_offset(rast);
683 ul_y = rt_raster_get_y_offset(rast);
684 srid = rt_raster_get_srid(rast);
685
686 center_x = scale_x * x + skew_x * y + ul_x + (scale_x + skew_x) * 0.5;
687 center_y = scale_y * y + skew_y * x + ul_y + (scale_y + skew_y) * 0.5;
688 point = lwpoint_make2d(srid, center_x, center_y);
689
690 return point;
691}
692
693/******************************************************************************
694* rt_raster_get_envelope_geom()
695******************************************************************************/
696
707 double gt[6] = {0.0};
708 int32_t srid = SRID_UNKNOWN;
709
710 POINTARRAY *pts = NULL;
711 POINT4D p4d;
712
713 assert(env != NULL);
714 *env = NULL;
715
716 /* raster is NULL, envelope is NULL */
717 if (raster == NULL)
718 return ES_NONE;
719
720 /* raster metadata */
721 srid = rt_raster_get_srid(raster);
723
725 3,
726 "rt_raster_get_envelope: raster is %dx%d",
727 raster->width,
728 raster->height
729 );
730
731 /* return point or line since at least one of the two dimensions is 0 */
732 if ((!raster->width) || (!raster->height)) {
733 p4d.x = gt[0];
734 p4d.y = gt[3];
735
736 /* return point */
737 if (!raster->width && !raster->height) {
738 LWPOINT *point = lwpoint_make2d(srid, p4d.x, p4d.y);
739 *env = lwpoint_as_lwgeom(point);
740 }
741 /* return linestring */
742 else {
743 LWLINE *line = NULL;
744 pts = ptarray_construct_empty(0, 0, 2);
745
746 /* first point of line */
747 ptarray_append_point(pts, &p4d, LW_TRUE);
748
749 /* second point of line */
751 raster,
753 &p4d.x, &p4d.y,
754 gt
755 ) != ES_NONE) {
756 rterror("rt_raster_get_envelope: Could not get second point for linestring");
757 return ES_ERROR;
758 }
759 ptarray_append_point(pts, &p4d, LW_TRUE);
760 line = lwline_construct(srid, NULL, pts);
761
762 *env = lwline_as_lwgeom(line);
763 }
764
765 return ES_NONE;
766 }
767 else {
768 rt_envelope rtenv;
769 int err = ES_NONE;
770 POINTARRAY **rings = NULL;
771 LWPOLY* poly = NULL;
772
773 /* only one ring */
774 rings = (POINTARRAY **) rtalloc(sizeof (POINTARRAY*));
775 if (!rings) {
776 rterror("rt_raster_get_envelope_geom: Could not allocate memory for polygon ring");
777 return ES_ERROR;
778 }
779 rings[0] = ptarray_construct(0, 0, 5);
780 if (!rings[0]) {
781 rterror("rt_raster_get_envelope_geom: Could not construct point array");
782 return ES_ERROR;
783 }
784 pts = rings[0];
785
786 err = rt_raster_get_envelope(raster, &rtenv);
787 if (err != ES_NONE) {
788 rterror("rt_raster_get_envelope_geom: Could not get raster envelope");
789 return err;
790 }
791
792 /* build ring */
793
794 /* minx, maxy */
795 p4d.x = rtenv.MinX;
796 p4d.y = rtenv.MaxY;
797 ptarray_set_point4d(pts, 0, &p4d);
798 ptarray_set_point4d(pts, 4, &p4d);
799
800 /* maxx, maxy */
801 p4d.x = rtenv.MaxX;
802 p4d.y = rtenv.MaxY;
803 ptarray_set_point4d(pts, 1, &p4d);
804
805 /* maxx, miny */
806 p4d.x = rtenv.MaxX;
807 p4d.y = rtenv.MinY;
808 ptarray_set_point4d(pts, 2, &p4d);
809
810 /* minx, miny */
811 p4d.x = rtenv.MinX;
812 p4d.y = rtenv.MinY;
813 ptarray_set_point4d(pts, 3, &p4d);
814
815 poly = lwpoly_construct(srid, 0, 1, rings);
816 *env = lwpoly_as_lwgeom(poly);
817 }
818
819 return ES_NONE;
820}
821
822/******************************************************************************
823* rt_raster_get_convex_hull()
824******************************************************************************/
825
840 double gt[6] = {0.0};
841 int32_t srid = SRID_UNKNOWN;
842
843 POINTARRAY *pts = NULL;
844 POINT4D p4d;
845
846 assert(hull != NULL);
847 *hull = NULL;
848
849 /* raster is NULL, convex hull is NULL */
850 if (raster == NULL)
851 return ES_NONE;
852
853 /* raster metadata */
854 srid = rt_raster_get_srid(raster);
856
857 RASTER_DEBUGF(3, "rt_raster_get_convex_hull: raster is %dx%d", raster->width, raster->height);
858
859 /* return point or line since at least one of the two dimensions is 0 */
860 if ((!raster->width) || (!raster->height)) {
861 p4d.x = gt[0];
862 p4d.y = gt[3];
863
864 /* return point */
865 if (!raster->width && !raster->height) {
866 LWPOINT *point = lwpoint_make2d(srid, p4d.x, p4d.y);
867 *hull = lwpoint_as_lwgeom(point);
868 }
869 /* return linestring */
870 else {
871 LWLINE *line = NULL;
872 pts = ptarray_construct_empty(0, 0, 2);
873
874 /* first point of line */
875 ptarray_append_point(pts, &p4d, LW_TRUE);
876
877 /* second point of line */
879 raster,
881 &p4d.x, &p4d.y,
882 gt
883 ) != ES_NONE) {
884 rterror("rt_raster_get_convex_hull: Could not get second point for linestring");
885 return ES_ERROR;
886 }
887 ptarray_append_point(pts, &p4d, LW_TRUE);
888 line = lwline_construct(srid, NULL, pts);
889
890 *hull = lwline_as_lwgeom(line);
891 }
892
893 return ES_NONE;
894 }
895 else {
896 POINTARRAY **rings = NULL;
897 LWPOLY* poly = NULL;
898
899 /* only one ring */
900 rings = (POINTARRAY **) rtalloc(sizeof (POINTARRAY*));
901 if (!rings) {
902 rterror("rt_raster_get_convex_hull: Could not allocate memory for polygon ring");
903 return ES_ERROR;
904 }
905 rings[0] = ptarray_construct(0, 0, 5);
906 /* TODO: handle error on ptarray construction */
907 /* XXX jorgearevalo: the error conditions aren't managed in ptarray_construct */
908 if (!rings[0]) {
909 rterror("rt_raster_get_convex_hull: Could not construct point array");
910 return ES_ERROR;
911 }
912 pts = rings[0];
913
914 /* Upper-left corner (first and last points) */
915 p4d.x = gt[0];
916 p4d.y = gt[3];
917 ptarray_set_point4d(pts, 0, &p4d);
918 ptarray_set_point4d(pts, 4, &p4d);
919
920 /* Upper-right corner (we go clockwise) */
922 raster,
923 raster->width, 0,
924 &p4d.x, &p4d.y,
925 gt
926 );
927 ptarray_set_point4d(pts, 1, &p4d);
928
929 /* Lower-right corner */
931 raster,
932 raster->width, raster->height,
933 &p4d.x, &p4d.y,
934 gt
935 );
936 ptarray_set_point4d(pts, 2, &p4d);
937
938 /* Lower-left corner */
940 raster,
941 0, raster->height,
942 &p4d.x, &p4d.y,
943 gt
944 );
945 ptarray_set_point4d(pts, 3, &p4d);
946
947 poly = lwpoly_construct(srid, 0, 1, rings);
948 *hull = lwpoly_as_lwgeom(poly);
949 }
950
951 return ES_NONE;
952}
953
954/******************************************************************************
955* rt_raster_gdal_polygonize()
956******************************************************************************/
957
977 rt_raster raster, int nband,
978 int exclude_nodata_value,
979 int *pnElements
980) {
981 CPLErr cplerr = CE_None;
982 char *pszQuery;
983 long j;
984 OGRSFDriverH ogr_drv = NULL;
985 GDALDriverH gdal_drv = NULL;
986 int destroy_gdal_drv = 0;
987 GDALDatasetH memdataset = NULL;
988 GDALRasterBandH gdal_band = NULL;
989 OGRDataSourceH memdatasource = NULL;
990 rt_geomval pols = NULL;
991 OGRLayerH hLayer = NULL;
992 OGRFeatureH hFeature = NULL;
993 OGRGeometryH hGeom = NULL;
994 OGRFieldDefnH hFldDfn = NULL;
995 unsigned char *wkb = NULL;
996 int wkbsize = 0;
997 LWGEOM *lwgeom = NULL;
998 int nFeatureCount = 0;
999 rt_band band = NULL;
1000 int iPixVal = -1;
1001 double dValue = 0.0;
1002 int iBandHasNodataValue = FALSE;
1003 double dBandNoData = 0.0;
1004
1005 uint32_t bandNums[1] = {nband};
1006 int excludeNodataValues[1] = {exclude_nodata_value};
1007
1008 /* checks */
1009 assert(NULL != raster);
1010 assert(NULL != pnElements);
1011
1012 RASTER_DEBUG(2, "In rt_raster_gdal_polygonize");
1013
1014 *pnElements = 0;
1015
1016 /*******************************
1017 * Get band
1018 *******************************/
1019 band = rt_raster_get_band(raster, nband);
1020 if (NULL == band) {
1021 rterror("rt_raster_gdal_polygonize: Error getting band %d from raster", nband);
1022 return NULL;
1023 }
1024
1025 if (exclude_nodata_value) {
1026
1027 /* band is NODATA */
1028 if (rt_band_get_isnodata_flag(band)) {
1029 RASTER_DEBUG(3, "Band is NODATA. Returning null");
1030 *pnElements = 0;
1031 return NULL;
1032 }
1033
1034 iBandHasNodataValue = rt_band_get_hasnodata_flag(band);
1035 if (iBandHasNodataValue)
1036 rt_band_get_nodata(band, &dBandNoData);
1037 else
1038 exclude_nodata_value = FALSE;
1039 }
1040
1041 /*****************************************************
1042 * Convert raster to GDAL MEM dataset
1043 *****************************************************/
1044 memdataset = rt_raster_to_gdal_mem(raster, NULL, bandNums, excludeNodataValues, 1, &gdal_drv, &destroy_gdal_drv);
1045 if (NULL == memdataset) {
1046 rterror("rt_raster_gdal_polygonize: Couldn't convert raster to GDAL MEM dataset");
1047 return NULL;
1048 }
1049
1050 /*****************************
1051 * Register ogr mem driver
1052 *****************************/
1053#ifdef GDAL_DCAP_RASTER
1054 /* in GDAL 2.0, OGRRegisterAll() is an alias to GDALAllRegister() */
1056#else
1057 OGRRegisterAll();
1058#endif
1059
1060 RASTER_DEBUG(3, "creating OGR MEM vector");
1061
1062 /*****************************************************
1063 * Create an OGR in-memory vector for layers
1064 *****************************************************/
1065 ogr_drv = OGRGetDriverByName("Memory");
1066 memdatasource = OGR_Dr_CreateDataSource(ogr_drv, "", NULL);
1067 if (NULL == memdatasource) {
1068 rterror("rt_raster_gdal_polygonize: Couldn't create a OGR Datasource to store pols");
1069 GDALClose(memdataset);
1070 if (destroy_gdal_drv) GDALDestroyDriver(gdal_drv);
1071 return NULL;
1072 }
1073
1074 /* Can MEM driver create new layers? */
1075 if (!OGR_DS_TestCapability(memdatasource, ODsCCreateLayer)) {
1076 rterror("rt_raster_gdal_polygonize: MEM driver can't create new layers, aborting");
1077
1078 /* xxx jorgearevalo: what should we do now? */
1079 GDALClose(memdataset);
1080 if (destroy_gdal_drv) GDALDestroyDriver(gdal_drv);
1081 OGRReleaseDataSource(memdatasource);
1082
1083 return NULL;
1084 }
1085
1086 RASTER_DEBUG(3, "polygonizying GDAL MEM raster band");
1087
1088 /*****************************
1089 * Polygonize the raster band
1090 *****************************/
1091
1097 hLayer = OGR_DS_CreateLayer(memdatasource, "PolygonizedLayer", NULL, wkbPolygon, NULL);
1098
1099 if (NULL == hLayer) {
1100 rterror("rt_raster_gdal_polygonize: Couldn't create layer to store polygons");
1101
1102 GDALClose(memdataset);
1103 if (destroy_gdal_drv) GDALDestroyDriver(gdal_drv);
1104 OGRReleaseDataSource(memdatasource);
1105
1106 return NULL;
1107 }
1108
1113 /* First, create a field definition to create the field */
1114 hFldDfn = OGR_Fld_Create("PixelValue", OFTReal);
1115
1116 /* Second, create the field */
1117 if (OGR_L_CreateField(hLayer, hFldDfn, TRUE) != OGRERR_NONE) {
1118 rtwarn("Couldn't create a field in OGR Layer. The polygons generated won't be able to store the pixel value");
1119 iPixVal = -1;
1120 }
1121 else {
1122 /* Index to the new field created in the layer */
1123 iPixVal = 0;
1124 }
1125
1126 /* Get GDAL raster band */
1127 gdal_band = GDALGetRasterBand(memdataset, 1);
1128 if (NULL == gdal_band) {
1129 rterror("rt_raster_gdal_polygonize: Couldn't get GDAL band to polygonize");
1130
1131 GDALClose(memdataset);
1132 if (destroy_gdal_drv) GDALDestroyDriver(gdal_drv);
1133 OGR_Fld_Destroy(hFldDfn);
1134 OGR_DS_DeleteLayer(memdatasource, 0);
1135 OGRReleaseDataSource(memdatasource);
1136
1137 return NULL;
1138 }
1139
1140 /*
1141 * Why: We pass the shared interrupt-aware progress callback so GDAL can
1142 * unwind promptly when PostgreSQL requests cancellation (#4222).
1143 */
1144 cplerr = GDALFPolygonize(
1145 gdal_band, NULL, hLayer, iPixVal, NULL, rt_util_gdal_progress_func, (void *)"GDALFPolygonize");
1146
1147 if (cplerr != CE_None) {
1148 rterror("rt_raster_gdal_polygonize: Could not polygonize GDAL band");
1149
1150 GDALClose(memdataset);
1151 if (destroy_gdal_drv) GDALDestroyDriver(gdal_drv);
1152 OGR_Fld_Destroy(hFldDfn);
1153 OGR_DS_DeleteLayer(memdatasource, 0);
1154 OGRReleaseDataSource(memdatasource);
1155
1156 return NULL;
1157 }
1158
1165 if (iBandHasNodataValue) {
1166 size_t sz = 50 * sizeof (char);
1167 pszQuery = (char *) rtalloc(sz);
1168 snprintf(pszQuery, sz, "PixelValue != %f", dBandNoData );
1169 OGRErr e = OGR_L_SetAttributeFilter(hLayer, pszQuery);
1170 if (e != OGRERR_NONE) {
1171 rtwarn("Error filtering NODATA values for band. All values will be treated as data values");
1172 }
1173 }
1174 else {
1175 pszQuery = NULL;
1176 }
1177
1178 /*********************************************************************
1179 * Transform OGR layers to WKB polygons
1180 * XXX jorgearevalo: GDALPolygonize does not set the coordinate system
1181 * on the output layer. Application code should do this when the layer
1182 * is created, presumably matching the raster coordinate system.
1183 *********************************************************************/
1184 nFeatureCount = OGR_L_GetFeatureCount(hLayer, TRUE);
1185
1186 /* Allocate memory for pols */
1187 pols = (rt_geomval) rtalloc(nFeatureCount * sizeof(struct rt_geomval_t));
1188
1189 if (NULL == pols) {
1190 rterror("rt_raster_gdal_polygonize: Could not allocate memory for geomval set");
1191
1192 GDALClose(memdataset);
1193 if (destroy_gdal_drv) GDALDestroyDriver(gdal_drv);
1194 OGR_Fld_Destroy(hFldDfn);
1195 OGR_DS_DeleteLayer(memdatasource, 0);
1196 if (NULL != pszQuery)
1197 rtdealloc(pszQuery);
1198 OGRReleaseDataSource(memdatasource);
1199
1200 return NULL;
1201 }
1202
1203 /* initialize GEOS */
1204 initGEOS(rtinfo, lwgeom_geos_error);
1205
1206 RASTER_DEBUGF(3, "storing polygons (%d)", nFeatureCount);
1207
1208 /* Reset feature reading to start in the first feature */
1209 OGR_L_ResetReading(hLayer);
1210
1211 for (j = 0; j < nFeatureCount; j++) {
1212 hFeature = OGR_L_GetNextFeature(hLayer);
1213 dValue = OGR_F_GetFieldAsDouble(hFeature, iPixVal);
1214
1215 hGeom = OGR_F_GetGeometryRef(hFeature);
1216 wkbsize = OGR_G_WkbSize(hGeom);
1217
1218 /* allocate wkb buffer */
1219 wkb = rtalloc(sizeof(unsigned char) * wkbsize);
1220 if (wkb == NULL) {
1221 rterror("rt_raster_gdal_polygonize: Could not allocate memory for WKB buffer");
1222
1223 OGR_F_Destroy(hFeature);
1224 GDALClose(memdataset);
1225 if (destroy_gdal_drv) GDALDestroyDriver(gdal_drv);
1226 OGR_Fld_Destroy(hFldDfn);
1227 OGR_DS_DeleteLayer(memdatasource, 0);
1228 if (NULL != pszQuery)
1229 rtdealloc(pszQuery);
1230 OGRReleaseDataSource(memdatasource);
1231
1232 return NULL;
1233 }
1234
1235 /* export WKB with LSB byte order */
1236 OGR_G_ExportToWkb(hGeom, wkbNDR, wkb);
1237
1238 /* convert WKB to LWGEOM */
1239 lwgeom = lwgeom_from_wkb(wkb, wkbsize, LW_PARSER_CHECK_NONE);
1240 if (!lwgeom) rterror("%s: invalid wkb", __func__);
1241
1242#if POSTGIS_DEBUG_LEVEL > 3
1243 {
1244 char *wkt = NULL;
1245 OGR_G_ExportToWkt(hGeom, &wkt);
1246 RASTER_DEBUGF(4, "GDAL wkt = %s", wkt);
1247 CPLFree(wkt);
1248
1249 d_print_binary_hex("GDAL wkb", wkb, wkbsize);
1250 }
1251#endif
1252
1253 /* cleanup unnecessary stuff */
1254 rtdealloc(wkb);
1255 wkb = NULL;
1256 wkbsize = 0;
1257
1258 OGR_F_Destroy(hFeature);
1259
1260 /* specify SRID */
1261 lwgeom_set_srid(lwgeom, rt_raster_get_srid(raster));
1262
1263 /* save lwgeom */
1264 pols[j].geom = lwgeom_as_lwpoly(lwgeom);
1265
1266#if POSTGIS_DEBUG_LEVEL > 3
1267 {
1268 char *wkt = lwgeom_to_wkt(lwgeom, WKT_ISO, DBL_DIG, NULL);
1269 RASTER_DEBUGF(4, "LWGEOM wkt = %s", wkt);
1270 rtdealloc(wkt);
1271
1273 size_t lwwkbsize = LWSIZE_GET(lwwkb->size) - LWVARHDRSZ;
1274 if (lwwkbsize) {
1275 d_print_binary_hex("LWGEOM wkb", (const uint8_t *)lwwkb->data, lwwkbsize);
1276 rtdealloc(lwwkb);
1277 }
1278 }
1279#endif
1280
1281 /* set pixel value */
1282 pols[j].val = dValue;
1283 }
1284
1285 *pnElements = nFeatureCount;
1286
1287 RASTER_DEBUG(3, "destroying GDAL MEM raster");
1288 GDALClose(memdataset);
1289 if (destroy_gdal_drv) GDALDestroyDriver(gdal_drv);
1290
1291 RASTER_DEBUG(3, "destroying OGR MEM vector");
1292 OGR_Fld_Destroy(hFldDfn);
1293 OGR_DS_DeleteLayer(memdatasource, 0);
1294 if (NULL != pszQuery) rtdealloc(pszQuery);
1295 OGRReleaseDataSource(memdatasource);
1296
1297 return pols;
1298}
1299
#define TRUE
Definition dbfopen.c:73
#define FALSE
Definition dbfopen.c:72
GEOSGeometry * LWGEOM2GEOS(const LWGEOM *lwgeom, uint8_t autofix)
void lwgeom_geos_error(const char *fmt,...)
void(*) LWGEOM GEOS2LWGEOM)(const GEOSGeometry *geom, uint8_t want3d)
LWGEOM * lwpoint_as_lwgeom(const LWPOINT *obj)
Definition lwgeom.c:372
#define WKB_ISO
Definition liblwgeom.h:2210
void lwgeom_set_srid(LWGEOM *geom, int32_t srid)
Set the SRID on an LWGEOM For collections, only the parent gets an SRID, all the children get SRID_UN...
Definition lwgeom.c:1638
#define LWVARHDRSZ
Definition liblwgeom.h:311
void lwgeom_free(LWGEOM *geom)
Definition lwgeom.c:1246
LWGEOM * lwgeom_as_multi(const LWGEOM *lwgeom)
Create a new LWGEOM of the appropriate MULTI* type.
Definition lwgeom.c:408
#define LW_PARSER_CHECK_NONE
Definition liblwgeom.h:2149
#define LWSIZE_GET(varsize)
Macro for reading the size from the GSERIALIZED size attribute.
Definition liblwgeom.h:324
char * lwgeom_to_wkt(const LWGEOM *geom, uint8_t variant, int precision, size_t *size_out)
WKT emitter function.
Definition lwout_wkt.c:708
lwvarlena_t * lwgeom_to_wkb_varlena(const LWGEOM *geom, uint8_t variant)
Definition lwout_wkb.c:851
POINTARRAY * ptarray_construct_empty(char hasz, char hasm, uint32_t maxpoints)
Create a new POINTARRAY with no points.
Definition ptarray.c:59
LWPOLY * lwgeom_as_lwpoly(const LWGEOM *lwgeom)
Definition lwgeom.c:243
LWLINE * lwline_construct(int32_t srid, GBOX *bbox, POINTARRAY *points)
Definition lwline.c:42
LWPOINT * lwpoint_make2d(int32_t srid, double x, double y)
Definition lwpoint.c:163
int lwgeom_is_collection(const LWGEOM *lwgeom)
Determine whether a LWGEOM contains sub-geometries or not This basically just checks that the struct ...
Definition lwgeom.c:1125
LWGEOM * lwline_as_lwgeom(const LWLINE *obj)
Definition lwgeom.c:367
LWMPOLY * lwgeom_as_lwmpoly(const LWGEOM *lwgeom)
Definition lwgeom.c:288
#define WKT_ISO
Definition liblwgeom.h:2219
#define WKB_NDR
Definition liblwgeom.h:2213
LWPOLY * lwpoly_construct(int32_t srid, GBOX *bbox, uint32_t nrings, POINTARRAY **points)
Definition lwpoly.c:43
int ptarray_append_point(POINTARRAY *pa, const POINT4D *pt, int allow_duplicates)
Append a point to the end of an existing POINTARRAY If allow_duplicate is LW_FALSE,...
Definition ptarray.c:147
void lwpoly_free(LWPOLY *poly)
Definition lwpoly.c:175
#define LW_TRUE
Return types for functions with status returns.
Definition liblwgeom.h:93
#define SRID_UNKNOWN
Unknown SRID value.
Definition liblwgeom.h:215
void ptarray_set_point4d(POINTARRAY *pa, uint32_t n, const POINT4D *p4d)
Definition lwgeom_api.c:369
LWGEOM * lwpoly_as_lwgeom(const LWPOLY *obj)
Definition lwgeom.c:357
LWGEOM * lwgeom_from_wkb(const uint8_t *wkb, const size_t wkb_size, const char check)
WKB inputs must have a declared size, to prevent malformed WKB from reading off the end of the memory...
Definition lwin_wkb.c:842
LWGEOM * lwgeom_make_valid(LWGEOM *geom)
Attempts to make an invalid geometries valid w/out losing points.
POINTARRAY * ptarray_construct(char hasz, char hasm, uint32_t npoints)
Construct an empty pointarray, allocating storage and setting the npoints, but not filling in any inf...
Definition ptarray.c:51
LWGEOM * lwgeom_clone_deep(const LWGEOM *lwgeom)
Deep clone an LWGEOM, everything is copied.
Definition lwgeom.c:557
void rterror(const char *fmt,...) __attribute__((format(printf
Wrappers used for reporting errors and info.
void * rtalloc(size_t size)
Wrappers used for managing memory.
Definition rt_context.c:191
uint16_t rt_band_get_width(rt_band band)
Return width of this band.
Definition rt_band.c:799
#define RASTER_DEBUG(level, msg)
Definition librtcore.h:304
rt_errorstate rt_raster_cell_to_geopoint(rt_raster raster, double xr, double yr, double *xw, double *yw, double *gt)
Convert an xr, yr raster point to an xw, yw point on map.
Definition rt_raster.c:637
int32_t rt_raster_get_srid(rt_raster raster)
Get raster's SRID.
Definition rt_raster.c:360
int rt_util_gdal_register_all(int force_register_all)
Definition rt_util.c:444
#define RASTER_DEBUGF(level, msg,...)
Definition librtcore.h:308
double rt_raster_get_x_skew(rt_raster raster)
Get skew about the X axis.
Definition rt_raster.c:185
double rt_raster_get_x_offset(rt_raster raster)
Get raster x offset, in projection units.
Definition rt_raster.c:217
void void rtinfo(const char *fmt,...) __attribute__((format(printf
void void void rtwarn(const char *fmt,...) __attribute__((format(printf
int rt_band_get_hasnodata_flag(rt_band band)
Get hasnodata flag value.
Definition rt_band.c:833
rt_errorstate rt_band_get_pixel(rt_band band, int x, int y, double *value, int *nodata)
Get pixel value.
Definition rt_band.c:1551
int rt_band_get_isnodata_flag(rt_band band)
Get isnodata flag value.
Definition rt_band.c:873
int rt_util_gdal_progress_func(double dfComplete, const char *pszMessage, void *pProgressArg)
Definition rt_gdal.c:66
double rt_raster_get_x_scale(rt_raster raster)
Get scale X in projection units.
Definition rt_raster.c:154
rt_errorstate
Enum definitions.
Definition librtcore.h:181
@ ES_NONE
Definition librtcore.h:182
@ ES_ERROR
Definition librtcore.h:183
uint16_t rt_raster_get_num_bands(rt_raster raster)
Definition rt_raster.c:376
uint16_t rt_raster_get_height(rt_raster raster)
Definition rt_raster.c:133
struct rt_geomval_t * rt_geomval
Definition librtcore.h:150
rt_errorstate rt_band_get_nodata(rt_band band, double *nodata)
Get NODATA value.
Definition rt_band.c:2067
uint16_t rt_raster_get_width(rt_raster raster)
Definition rt_raster.c:125
void rtdealloc(void *mem)
Definition rt_context.c:206
GDALDatasetH rt_raster_to_gdal_mem(rt_raster raster, const char *srs, uint32_t *bandNums, int *excludeNodataValues, int count, GDALDriverH *rtn_drv, int *destroy_rtn_drv)
Return GDAL dataset using GDAL MEM driver from raster.
Definition rt_raster.c:1813
double rt_raster_get_y_scale(rt_raster raster)
Get scale Y in projection units.
Definition rt_raster.c:163
rt_errorstate rt_raster_get_envelope(rt_raster raster, rt_envelope *env)
Get raster's envelope.
Definition rt_raster.c:782
double rt_raster_get_y_skew(rt_raster raster)
Get skew about the Y axis.
Definition rt_raster.c:194
void rt_raster_get_geotransform_matrix(rt_raster raster, double *gt)
Get 6-element array of raster geotransform matrix.
Definition rt_raster.c:588
uint16_t rt_band_get_height(rt_band band)
Return height of this band.
Definition rt_band.c:808
double rt_raster_get_y_offset(rt_raster raster)
Get raster y offset, in projection units.
Definition rt_raster.c:226
int rt_raster_is_empty(rt_raster raster)
Return TRUE if the raster is empty.
Definition rt_raster.c:1240
rt_band rt_raster_get_band(rt_raster raster, int bandNum)
Return Nth band, or NULL if unavailable.
Definition rt_raster.c:385
This library is the generic raster handling section of PostGIS.
static char * trim(const char *input)
rt_errorstate rt_raster_surface(rt_raster raster, int nband, LWMPOLY **surface)
Get a raster as a surface (multipolygon).
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...
LWPOLY * rt_raster_pixel_as_polygon(rt_raster rast, int x, int y)
Get a raster pixel as a polygon.
rt_errorstate rt_raster_get_convex_hull(rt_raster raster, LWGEOM **hull)
Get raster's convex hull.
static rt_errorstate _rti_raster_get_band_perimeter(rt_band band, uint16_t *trim)
Definition rt_geometry.c:40
LWPOINT * rt_raster_pixel_as_centroid_point(rt_raster rast, int x, int y)
Get a raster pixel centroid point.
rt_errorstate rt_raster_get_envelope_geom(rt_raster raster, LWGEOM **env)
Get raster's envelope as a geometry.
rt_errorstate rt_raster_get_perimeter(rt_raster raster, int nband, LWGEOM **perimeter)
Get raster perimeter.
double x
Definition liblwgeom.h:414
double y
Definition liblwgeom.h:414
uint32_t size
Definition liblwgeom.h:307
char data[]
Definition liblwgeom.h:308
double MinX
Definition librtcore.h:167
double MaxX
Definition librtcore.h:168
double MinY
Definition librtcore.h:169
double MaxY
Definition librtcore.h:170
LWPOLY * geom
Definition librtcore.h:2555