PostGIS  3.4.0dev-r@@SVN_REVISION@@
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 
35 typedef 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 
76 static void
78 {
79  memset(arg, 0, sizeof(_rti_contour_arg));
80  return;
81 }
82 
83 
84 static 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 */
137  stringbuffer_t sb;
138  char **papszOptList = NULL;
139 
140  _rti_contour_arg arg;
141  _rti_contour_arg_init(&arg);
142 
143  /* Load raster into GDAL memory */
144  arg.src.ds = rt_raster_to_gdal_mem(src_raster, src_srs, NULL, NULL, 0, &(arg.src.drv), &(arg.src.destroy_drv));
145  /* Extract the desired band */
146  hBand = GDALGetRasterBand(arg.src.ds, src_band);
147 
148  /* Set up the OGR destination data store */
149  arg.dst.srid = src_srid;
150  arg.dst.drv = OGRGetDriverByName("Memory");
151  if (!arg.dst.drv)
152  return _rti_contour_arg_destroy(&arg);
153 
154  arg.dst.ds = OGR_Dr_CreateDataSource(arg.dst.drv, "contour_ds", NULL);
155  if (!arg.dst.ds)
156  return _rti_contour_arg_destroy(&arg);
157 
158  /* Polygonize is 2.4+ only */
159 #if POSTGIS_GDAL_VERSION >= 24
160  arg.dst.gtype = polygonize ? wkbPolygon : wkbLineString;
161 #else
162  arg.dst.gtype = wkbLineString;
163 #endif
164 
165  /* Layer has geometry, elevation, id */
166  arg.dst.lyr = OGR_DS_CreateLayer(arg.dst.ds, "contours", NULL, arg.dst.gtype, NULL);
167  if (!arg.dst.lyr)
168  return _rti_contour_arg_destroy(&arg);
169 
170  /* ID field */
171  OGRFieldDefnH hFldId = OGR_Fld_Create("id", OFTInteger);
172  ogrerr = OGR_L_CreateField(arg.dst.lyr, hFldId, TRUE);
173  if (ogrerr != OGRERR_NONE)
174  return _rti_contour_arg_destroy(&arg);
175 
176  /* ELEVATION field */
177  OGRFieldDefnH hFldElevation = OGR_Fld_Create("elevation", OFTReal);
178  ogrerr = OGR_L_CreateField(arg.dst.lyr, hFldElevation, TRUE);
179  if (ogrerr != OGRERR_NONE)
180  return _rti_contour_arg_destroy(&arg);
181 
182  int use_no_data = 0;
183  double no_data_value = GDALGetRasterNoDataValue(hBand, &use_no_data);
184 
185  // LEVEL_INTERVAL=f
186  // The elevation interval between contours generated.
187  // LEVEL_BASE=f
188  // 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.
189  // LEVEL_EXP_BASE=f
190  // 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.
191  // FIXED_LEVELS=f[,f]*
192  // The list of fixed contour levels at which contours should be generated. This option has precedence on LEVEL_INTERVAL
193  // NODATA=f
194  // 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.
195  // ID_FIELD=d
196  // This will be used as a field index to indicate where a unique id should be written for each feature (contour) written.
197  // ELEV_FIELD=d
198  // 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.
199  // ELEV_FIELD_MIN=d
200  // 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.
201  // ELEV_FIELD_MAX=d
202  // 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.
203  // POLYGONIZE=YES|NO
204 
205  /* Options strings list */
206  stringbuffer_init(&sb);
207 
208  if (use_no_data)
209  stringbuffer_aprintf(&sb, "NODATA=%g ", no_data_value);
210 
211  if (fixed_level_count > 0) {
212  int i = 0;
213  stringbuffer_append(&sb, "FIXED_LEVELS=");
214  for (i = 0; i < fixed_level_count; i++) {
215  if (i) stringbuffer_append_char(&sb, ',');
216  stringbuffer_aprintf(&sb, "%g", fixed_levels[i]);
217  }
218  stringbuffer_append_char(&sb, ' ');
219  }
220  else {
221  stringbuffer_aprintf(&sb, "LEVEL_INTERVAL=%g ", contour_interval);
222  stringbuffer_aprintf(&sb, "LEVEL_BASE=%g ", contour_base);
223  }
224 
225  stringbuffer_aprintf(&sb, "ID_FIELD=%d ", 0);
226  stringbuffer_aprintf(&sb, "ELEV_FIELD=%d ", 1);
227  stringbuffer_aprintf(&sb, "POLYGONIZE=%s ", polygonize ? "YES" : "NO");
228 
229  papszOptList = CSLTokenizeString(stringbuffer_getstring(&sb));
230 
231  // CPLSetConfigOption("OGR_GEOMETRY_ACCEPT_UNCLOSED_RING", "NO");
232 
233  /* Run the contouring routine, filling up the OGR layer */
234  cplerr = GDALContourGenerateEx(
235  hBand,
236  arg.dst.lyr,
237  papszOptList, // Options
238  rt_util_gdal_progress_func, // GDALProgressFunc pfnProgress
239  (void*)"GDALContourGenerateEx" // void *pProgressArg
240  );
241 
242  // /* Run the contouring routine, filling up the OGR layer */
243  // cplerr = GDALContourGenerate(
244  // hBand,
245  // contour_interval, contour_base,
246  // fixed_level_count, fixed_levels,
247  // use_no_data, no_data_value,
248  // arg.dst.lyr, 0, 1, // OGRLayer, idFieldNum, elevFieldNum
249  // NULL, // GDALProgressFunc pfnProgress
250  // NULL // void *pProgressArg
251  // );
252 
253  if (cplerr >= CE_Failure) {
254  return _rti_contour_arg_destroy(&arg); // FALSE
255  }
256 
257  /* Convert the OGR layer into PostGIS geometries */
258  nfeatures = OGR_L_GetFeatureCount(arg.dst.lyr, TRUE);
259  if (nfeatures < 0)
260  return _rti_contour_arg_destroy(&arg);
261 
262  *contours = rtalloc(sizeof(struct rt_contour_t) * nfeatures);
263  OGR_L_ResetReading(arg.dst.lyr);
264  while ((hFeat = OGR_L_GetNextFeature(arg.dst.lyr))) {
265  size_t szWkb;
266  unsigned char *bufWkb;
267  struct rt_contour_t contour;
268  OGRGeometryH hGeom;
269  LWGEOM *geom;
270 
271  /* Somehow we're still iterating, should not happen. */
272  if(i >= nfeatures) break;
273 
274  /* Store elevation/id */
275  contour.id = OGR_F_GetFieldAsInteger(hFeat, 0);
276  contour.elevation = OGR_F_GetFieldAsDouble(hFeat, 1);
277  /* Convert OGR geometry to LWGEOM via WKB */
278  if (!(hGeom = OGR_F_GetGeometryRef(hFeat))) continue;
279  szWkb = OGR_G_WkbSize(hGeom);
280  bufWkb = rtalloc(szWkb);
281  if (OGR_G_ExportToWkb(hGeom, wkbNDR, bufWkb) != OGRERR_NONE) continue;
282  /* Reclaim feature and associated geometry memory */
283  OGR_F_Destroy(hFeat);
284  geom = lwgeom_from_wkb(bufWkb, szWkb, LW_PARSER_CHECK_NONE);
286  contour.geom = gserialized_from_lwgeom(geom, NULL);
287  lwgeom_free(geom);
288  rtdealloc(bufWkb);
289  (*contours)[i++] = contour;
290  }
291 
292  /* Return total number of contours saved */
293  *ncontours = i;
294 
295  /* Free all the non-database allocated structures */
298 
299  /* Done */
300  return TRUE;
301 }
302 
#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.
Definition: gserialized.c:222
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:1547
void lwgeom_free(LWGEOM *geom)
Definition: lwgeom.c:1155
#define LW_PARSER_CHECK_NONE
Definition: liblwgeom.h:2114
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:834
int _lwgeom_interrupt_requested
Definition: lwgeom_api.c:661
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:1935
This library is the generic raster handling section of PostGIS.
src_band
Definition: pixval.py:76
static int _rti_contour_arg_destroy(_rti_contour_arg *arg)
Definition: rt_gdal.c:85
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)
Definition: stringbuffer.c:48
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.
Definition: stringbuffer.c:247
void stringbuffer_init(stringbuffer_t *s)
Definition: stringbuffer.c:54
const char * stringbuffer_getstring(stringbuffer_t *s)
Returns a reference to the internal string being managed by the stringbuffer.
Definition: stringbuffer.c:122
static void stringbuffer_append(stringbuffer_t *s, const char *a)
Append the specified string to the stringbuffer_t.
Definition: stringbuffer.h:105
static void stringbuffer_append_char(stringbuffer_t *s, char c)
Definition: stringbuffer.h:119
GDALDatasetH ds
Definition: rt_gdal.c:38
OGRDataSourceH ds
Definition: rt_gdal.c:45
GDALDriverH drv
Definition: rt_gdal.c:39
struct _rti_contour_arg::@14 dst
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::@13 src
GSERIALIZED * geom
Definition: librtcore.h:1749
double elevation
Definition: librtcore.h:1750