28 #ifdef HAVE_LIBPROTOBUF
30 #if POSTGIS_PGSQL_VERSION >= 94
31 #include "utils/jsonb.h"
34 #if POSTGIS_PGSQL_VERSION < 110
36 # define DatumGetJsonbP DatumGetJsonb
41 #define FEATURES_CAPACITY_INITIAL 50
108 return (
id & 0x7) | (
count << 3);
118 int32_t *px, int32_t *py)
122 int32_t dx, dy,
x,
y;
126 for (i = 0; i < pa->
npoints; i++)
171 int32_t px = 0, py = 0;
177 VectorTile__Tile__Feature *feature = ctx->
feature;
178 feature->type = VECTOR_TILE__TILE__GEOM_TYPE__POINT;
179 feature->has_type = 1;
180 feature->n_geometry = 3;
181 feature->geometry = palloc(
sizeof(*feature->geometry) * 3);
188 VectorTile__Tile__Feature *feature = ctx->
feature;
191 feature->type = VECTOR_TILE__TILE__GEOM_TYPE__POINT;
192 feature->has_type = 1;
194 feature->geometry = palloc(
sizeof(*feature->geometry) * c);
196 lwline->
points, feature->geometry);
202 VectorTile__Tile__Feature *feature = ctx->
feature;
203 feature->type = VECTOR_TILE__TILE__GEOM_TYPE__LINESTRING;
204 feature->has_type = 1;
206 feature->geometry = palloc(
sizeof(*feature->geometry) * c);
208 lwline->
points, feature->geometry);
214 int32_t px = 0, py = 0;
215 size_t c = 0, offset = 0;
216 VectorTile__Tile__Feature *feature = ctx->
feature;
217 feature->type = VECTOR_TILE__TILE__GEOM_TYPE__LINESTRING;
218 feature->has_type = 1;
219 for (i = 0; i < lwmline->
ngeoms; i++)
221 feature->geometry = palloc(
sizeof(*feature->geometry) * c);
222 for (i = 0; i < lwmline->
ngeoms; i++)
225 feature->geometry + offset, &px, &py);
226 feature->n_geometry = offset;
232 int32_t px = 0, py = 0;
233 size_t c = 0, offset = 0;
234 VectorTile__Tile__Feature *feature = ctx->
feature;
235 feature->type = VECTOR_TILE__TILE__GEOM_TYPE__POLYGON;
236 feature->has_type = 1;
237 for (i = 0; i < lwpoly->
nrings; i++)
239 feature->geometry = palloc(
sizeof(*feature->geometry) * c);
240 for (i = 0; i < lwpoly->
nrings; i++)
243 feature->geometry + offset, &px, &py);
244 feature->n_geometry = offset;
250 int32_t px = 0, py = 0;
251 size_t c = 0, offset = 0;
253 VectorTile__Tile__Feature *feature = ctx->
feature;
254 feature->type = VECTOR_TILE__TILE__GEOM_TYPE__POLYGON;
255 feature->has_type = 1;
256 for (i = 0; i < lwmpoly->
ngeoms; i++)
257 for (j = 0; poly = lwmpoly->
geoms[i], j < poly->
nrings; j++)
259 feature->geometry = palloc(
sizeof(*feature->geometry) * c);
260 for (i = 0; i < lwmpoly->
ngeoms; i++)
261 for (j = 0; poly = lwmpoly->
geoms[i], j < poly->
nrings; j++)
263 poly->
rings[j], feature->geometry + offset,
265 feature->n_geometry = offset;
286 default: elog(ERROR,
"encode_geometry: '%s' geometry type not supported",
293 Oid tupType = HeapTupleHeaderGetTypeId(ctx->
row);
294 int32 tupTypmod = HeapTupleHeaderGetTypMod(ctx->
row);
295 TupleDesc tupdesc = lookup_rowtype_tupdesc(tupType, tupTypmod);
311 size_t size = strlen(
name);
312 kv = palloc(
sizeof(*kv));
322 bool geom_found =
false;
324 POSTGIS_DEBUG(2,
"parse_column_keys called");
334 for (i = 0; i < natts; i++)
336 #if POSTGIS_PGSQL_VERSION < 110
345 #if POSTGIS_PGSQL_VERSION >= 94
346 if (typoid == JSONBOID)
355 if (!geom_found && typoid == postgis_oid(GEOMETRYOID))
364 if (!geom_found && strcmp(tkey, ctx->
geom_name) == 0)
376 elog(ERROR,
"parse_column_keys: no geometry column found");
383 char **keys = palloc(n_keys *
sizeof(*keys));
386 ctx->
layer->n_keys = n_keys;
387 ctx->
layer->keys = keys;
394 VectorTile__Tile__Value *
value = palloc(
sizeof(*
value));
395 vector_tile__tile__value__init(
value);
399 #define MVT_CREATE_VALUES(kvtype, hash, hasfield, valuefield) \
401 POSTGIS_DEBUG(2, "MVT_CREATE_VALUES called"); \
404 for (kv = ctx->hash; kv != NULL; kv=kv->hh.next) \
406 VectorTile__Tile__Value *value = create_value(); \
407 value->hasfield = 1; \
408 value->valuefield = kv->valuefield; \
409 values[kv->id] = value; \
416 VectorTile__Tile__Value **values;
419 POSTGIS_DEBUG(2,
"encode_values called");
429 float_values_hash, has_float_value, float_value);
431 double_values_hash, has_double_value, double_value);
433 uint_values_hash, has_uint_value, uint_value);
435 sint_values_hash, has_sint_value, sint_value);
437 bool_values_hash, has_bool_value, bool_value);
439 POSTGIS_DEBUGF(3,
"encode_values n_values: %d", ctx->
values_hash_i);
441 ctx->
layer->values = values;
459 #define MVT_PARSE_VALUE(value, kvtype, hash, valuefield, size) \
461 POSTGIS_DEBUG(2, "MVT_PARSE_VALUE called"); \
464 HASH_FIND(hh, ctx->hash, &value, size, kv); \
467 POSTGIS_DEBUG(4, "MVT_PARSE_VALUE value not found"); \
468 kv = palloc(sizeof(*kv)); \
469 POSTGIS_DEBUGF(4, "MVT_PARSE_VALUE new hash key: %d", \
470 ctx->values_hash_i); \
471 kv->id = ctx->values_hash_i++; \
472 kv->valuefield = value; \
473 HASH_ADD(hh, ctx->hash, valuefield, size, kv); \
475 tags[ctx->row_columns*2] = k; \
476 tags[ctx->row_columns*2+1] = kv->id; \
480 #define MVT_PARSE_INT_VALUE(value) \
484 uint64_t cvalue = value; \
485 MVT_PARSE_VALUE(cvalue, mvt_kv_uint_value, \
486 uint_values_hash, uint_value, \
491 int64_t cvalue = value; \
492 MVT_PARSE_VALUE(cvalue, mvt_kv_sint_value, \
493 sint_values_hash, sint_value, \
498 #define MVT_PARSE_DATUM(type, kvtype, hash, valuefield, datumfunc, size) \
500 type value = datumfunc(datum); \
501 MVT_PARSE_VALUE(value, kvtype, hash, valuefield, size); \
504 #define MVT_PARSE_INT_DATUM(type, datumfunc) \
506 type value = datumfunc(datum); \
507 MVT_PARSE_INT_VALUE(value); \
514 POSTGIS_DEBUG(2,
"add_value_as_string called");
518 POSTGIS_DEBUG(4,
"add_value_as_string value not found");
519 kv = palloc(
sizeof(*kv));
520 POSTGIS_DEBUGF(4,
"add_value_as_string new hash key: %d",
543 POSTGIS_DEBUG(2,
"parse_value_as_string called");
544 getTypeOutputInfo(typoid, &foutoid, &typisvarlena);
545 value = OidOutputFunctionCall(foutoid, datum);
546 POSTGIS_DEBUGF(4,
"parse_value_as_string value: %s",
value);
550 #if POSTGIS_PGSQL_VERSION >= 94
556 bool skipNested =
false;
557 JsonbIteratorToken
r;
560 if (!JB_ROOT_IS_OBJECT(jb))
563 it = JsonbIteratorInit(&jb->root);
565 while ((
r = JsonbIteratorNext(&it, &v, skipNested)) != WJB_DONE)
569 if (
r == WJB_KEY && v.type != jbvNull)
578 key = palloc(v.val.string.len + 1);
579 memcpy(key, v.val.string.val, v.val.string.len);
580 key[v.val.string.len] =
'\0';
582 tags = repalloc(tags, newSize * 2 *
sizeof(*tags));
586 r = JsonbIteratorNext(&it, &v, skipNested);
588 if (v.type == jbvString)
591 value = palloc(v.val.string.len + 1);
592 memcpy(
value, v.val.string.val, v.val.string.len);
593 value[v.val.string.len] =
'\0';
597 else if (v.type == jbvBool)
600 bool_values_hash, bool_value,
sizeof(protobuf_c_boolean));
603 else if (v.type == jbvNumeric)
608 str = DatumGetCString(DirectFunctionCall1(numeric_out,
609 PointerGetDatum(v.val.numeric)));
610 d = strtod(str, NULL);
611 l = strtol(str, NULL, 10);
615 double_value,
sizeof(
double));
633 uint32_t *tags = palloc(n_keys * 2 *
sizeof(*tags));
640 POSTGIS_DEBUG(2,
"parse_values called");
644 tuple.t_len = HeapTupleHeaderGetDatumLength(ctx->
row);
645 ItemPointerSetInvalid(&(tuple.t_self));
646 tuple.t_tableOid = InvalidOid;
647 tuple.t_data = ctx->
row;
652 POSTGIS_DEBUGF(3,
"parse_values natts: %d", natts);
654 for (i = 0; i < natts; i++)
659 Datum datum = cc.
values[i];
666 POSTGIS_DEBUG(3,
"parse_values isnull detected");
670 #if POSTGIS_PGSQL_VERSION < 110
671 key = cc.
tupdesc->attrs[i]->attname.data;
673 key = cc.
tupdesc->attrs[i].attname.data;
678 #if POSTGIS_PGSQL_VERSION >= 94
680 elog(ERROR,
"parse_values: unexpectedly could not find parsed key name '%s'", key);
681 if (typoid == JSONBOID)
688 elog(ERROR,
"parse_values: unexpectedly could not find parsed key name '%s'", key);
695 bool_values_hash, bool_value,
696 DatumGetBool,
sizeof(protobuf_c_boolean));
709 float_values_hash, float_value,
710 DatumGetFloat4,
sizeof(
float));
714 double_values_hash, double_value,
715 DatumGetFloat8,
sizeof(
double));
728 POSTGIS_DEBUGF(3,
"parse_values n_tags %zd", ctx->
feature->n_tags);
745 return geom->
type - 3;
751 for (i = 0; i < g->
ngeoms; i++)
759 elog(ERROR,
"%s: Invalid type (%d)", __func__, geom->
type);
786 geom_out = g->
geoms[0];
807 POSTGIS_DEBUG(3,
"mvt_geom: geometry outside clip box");
813 POSTGIS_DEBUG(3,
"mvt_geom: geometry contained fully inside the box");
833 LWGEOM *geom_clipped, *envelope;
835 GEOSGeometry *geos_input, *geos_box, *geos_result;
843 POSTGIS_DEBUG(3,
"mvt_geom: geometry outside clip box");
849 POSTGIS_DEBUG(3,
"mvt_geom: geometry contained fully inside the box");
863 GEOSGeom_destroy(geos_input);
867 geos_result = GEOSIntersection(geos_input, geos_box);
870 POSTGIS_DEBUG(3,
"mvt_geom: no geometry after intersection. Retrying after validation");
871 GEOSGeom_destroy(geos_input);
875 GEOSGeom_destroy(geos_box);
878 geos_result = GEOSIntersection(geos_input, geos_box);
881 GEOSGeom_destroy(geos_box);
882 GEOSGeom_destroy(geos_input);
887 GEOSSetSRID(geos_result, lwg_in->
srid);
890 GEOSGeom_destroy(geos_box);
891 GEOSGeom_destroy(geos_input);
892 GEOSGeom_destroy(geos_result);
896 POSTGIS_DEBUG(3,
"mvt_geom: no geometry after clipping");
935 for (i = 0; i < lwmg->
ngeoms; i++)
970 gridspec grid = {0, 0, 0, 0, 1, 1, 0, 0};
987 static const uint32_t max_iterations = 3;
997 valid = GEOSisValid(geo) == 1;
999 while (!valid && iterations < max_iterations)
1001 #if POSTGIS_GEOS_VERSION < 38
1004 GEOSGeometry *geo_valid = GEOSMakeValid(geo);
1006 GEOSGeom_destroy(geo);
1011 GEOSGeom_destroy(geo_valid);
1018 valid = GEOSisValid(geo) == 1;
1021 GEOSGeom_destroy(geo);
1025 POSTGIS_DEBUG(1,
"mvt_geom: Could not transform into a valid MVT geometry");
1055 POSTGIS_DEBUG(3,
"mvt_geom: no geometry after clip");
1066 POSTGIS_DEBUG(1,
"mvt_geom: Dropping geometry after type change");
1084 AFFINE affine = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
1085 gridspec grid = {0, 0, 0, 0, 1, 1, 0, 0};
1086 double width = gbox->
xmax - gbox->
xmin;
1087 double height = gbox->
ymax - gbox->
ymin;
1088 double resx, resy,
res, fx, fy;
1091 POSTGIS_DEBUG(2,
"mvt_geom called");
1100 if (width == 0 || height == 0)
1101 elog(ERROR,
"mvt_geom: bounds width or height cannot be 0");
1104 elog(ERROR,
"mvt_geom: extent cannot be 0");
1106 resx = width / extent;
1107 resy = height / extent;
1108 res = (resx < resy ? resx : resy)/2;
1109 fx = extent / width;
1110 fy = -(extent / height);
1146 VectorTile__Tile__Layer *layer;
1148 POSTGIS_DEBUG(2,
"mvt_agg_init_context called");
1151 elog(ERROR,
"mvt_agg_init_context: extent cannot be 0");
1168 layer = palloc(
sizeof(*layer));
1169 vector_tile__tile__layer__init(layer);
1171 layer->name = ctx->
name;
1172 layer->has_extent = 1;
1173 layer->extent = ctx->
extent;
1175 sizeof(*layer->features));
1189 bool isnull =
false;
1193 VectorTile__Tile__Feature *feature;
1194 VectorTile__Tile__Layer *layer = ctx->
layer;
1196 POSTGIS_DEBUG(2,
"mvt_agg_transfn called");
1201 layer->features = repalloc(layer->features, new_capacity *
1202 sizeof(*layer->features));
1204 POSTGIS_DEBUGF(3,
"mvt_agg_transfn new_capacity: %zd", new_capacity);
1210 datum = GetAttributeByNum(ctx->
row, ctx->
geom_index + 1, &isnull);
1211 POSTGIS_DEBUGF(3,
"mvt_agg_transfn ctx->geom_index: %d", ctx->
geom_index);
1212 POSTGIS_DEBUGF(3,
"mvt_agg_transfn isnull: %u", isnull);
1213 POSTGIS_DEBUGF(3,
"mvt_agg_transfn datum: %lu", datum);
1216 POSTGIS_DEBUG(3,
"mvt_agg_transfn got null geom");
1220 feature = palloc(
sizeof(*feature));
1221 vector_tile__tile__feature__init(feature);
1228 POSTGIS_DEBUGF(3,
"mvt_agg_transfn encoded feature count: %zd", layer->n_features);
1229 layer->features[layer->n_features++] = feature;
1240 VectorTile__Tile *tile;
1244 tile = palloc(
sizeof(VectorTile__Tile));
1245 vector_tile__tile__init(tile);
1246 tile->layers = palloc(
sizeof(VectorTile__Tile__Layer*) * n_layers);
1247 tile->layers[0] = ctx->
layer;
1248 tile->n_layers = n_layers;
1267 if (ctx && ctx->
layer && ctx->
layer->n_features == 0)
1269 bytea *ba = palloc(VARHDRSZ);
1270 SET_VARSIZE(ba, VARHDRSZ);
1275 len = VARHDRSZ + vector_tile__tile__get_packed_size(ctx->
tile);
1277 vector_tile__tile__pack(ctx->
tile, (
uint8_t*)VARDATA(ba));
1278 SET_VARSIZE(ba, len);
1290 return palloc(size);
1300 ProtobufCAllocator allocator =
1307 size_t len = VARSIZE(ba) - VARHDRSZ;
1308 VectorTile__Tile *tile = vector_tile__tile__unpack(&allocator, len, (
uint8_t*)VARDATA(ba));
1315 static VectorTile__Tile__Value *
1318 VectorTile__Tile__Value *nvalue = palloc(
sizeof(VectorTile__Tile__Value));
1319 memcpy(nvalue,
value,
sizeof(VectorTile__Tile__Value));
1320 if (
value->string_value)
1321 nvalue->string_value = pstrdup(
value->string_value);
1325 static VectorTile__Tile__Feature *
1329 VectorTile__Tile__Feature *nfeature;
1332 if (!feature)
return NULL;
1335 nfeature = palloc(
sizeof(VectorTile__Tile__Feature));
1336 vector_tile__tile__feature__init(nfeature);
1339 nfeature->has_id = feature->has_id;
1340 nfeature->id = feature->id;
1341 nfeature->has_type = feature->has_type;
1342 nfeature->type = feature->type;
1346 if (feature->n_tags > 0)
1348 nfeature->n_tags = feature->n_tags;
1349 nfeature->tags = palloc(
sizeof(
uint32_t)*feature->n_tags);
1350 for (i = 0; i < feature->n_tags/2; i++)
1352 nfeature->tags[2*i] = feature->tags[2*i] + key_offset;
1353 nfeature->tags[2*i+1] = feature->tags[2*i+1] + value_offset;
1358 if (feature->n_geometry > 0)
1360 nfeature->n_geometry = feature->n_geometry;
1361 nfeature->geometry = palloc(
sizeof(
uint32_t)*feature->n_geometry);
1362 memcpy(nfeature->geometry, feature->geometry,
sizeof(
uint32_t)*feature->n_geometry);
1369 static VectorTile__Tile__Layer *
1373 int key2_offset, value2_offset;
1374 VectorTile__Tile__Layer *layer = palloc(
sizeof(VectorTile__Tile__Layer));
1375 vector_tile__tile__layer__init(layer);
1378 layer->version = layer1->version;
1379 layer->name = pstrdup(layer1->name);
1380 layer->has_extent = layer1->has_extent;
1381 layer->extent = layer1->extent;
1385 layer->n_keys = layer1->n_keys + layer2->n_keys;
1386 layer->keys = layer->n_keys ? palloc(layer->n_keys *
sizeof(
void*)) : NULL;
1387 for (i = 0; i < layer1->n_keys; i++)
1388 layer->keys[j++] = pstrdup(layer1->keys[i]);
1390 for (i = 0; i < layer2->n_keys; i++)
1391 layer->keys[j++] = pstrdup(layer2->keys[i]);
1396 layer->n_values = layer1->n_values + layer2->n_values;
1397 layer->values = layer->n_values ? palloc(layer->n_values *
sizeof(
void*)) : NULL;
1399 for (i = 0; i < layer1->n_values; i++)
1402 for (i = 0; i < layer2->n_values; i++)
1406 layer->n_features = layer1->n_features + layer2->n_features;
1407 layer->features = layer->n_features ? palloc(layer->n_features *
sizeof(
void*)) : NULL;
1409 for (i = 0; i < layer1->n_features; i++)
1411 for (i = 0; i < layer2->n_features; i++)
1412 layer->features[j++] =
tile_feature_copy(layer2->features[i], key2_offset, value2_offset);
1418 static VectorTile__Tile *
1422 VectorTile__Tile *tile;
1425 if (tile1->n_layers == 0 && tile2->n_layers == 0)
1427 else if (tile1->n_layers == 0)
1429 else if (tile2->n_layers == 0)
1432 tile = palloc(
sizeof(VectorTile__Tile));
1433 vector_tile__tile__init(tile);
1434 tile->layers = palloc(
sizeof(
void*));
1438 for (i = 0; i < tile1->n_layers; i++)
1440 for (j = 0; j < tile2->n_layers; j++)
1442 VectorTile__Tile__Layer *l1 = tile1->layers[i];
1443 VectorTile__Tile__Layer *l2 = tile2->layers[j];
1444 if (strcmp(l1->name, l2->name)==0)
1449 tile->layers[tile->n_layers++] = layer;
1451 tile->layers = repalloc(tile->layers, (tile->n_layers+1) *
sizeof(
void*));
1462 if (ctx1 && ! ctx2)
return ctx1;
1463 if (ctx2 && ! ctx1)
return ctx2;
1464 if (ctx1 && ctx2 && ctx1->
tile && ctx2->
tile)
1473 elog(DEBUG2,
"ctx1->tile = %p", ctx1->
tile);
1474 elog(DEBUG2,
"ctx2->tile = %p", ctx2->
tile);
1475 elog(ERROR,
"%s: unable to combine contexts where tile attribute is null", __func__);
int gbox_overlaps_2d(const GBOX *g1, const GBOX *g2)
Return LW_TRUE if the GBOX overlaps on the 2d plane, LW_FALSE otherwise.
void gbox_init(GBOX *gbox)
Zero out all the entries in the GBOX.
int gbox_contains_2d(const GBOX *g1, const GBOX *g2)
Return LW_TRUE if the first GBOX contains the second on the 2d plane, LW_FALSE otherwise.
LWGEOM * lwgeom_from_gserialized(const GSERIALIZED *g)
Allocate a new LWGEOM from a GSERIALIZED.
GEOSGeometry * LWGEOM2GEOS(const LWGEOM *lwgeom, uint8_t autofix)
LWGEOM * GEOS2LWGEOM(const GEOSGeometry *geom, uint8_t want3d)
void lwgeom_geos_error(const char *fmt,...)
GEOSGeometry * LWGEOM_GEOS_makeValid(const GEOSGeometry *)
LWGEOM * lwcollection_as_lwgeom(const LWCOLLECTION *obj)
LWCOLLECTION * lwcollection_construct_empty(uint8_t type, int srid, char hasz, char hasm)
void lwgeom_free(LWGEOM *geom)
LWGEOM * lwcollection_getsubgeom(LWCOLLECTION *col, int gnum)
void lwgeom_remove_repeated_points_in_place(LWGEOM *in, double tolerance)
void lwgeom_simplify_in_place(LWGEOM *igeom, double dist, int preserve_collapsed)
uint32_t lwgeom_get_type(const LWGEOM *geom)
Return LWTYPE number.
#define POINTTYPE
LWTYPE numbers, used internally by PostGIS.
#define FLAGS_GET_Z(flags)
Macros for manipulating the 'flags' byte.
int lwgeom_is_collection(const LWGEOM *lwgeom)
Determine whether a LWGEOM can contain sub-geometries or not.
void lwgeom_affine(LWGEOM *geom, const AFFINE *affine)
const char * lwtype_name(uint8_t type)
Return the type name string associated with a type number (e.g.
#define FLAGS_GET_M(flags)
LWLINE * lwline_from_lwmpoint(int srid, const LWMPOINT *mpoint)
void lwgeom_force_clockwise(LWGEOM *lwgeom)
Force Right-hand-rule on LWGEOM polygons.
int lwgeom_is_empty(const LWGEOM *geom)
Return true or false depending on whether a geometry is an "empty" geometry (no vertices members)
int lwgeom_calculate_gbox(const LWGEOM *lwgeom, GBOX *gbox)
Calculate bounding box of a geometry, automatically taking into account whether it is cartesian or ge...
LWCOLLECTION * lwcollection_extract(LWCOLLECTION *col, int type)
Takes a potentially heterogeneous collection and returns a homogeneous collection consisting only of ...
LWCOLLECTION * lwcollection_add_lwgeom(LWCOLLECTION *col, const LWGEOM *geom)
Appends geom to the collection managed by col.
#define FLAGS_SET_GEODETIC(flags, value)
LWGEOM * lwgeom_clip_by_rect(const LWGEOM *geom1, double x0, double y0, double x1, double y1)
LWPOLY * lwpoly_construct_envelope(int srid, double x1, double y1, double x2, double y2)
LWGEOM * lwgeom_make_valid(LWGEOM *geom)
Attempts to make an invalid geometries valid w/out losing points.
const POINT2D * getPoint2d_cp(const POINTARRAY *pa, uint32_t n)
Returns a POINT2D pointer into the POINTARRAY serialized_ptlist, suitable for reading from.
void lwgeom_reverse_in_place(LWGEOM *lwgeom)
Reverse vertex order of LWGEOM.
void lwgeom_grid_in_place(LWGEOM *lwgeom, const gridspec *grid)
void lwnotice(const char *fmt,...)
Write a notice out to the notice handler.
static void encode_poly(mvt_agg_context *ctx, LWPOLY *lwpoly)
static VectorTile__Tile__Value * create_value()
static uint32_t get_key_index_with_size(mvt_agg_context *ctx, const char *name, size_t size)
static LWGEOM * mvt_iterate_clip_by_box_geos(LWGEOM *lwgeom, GBOX *clip_gbox, uint8_t basic_type)
Clips the geometry using GEOSIntersection in a "safe way", cleaning the input if necessary and clippi...
static void encode_mline(mvt_agg_context *ctx, LWMLINE *lwmline)
static void parse_datum_as_string(mvt_agg_context *ctx, Oid typoid, Datum datum, uint32_t *tags, uint32_t k)
static void encode_geometry(mvt_agg_context *ctx, LWGEOM *lwgeom)
static void add_value_as_string_with_size(mvt_agg_context *ctx, char *value, size_t size, uint32_t *tags, uint32_t k)
#define MVT_PARSE_INT_VALUE(value)
mvt_agg_context * mvt_ctx_combine(mvt_agg_context *ctx1, mvt_agg_context *ctx2)
static void encode_mpoly(mvt_agg_context *ctx, LWMPOLY *lwmpoly)
mvt_agg_context * mvt_ctx_deserialize(const bytea *ba)
static VectorTile__Tile__Feature * tile_feature_copy(const VectorTile__Tile__Feature *feature, int key_offset, int value_offset)
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.
static void encode_mpoint(mvt_agg_context *ctx, LWMPOINT *mpoint)
#define FEATURES_CAPACITY_INITIAL
static void encode_keys(mvt_agg_context *ctx)
static LWGEOM * mvt_unsafe_clip_by_box(LWGEOM *lwg_in, GBOX *clip_box)
static void encode_point(mvt_agg_context *ctx, LWPOINT *point)
#define MVT_PARSE_INT_DATUM(type, datumfunc)
bytea * mvt_agg_finalfn(mvt_agg_context *ctx)
Finalize aggregation.
static uint8 lwgeom_get_basic_type(LWGEOM *geom)
bytea * mvt_ctx_serialize(mvt_agg_context *ctx)
static LWGEOM * mvt_safe_clip_polygon_by_box(LWGEOM *lwg_in, GBOX *clip_box)
Clips an input geometry using GEOSIntersection It used to try to use GEOSClipByRect (as mvt_unsafe_cl...
static void mvt_deallocator(__attribute__((__unused__)) void *data, void *ptr)
static uint32_t * parse_jsonb(mvt_agg_context *ctx, Jsonb *jb, uint32_t *tags)
static void parse_column_keys(mvt_agg_context *ctx)
static uint32_t c_int(enum mvt_cmd_id id, uint32_t count)
static VectorTile__Tile * mvt_ctx_to_tile(mvt_agg_context *ctx)
static uint32_t add_key(mvt_agg_context *ctx, char *name)
static VectorTile__Tile__Value * tile_value_copy(const VectorTile__Tile__Value *value)
static LWGEOM * mvt_clip_and_validate_geos(LWGEOM *lwgeom, uint8_t basic_type, uint32_t extent, uint32_t buffer, bool clip_geom)
static void * mvt_allocator(__attribute__((__unused__)) void *data, size_t size)
void mvt_agg_init_context(mvt_agg_context *ctx)
Initialize aggregation context.
static bytea * mvt_ctx_to_bytea(mvt_agg_context *ctx)
#define MVT_CREATE_VALUES(kvtype, hash, hasfield, valuefield)
static TupleDesc get_tuple_desc(mvt_agg_context *ctx)
static uint32_t encode_ptarray_initial(mvt_agg_context *ctx, enum mvt_type type, POINTARRAY *pa, uint32_t *buffer)
static LWGEOM * lwgeom_to_basic_type(LWGEOM *geom, uint8 original_type)
In place process a collection to find a concrete geometry object and expose that as the actual object...
static VectorTile__Tile * vectortile_tile_combine(VectorTile__Tile *tile1, VectorTile__Tile *tile2)
void mvt_agg_transfn(mvt_agg_context *ctx)
Aggregation step.
static void parse_values(mvt_agg_context *ctx)
static void add_value_as_string(mvt_agg_context *ctx, char *value, uint32_t *tags, uint32_t k)
static void encode_values(mvt_agg_context *ctx)
static uint32_t p_int(int32_t value)
#define MVT_PARSE_VALUE(value, kvtype, hash, valuefield, size)
static VectorTile__Tile__Layer * vectortile_layer_combine(const VectorTile__Tile__Layer *layer1, const VectorTile__Tile__Layer *layer2)
static void encode_line(mvt_agg_context *ctx, LWLINE *lwline)
static uint32_t encode_ptarray(__attribute__((__unused__)) mvt_agg_context *ctx, enum mvt_type type, POINTARRAY *pa, uint32_t *buffer, int32_t *px, int32_t *py)
#define MVT_PARSE_DATUM(type, kvtype, hash, valuefield, datumfunc, size)
static LWGEOM * mvt_grid_and_validate_geos(LWGEOM *ng, uint8_t basic_type)
Given a geometry, it uses GEOS operations to make sure that it's valid according to the MVT spec and ...
Datum buffer(PG_FUNCTION_ARGS)
struct mvt_kv_string_value * string_values_hash
struct mvt_kv_bool_value * bool_values_hash
struct mvt_kv_uint_value * uint_values_hash
VectorTile__Tile__Layer * layer
struct mvt_kv_float_value * float_values_hash
struct mvt_kv_sint_value * sint_values_hash
VectorTile__Tile__Feature * feature
struct mvt_kv_key * keys_hash
struct mvt_kv_double_value * double_values_hash
mvt_column_cache column_cache
uint32_t * column_keys_index
protobuf_c_boolean bool_value
#define HASH_CLEAR(hh, head)
#define HASH_ADD_KEYPTR(hh, head, keyptr, keylen_in, add)
#define HASH_FIND(hh, head, keyptr, keylen, out)