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