PostGIS 3.7.0dev-r@@SVN_REVISION@@
Loading...
Searching...
No Matches
lwgeom_out_mvt.c
Go to the documentation of this file.
1/**********************************************************************
2 *
3 * PostGIS - Spatial Types for PostgreSQL
4 * http://postgis.net
5 *
6 * PostGIS is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * PostGIS is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with PostGIS. If not, see <http://www.gnu.org/licenses/>.
18 *
19 **********************************************************************
20 *
21 * Copyright (C) 2016-2017 Björn Harrtell <bjorn@wololo.org>
22 *
23 **********************************************************************/
24
25#include "postgres.h"
26#include "utils/builtins.h"
27#include "executor/spi.h"
28#include "../postgis_config.h"
29#include "lwgeom_pg.h"
30#include "lwgeom_log.h"
31#include "liblwgeom.h"
32#include "mvt.h"
33
34#ifdef HAVE_LIBPROTOBUF
35#include "vector_tile.pb-c.h"
36#endif /* HAVE_LIBPROTOBUF */
37
42Datum ST_AsMVTGeom(PG_FUNCTION_ARGS)
43{
44#ifndef HAVE_LIBPROTOBUF
45 elog(ERROR, "ST_AsMVTGeom: Compiled without protobuf-c support");
46 PG_RETURN_NULL();
47#else
48 GBOX *bounds = NULL;
49 int32_t extent = 0;
50 int32_t buffer = 0;
51 bool clip_geom = true;
52 GSERIALIZED *geom_in, *geom_out;
53 LWGEOM *lwgeom_in, *lwgeom_out;
54 uint8_t type = 0;
55
56 if (PG_ARGISNULL(0))
57 {
58 PG_RETURN_NULL();
59 }
60
61 if (PG_ARGISNULL(1))
62 {
63 elog(ERROR, "%s: Geometric bounds cannot be null", __func__);
64 PG_RETURN_NULL();
65 }
66 bounds = (GBOX *)PG_GETARG_POINTER(1);
67 if (bounds->xmax - bounds->xmin <= 0 || bounds->ymax - bounds->ymin <= 0)
68 {
69 elog(ERROR, "%s: Geometric bounds are too small", __func__);
70 PG_RETURN_NULL();
71 }
72
73 extent = PG_ARGISNULL(2) ? 4096 : PG_GETARG_INT32(2);
74 if (extent <= 0)
75 {
76 elog(ERROR, "%s: Extent must be greater than 0", __func__);
77 PG_RETURN_NULL();
78 }
79
80 buffer = PG_ARGISNULL(3) ? 256 : PG_GETARG_INT32(3);
81 clip_geom = PG_ARGISNULL(4) ? true : PG_GETARG_BOOL(4);
82
83 geom_in = PG_GETARG_GSERIALIZED_P_COPY(0);
84 type = gserialized_get_type(geom_in);
85
86 /* If possible, peek into the bounding box before deserializing it to discard small geometries
87 * We don't check COLLECTIONTYPE since that might be a collection of points */
88 if (type == LINETYPE || type == POLYGONTYPE || type == MULTILINETYPE || type == MULTIPOLYGONTYPE)
89 {
90 GBOX gserialized_box;
91 /* We only apply the optimization if the bounding box is available */
92 if (gserialized_fast_gbox_p(geom_in, &gserialized_box) == LW_SUCCESS)
93 {
94 /* Shortcut to drop geometries smaller than the resolution */
95 double geom_width = gserialized_box.xmax - gserialized_box.xmin;
96 double geom_height = gserialized_box.ymax - gserialized_box.ymin;
97
98 /* We use half of the square height and width as limit: We use this
99 * and not area so it works properly with lines */
100 double bounds_width = ((bounds->xmax - bounds->xmin) / extent) / 2.0;
101 double bounds_height = ((bounds->ymax - bounds->ymin) / extent) / 2.0;
102 if (geom_width < bounds_width && geom_height < bounds_height)
103 {
104 PG_RETURN_NULL();
105 }
106 }
107 }
108
109 lwgeom_in = lwgeom_from_gserialized(geom_in);
110
111 lwgeom_out = mvt_geom(lwgeom_in, bounds, extent, buffer, clip_geom);
112 if (lwgeom_out == NULL)
113 PG_RETURN_NULL();
114
115 geom_out = geometry_serialize(lwgeom_out);
116 lwgeom_free(lwgeom_out);
117 PG_FREE_IF_COPY(geom_in, 0);
118 PG_RETURN_POINTER(geom_out);
119#endif
120}
121
126Datum pgis_asmvt_transfn(PG_FUNCTION_ARGS)
127{
128#ifndef HAVE_LIBPROTOBUF
129 elog(ERROR, "ST_AsMVT: Compiled without protobuf-c support");
130 PG_RETURN_NULL();
131#else
132 MemoryContext aggcontext, old_context;
133 mvt_agg_context *ctx;
134
135 /* We need to initialize the internal cache to access it later via postgis_oid() */
136 postgis_initialize_cache();
137
138 if (!AggCheckCallContext(fcinfo, &aggcontext))
139 elog(ERROR, "%s called in non-aggregate context", __func__);
140
141 if (PG_ARGISNULL(0)) {
142 old_context = MemoryContextSwitchTo(aggcontext);
143 ctx = palloc(sizeof(*ctx));
144 ctx->name = "default";
145 if (PG_NARGS() > 2 && !PG_ARGISNULL(2))
146 ctx->name = text_to_cstring(PG_GETARG_TEXT_P(2));
147 ctx->extent = 4096;
148 if (PG_NARGS() > 3 && !PG_ARGISNULL(3))
149 ctx->extent = PG_GETARG_INT32(3);
150 ctx->geom_name = NULL;
151 if (PG_NARGS() > 4 && !PG_ARGISNULL(4))
152 ctx->geom_name = text_to_cstring(PG_GETARG_TEXT_P(4));
153 if (PG_NARGS() > 5 && !PG_ARGISNULL(5))
154 ctx->id_name = text_to_cstring(PG_GETARG_TEXT_P(5));
155 else
156 ctx->id_name = NULL;
157
158 ctx->trans_context = AllocSetContextCreate(aggcontext, "MVT transfn", ALLOCSET_DEFAULT_SIZES);
159
160 MemoryContextSwitchTo(ctx->trans_context);
162 MemoryContextSwitchTo(old_context);
163 } else {
164 ctx = (mvt_agg_context *) PG_GETARG_POINTER(0);
165 }
166
167 if (!type_is_rowtype(get_fn_expr_argtype(fcinfo->flinfo, 1)))
168 elog(ERROR, "%s: parameter row cannot be other than a rowtype", __func__);
169 ctx->row = PG_GETARG_HEAPTUPLEHEADER(1);
170
171 old_context = MemoryContextSwitchTo(ctx->trans_context);
172 mvt_agg_transfn(ctx);
173 MemoryContextSwitchTo(old_context);
174
175 PG_FREE_IF_COPY(ctx->row, 1);
176 PG_RETURN_POINTER(ctx);
177#endif
178}
179
184Datum pgis_asmvt_finalfn(PG_FUNCTION_ARGS)
185{
186#ifndef HAVE_LIBPROTOBUF
187 elog(ERROR, "ST_AsMVT: Compiled without protobuf-c support");
188 PG_RETURN_NULL();
189#else
190 mvt_agg_context *ctx;
191 bytea *buf;
192 elog(DEBUG2, "%s called", __func__);
193 if (!AggCheckCallContext(fcinfo, NULL))
194 elog(ERROR, "%s called in non-aggregate context", __func__);
195
196 if (PG_ARGISNULL(0))
197 {
198 bytea *emptybuf = palloc(VARHDRSZ);
199 SET_VARSIZE(emptybuf, VARHDRSZ);
200 PG_RETURN_BYTEA_P(emptybuf);
201 }
202
203 ctx = (mvt_agg_context *) PG_GETARG_POINTER(0);
204 buf = mvt_agg_finalfn(ctx);
205 PG_RETURN_BYTEA_P(buf);
206#endif
207}
208
210Datum pgis_asmvt_serialfn(PG_FUNCTION_ARGS)
211{
212#ifndef HAVE_LIBPROTOBUF
213 elog(ERROR, "ST_AsMVT: Compiled without protobuf-c support");
214 PG_RETURN_NULL();
215#else
216 mvt_agg_context *ctx;
217 bytea *result;
218 elog(DEBUG2, "%s called", __func__);
219 if (!AggCheckCallContext(fcinfo, NULL))
220 elog(ERROR, "%s called in non-aggregate context", __func__);
221
222 if (PG_ARGISNULL(0))
223 {
224 bytea *emptybuf = palloc(VARHDRSZ);
225 SET_VARSIZE(emptybuf, VARHDRSZ);
226 PG_RETURN_BYTEA_P(emptybuf);
227 }
228
229 ctx = (mvt_agg_context *) PG_GETARG_POINTER(0);
231 if (ctx->trans_context)
232 MemoryContextDelete(ctx->trans_context);
233 ctx->trans_context = NULL;
234 PG_RETURN_BYTEA_P(result);
235#endif
236}
237
238
240Datum pgis_asmvt_deserialfn(PG_FUNCTION_ARGS)
241{
242#ifndef HAVE_LIBPROTOBUF
243 elog(ERROR, "ST_AsMVT: Compiled without protobuf-c support");
244 PG_RETURN_NULL();
245#else
246 MemoryContext aggcontext, oldcontext;
247 mvt_agg_context *ctx;
248 elog(DEBUG2, "%s called", __func__);
249 if (!AggCheckCallContext(fcinfo, &aggcontext))
250 elog(ERROR, "%s called in non-aggregate context", __func__);
251
252 oldcontext = MemoryContextSwitchTo(aggcontext);
253 ctx = mvt_ctx_deserialize(PG_GETARG_BYTEA_P(0));
254 MemoryContextSwitchTo(oldcontext);
255
256 PG_RETURN_POINTER(ctx);
257#endif
258}
259
261Datum pgis_asmvt_combinefn(PG_FUNCTION_ARGS)
262{
263#ifndef HAVE_LIBPROTOBUF
264 elog(ERROR, "ST_AsMVT: Compiled without protobuf-c support");
265 PG_RETURN_NULL();
266#else
267 MemoryContext aggcontext, oldcontext;
268 mvt_agg_context *ctx, *ctx1, *ctx2;
269 elog(DEBUG2, "%s called", __func__);
270 if (!AggCheckCallContext(fcinfo, &aggcontext))
271 elog(ERROR, "%s called in non-aggregate context", __func__);
272
273 ctx1 = (mvt_agg_context*)PG_GETARG_POINTER(0);
274 ctx2 = (mvt_agg_context*)PG_GETARG_POINTER(1);
275 oldcontext = MemoryContextSwitchTo(aggcontext);
276 ctx = mvt_ctx_combine(ctx1, ctx2);
277 MemoryContextSwitchTo(oldcontext);
278 PG_RETURN_POINTER(ctx);
279#endif
280}
281
char result[OUT_DOUBLE_BUFFER_SIZE]
Definition cu_print.c:267
LWGEOM * lwgeom_from_gserialized(const GSERIALIZED *g)
Allocate a new LWGEOM from a GSERIALIZED.
uint32_t gserialized_get_type(const GSERIALIZED *g)
Extract the geometry type from the serialized form (it hides in the anonymous data area,...
int gserialized_fast_gbox_p(const GSERIALIZED *g, GBOX *gbox)
Read the box from the GSERIALIZED or return #LWFAILURE if box is unavailable.
void lwgeom_free(LWGEOM *geom)
Definition lwgeom.c:1246
#define MULTILINETYPE
Definition liblwgeom.h:106
#define LINETYPE
Definition liblwgeom.h:103
#define LW_SUCCESS
Definition liblwgeom.h:97
#define MULTIPOLYGONTYPE
Definition liblwgeom.h:107
#define POLYGONTYPE
Definition liblwgeom.h:104
This library is the generic geometry handling section of PostGIS.
Datum ST_AsMVTGeom(PG_FUNCTION_ARGS)
Datum pgis_asmvt_serialfn(PG_FUNCTION_ARGS)
PG_FUNCTION_INFO_V1(ST_AsMVTGeom)
Process input parameters to mvt_geom and returned serialized geometry.
Datum pgis_asmvt_finalfn(PG_FUNCTION_ARGS)
Datum pgis_asmvt_transfn(PG_FUNCTION_ARGS)
Datum pgis_asmvt_deserialfn(PG_FUNCTION_ARGS)
Datum pgis_asmvt_combinefn(PG_FUNCTION_ARGS)
mvt_agg_context * mvt_ctx_deserialize(const bytea *ba)
Definition mvt.c:1140
bytea * mvt_ctx_serialize(mvt_agg_context *ctx)
Definition mvt.c:1125
mvt_agg_context * mvt_ctx_combine(mvt_agg_context *ctx1, mvt_agg_context *ctx2)
Definition mvt.c:1263
void mvt_agg_init_context(mvt_agg_context *ctx)
Initialize aggregation context.
Definition mvt.c:988
void mvt_agg_transfn(mvt_agg_context *ctx)
Aggregation step.
Definition mvt.c:1030
bytea * mvt_agg_finalfn(mvt_agg_context *ctx)
Finalize aggregation.
Definition mvt.c:1296
LWGEOM * mvt_geom(LWGEOM *lwgeom, const GBOX *gbox, uint32_t extent, uint32_t buffer, bool clip_geom)
Transform a geometry into vector tile coordinate space.
Definition mvt.c:931
Datum buffer(PG_FUNCTION_ARGS)
double ymax
Definition liblwgeom.h:357
double xmax
Definition liblwgeom.h:355
double ymin
Definition liblwgeom.h:356
double xmin
Definition liblwgeom.h:354
char * id_name
Definition mvt.h:67
char * geom_name
Definition mvt.h:71
MemoryContext trans_context
Definition mvt.h:62
uint32_t extent
Definition mvt.h:64
HeapTupleHeader row
Definition mvt.h:74
char * name
Definition mvt.h:63