PostGIS 3.6.2dev-r@@SVN_REVISION@@
Loading...
Searching...
No Matches
rt_gdal.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) 2021 Paul Ramsey <pramsey@cleverelephant.ca>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2
11 * of the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software Foundation,
20 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 *
22 */
23
24#include "../../postgis_config.h"
25/* #define POSTGIS_DEBUG_LEVEL 4 */
26
27#include "librtcore.h"
28#include "librtcore_internal.h"
29#include "stringbuffer.h"
30
31/******************************************************************************
32* rt_raster_gdal_contour()
33******************************************************************************/
34
35typedef struct
36{
37 struct {
38 GDALDatasetH ds;
39 GDALDriverH drv;
41 } src;
42
43 struct {
44 OGRSFDriverH drv;
45 OGRDataSourceH ds;
46 OGRLayerH lyr;
47 int srid;
48 OGRwkbGeometryType gtype;
49 } dst;
50
52
53
54/* ---------------------------------------------------------------- */
55/* GDAL progress callback for interrupt handling */
56/* ---------------------------------------------------------------- */
57
59 double dfComplete,
60 const char *pszMessage,
61 void *pProgressArg)
62{
63 (void)dfComplete;
64 (void)pszMessage;
65
67 {
68 // rtwarn("%s interrupted at %g", (const char*)pProgressArg, dfComplete);
70 return FALSE;
71 }
72 else
73 return TRUE;
74}
75
76static void
78{
79 memset(arg, 0, sizeof(_rti_contour_arg));
80 return;
81}
82
83
84static int
86{
87 if(arg->src.ds != NULL)
88 GDALClose(arg->src.ds);
89
90 if (arg->src.drv != NULL && arg->src.destroy_drv) {
91 GDALDeregisterDriver(arg->src.drv);
92 GDALDestroyDriver(arg->src.drv);
93 }
94
95 if (arg->dst.ds != NULL)
96 OGR_DS_Destroy(arg->dst.ds);
97
98 return FALSE;
99}
100
101
102
115 /* input parameters */
116 rt_raster src_raster,
117 int src_band,
118 int src_srid,
119 const char* src_srs,
120 double contour_interval,
121 double contour_base,
122 int fixed_level_count,
123 double *fixed_levels,
124 int polygonize,
125 /* output parameters */
126 size_t *ncontours,
127 struct rt_contour_t **contours
128 )
129{
130 CPLErr cplerr;
131 OGRErr ogrerr;
132 GDALRasterBandH hBand;
133 int nfeatures = 0, i = 0;
134 OGRFeatureH hFeat;
135
136 /* For building out options list */
138 char **papszOptList = NULL;
139 const char* elev_field = polygonize ? "ELEV_FIELD_MIN" : "ELEV_FIELD";
140
143
144 /* Load raster into GDAL memory */
145 arg.src.ds = rt_raster_to_gdal_mem(src_raster, src_srs, NULL, NULL, 0, &(arg.src.drv), &(arg.src.destroy_drv));
146 /* Extract the desired band */
147 hBand = GDALGetRasterBand(arg.src.ds, src_band);
148
149 /* Set up the OGR destination data store */
150 arg.dst.srid = src_srid;
151 arg.dst.drv = OGRGetDriverByName("Memory");
152 if (!arg.dst.drv)
153 return _rti_contour_arg_destroy(&arg);
154
155 arg.dst.ds = OGR_Dr_CreateDataSource(arg.dst.drv, "contour_ds", NULL);
156 if (!arg.dst.ds)
157 return _rti_contour_arg_destroy(&arg);
158
159 /* Polygonize is 2.4+ only */
160#if POSTGIS_GDAL_VERSION >= 20400
161 arg.dst.gtype = polygonize ? wkbPolygon : wkbLineString;
162#else
163 arg.dst.gtype = wkbLineString;
164#endif
165
166 /* Layer has geometry, elevation, id */
167 arg.dst.lyr = OGR_DS_CreateLayer(arg.dst.ds, "contours", NULL, arg.dst.gtype, NULL);
168 if (!arg.dst.lyr)
169 return _rti_contour_arg_destroy(&arg);
170
171 /* ID field */
172 OGRFieldDefnH hFldId = OGR_Fld_Create("id", OFTInteger);
173 ogrerr = OGR_L_CreateField(arg.dst.lyr, hFldId, TRUE);
174 if (ogrerr != OGRERR_NONE)
175 return _rti_contour_arg_destroy(&arg);
176
177 /* ELEVATION field */
178 OGRFieldDefnH hFldElevation = OGR_Fld_Create("elevation", OFTReal);
179 ogrerr = OGR_L_CreateField(arg.dst.lyr, hFldElevation, TRUE);
180 if (ogrerr != OGRERR_NONE)
181 return _rti_contour_arg_destroy(&arg);
182
183 int use_no_data = 0;
184 double no_data_value = GDALGetRasterNoDataValue(hBand, &use_no_data);
185
186 // LEVEL_INTERVAL=f
187 // The elevation interval between contours generated.
188 // LEVEL_BASE=f
189 // The "base" relative to which contour intervals are applied. This is normally zero, but could be different. To generate 10m contours at 5, 15, 25, ... the LEVEL_BASE would be 5.
190 // LEVEL_EXP_BASE=f
191 // If greater than 0, contour levels are generated on an exponential scale. Levels will then be generated by LEVEL_EXP_BASE^k where k is a positive integer.
192 // FIXED_LEVELS=f[,f]*
193 // The list of fixed contour levels at which contours should be generated. This option has precedence on LEVEL_INTERVAL
194 // NODATA=f
195 // The value to use as a "nodata" value. That is, a pixel value which should be ignored in generating contours as if the value of the pixel were not known.
196 // ID_FIELD=d
197 // This will be used as a field index to indicate where a unique id should be written for each feature (contour) written.
198 // ELEV_FIELD=d
199 // This will be used as a field index to indicate where the elevation value of the contour should be written. Only used in line contouring mode.
200 // ELEV_FIELD_MIN=d
201 // This will be used as a field index to indicate where the minimum elevation value of the polygon contour should be written. Only used in polygonal contouring mode.
202 // ELEV_FIELD_MAX=d
203 // This will be used as a field index to indicate where the maximum elevation value of the polygon contour should be written. Only used in polygonal contouring mode.
204 // POLYGONIZE=YES|NO
205
206 /* Options strings list */
208
209 if (use_no_data)
210 stringbuffer_aprintf(&sb, "NODATA=%g ", no_data_value);
211
212 if (fixed_level_count > 0) {
213 int i = 0;
214 stringbuffer_append(&sb, "FIXED_LEVELS=");
215 for (i = 0; i < fixed_level_count; i++) {
216 if (i) stringbuffer_append_char(&sb, ',');
217 stringbuffer_aprintf(&sb, "%g", fixed_levels[i]);
218 }
219 stringbuffer_append_char(&sb, ' ');
220 }
221 else {
222 stringbuffer_aprintf(&sb, "LEVEL_INTERVAL=%g ", contour_interval);
223 stringbuffer_aprintf(&sb, "LEVEL_BASE=%g ", contour_base);
224 }
225
226 stringbuffer_aprintf(&sb, "ID_FIELD=%d ", 0);
227 stringbuffer_aprintf(&sb, "%s=%d ", elev_field, 1);
228
229 stringbuffer_aprintf(&sb, "POLYGONIZE=%s ", polygonize ? "YES" : "NO");
230
231 papszOptList = CSLTokenizeString(stringbuffer_getstring(&sb));
232
233 // CPLSetConfigOption("OGR_GEOMETRY_ACCEPT_UNCLOSED_RING", "NO");
234
235 /* Run the contouring routine, filling up the OGR layer */
236 cplerr = GDALContourGenerateEx(
237 hBand,
238 arg.dst.lyr,
239 papszOptList, // Options
240 rt_util_gdal_progress_func, // GDALProgressFunc pfnProgress
241 (void*)"GDALContourGenerateEx" // void *pProgressArg
242 );
243
244 // /* Run the contouring routine, filling up the OGR layer */
245 // cplerr = GDALContourGenerate(
246 // hBand,
247 // contour_interval, contour_base,
248 // fixed_level_count, fixed_levels,
249 // use_no_data, no_data_value,
250 // arg.dst.lyr, 0, 1, // OGRLayer, idFieldNum, elevFieldNum
251 // NULL, // GDALProgressFunc pfnProgress
252 // NULL // void *pProgressArg
253 // );
254
255 if (cplerr >= CE_Failure) {
256 return _rti_contour_arg_destroy(&arg); // FALSE
257 }
258
259 /* Convert the OGR layer into PostGIS geometries */
260 nfeatures = OGR_L_GetFeatureCount(arg.dst.lyr, TRUE);
261 if (nfeatures < 0)
262 return _rti_contour_arg_destroy(&arg);
263
264 *contours = rtalloc(sizeof(struct rt_contour_t) * nfeatures);
265 OGR_L_ResetReading(arg.dst.lyr);
266 while ((hFeat = OGR_L_GetNextFeature(arg.dst.lyr))) {
267 size_t szWkb;
268 unsigned char *bufWkb;
269 struct rt_contour_t contour;
270 OGRGeometryH hGeom;
271 LWGEOM *geom;
272
273 /* Somehow we're still iterating, should not happen. */
274 if(i >= nfeatures) break;
275
276 /* Store elevation/id */
277 contour.id = OGR_F_GetFieldAsInteger(hFeat, 0);
278 contour.elevation = OGR_F_GetFieldAsDouble(hFeat, 1);
279 /* Convert OGR geometry to LWGEOM via WKB */
280 if (!(hGeom = OGR_F_GetGeometryRef(hFeat))) continue;
281 szWkb = OGR_G_WkbSize(hGeom);
282 bufWkb = rtalloc(szWkb);
283 if (OGR_G_ExportToWkb(hGeom, wkbNDR, bufWkb) != OGRERR_NONE) continue;
284 /* Reclaim feature and associated geometry memory */
285 OGR_F_Destroy(hFeat);
286 geom = lwgeom_from_wkb(bufWkb, szWkb, LW_PARSER_CHECK_NONE);
287 if (!geom) rterror("%s: invalid wkb", __func__);
289 contour.geom = gserialized_from_lwgeom(geom, NULL);
291 rtdealloc(bufWkb);
292 (*contours)[i++] = contour;
293 }
294
295 /* Return total number of contours saved */
296 *ncontours = i;
297
298 /* Free all the non-database allocated structures */
301
302 /* Done */
303 return TRUE;
304}
305
#define TRUE
Definition dbfopen.c:73
#define FALSE
Definition dbfopen.c:72
GSERIALIZED * gserialized_from_lwgeom(LWGEOM *geom, size_t *size)
Allocate a new GSERIALIZED from an LWGEOM.
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
void lwgeom_free(LWGEOM *geom)
Definition lwgeom.c:1218
#define LW_PARSER_CHECK_NONE
Definition liblwgeom.h:2146
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
int _lwgeom_interrupt_requested
Definition lwgeom_api.c:656
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
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
This library is the generic raster handling section of PostGIS.
static int _rti_contour_arg_destroy(_rti_contour_arg *arg)
Definition rt_gdal.c:85
static int rt_util_gdal_progress_func(double dfComplete, const char *pszMessage, void *pProgressArg)
Definition rt_gdal.c:58
static void _rti_contour_arg_init(_rti_contour_arg *arg)
Definition rt_gdal.c:77
int rt_raster_gdal_contour(rt_raster src_raster, int src_band, int src_srid, const char *src_srs, double contour_interval, double contour_base, int fixed_level_count, double *fixed_levels, int polygonize, size_t *ncontours, struct rt_contour_t **contours)
Return palloc'ed list of contours.
Definition rt_gdal.c:114
void stringbuffer_release(stringbuffer_t *s)
int stringbuffer_aprintf(stringbuffer_t *s, const char *fmt,...)
Appends a formatted string to the current string buffer, using the format and argument list provided.
const char * stringbuffer_getstring(stringbuffer_t *s)
Returns a reference to the internal string being managed by the stringbuffer.
void stringbuffer_init(stringbuffer_t *s)
static void stringbuffer_append(stringbuffer_t *s, const char *a)
Append the specified string to the stringbuffer_t.
static void stringbuffer_append_char(stringbuffer_t *s, char c)
struct _rti_contour_arg::@14 src
GDALDatasetH ds
Definition rt_gdal.c:38
OGRDataSourceH ds
Definition rt_gdal.c:45
GDALDriverH drv
Definition rt_gdal.c:39
OGRSFDriverH drv
Definition rt_gdal.c:44
OGRLayerH lyr
Definition rt_gdal.c:46
OGRwkbGeometryType gtype
Definition rt_gdal.c:48
struct _rti_contour_arg::@15 dst
GSERIALIZED * geom
Definition librtcore.h:1775
double elevation
Definition librtcore.h:1776