[postgis-tickets] r16096 - Apply simplification prior to affine / gridding stage in MVT geom processing
Paul Ramsey
pramsey at cleverelephant.ca
Wed Nov 8 12:25:28 PST 2017
Author: pramsey
Date: 2017-11-08 12:25:28 -0800 (Wed, 08 Nov 2017)
New Revision: 16096
Modified:
trunk/postgis/mvt.c
Log:
Apply simplification prior to affine / gridding stage in MVT geom processing
Modified: trunk/postgis/mvt.c
===================================================================
--- trunk/postgis/mvt.c 2017-11-07 18:31:37 UTC (rev 16095)
+++ trunk/postgis/mvt.c 2017-11-08 20:25:28 UTC (rev 16096)
@@ -638,6 +638,7 @@
POSTGIS_DEBUGF(3, "parse_values n_tags %zd", ctx->feature->n_tags);
}
+
static int max_type(LWCOLLECTION *lwcoll)
{
int i, max = POINTTYPE;
@@ -652,6 +653,38 @@
}
/**
+ * In place process a collection to find a concrete geometry
+ * object and expose that as the actual object. Will some
+ * geom be lost? Sure, but your MVT renderer couldn't
+ * draw it anyways.
+ */
+static void
+lwgeom_to_basic_type(LWGEOM *geom)
+{
+ if (lwgeom_get_type(geom) == COLLECTIONTYPE)
+ {
+ /* MVT doesn't handle generic collections, so we */
+ /* need to strip them down to a typed collection */
+ /* by finding the largest basic type available and */
+ /* using that as the basis of a typed collection. */
+ LWCOLLECTION *g = (LWCOLLECTION*)geom;
+ int i, maxtype = 0;
+ for (i = 0; i < g->ngeoms; i++)
+ {
+ LWGEOM *sg = g->geoms[i];
+ if (sg->type > maxtype && sg->type < COLLECTIONTYPE)
+ maxtype = sg->type;
+ }
+ if (maxtype > 3) maxtype -= 3;
+ /* Force the working geometry to be a simpler version */
+ /* of itself */
+ LWCOLLECTION *gc = lwcollection_extract(g, maxtype);
+ *g = *gc;
+ }
+ return;
+}
+
+/**
* Transform a geometry into vector tile coordinate space.
*
* Makes best effort to keep validity. Might collapse geometry into lower
@@ -667,35 +700,48 @@
double width = gbox->xmax - gbox->xmin;
double height = gbox->ymax - gbox->ymin;
double resx = width / extent;
+ double resy = height / extent;
+ double res = (resx < resy ? resx : resy)/2;
double fx = extent / width;
double fy = -(extent / height);
double buffer_map_xunits = resx * buffer;
- const GBOX *lwgeom_gbox;
+ int preserve_collapsed = LW_TRUE;
POSTGIS_DEBUG(2, "mvt_geom called");
/* Short circuit out on EMPTY */
if (lwgeom_is_empty(lwgeom))
return NULL;
- lwgeom_gbox = lwgeom_get_bbox(lwgeom);
if (width == 0 || height == 0)
elog(ERROR, "mvt_geom: bounds width or height cannot be 0");
if (extent == 0)
elog(ERROR, "mvt_geom: extent cannot be 0");
- if (clip_geom) {
- GBOX *bgbox = gbox_copy(gbox);
- gbox_expand(bgbox, buffer_map_xunits);
- if (!gbox_overlaps_2d(lwgeom_gbox, bgbox)) {
+ /* Remove all non-essential points (under the output resolution) */
+ lwgeom_remove_repeated_points_in_place(lwgeom, res);
+ lwgeom_simplify_in_place(lwgeom, res, preserve_collapsed);
+
+ /* If geometry has disappeared, you're done */
+ if (lwgeom_is_empty(lwgeom))
+ return NULL;
+
+ if (clip_geom)
+ {
+ const GBOX *lwgeom_gbox = lwgeom_get_bbox(lwgeom);;
+ GBOX bgbox = *gbox;
+ gbox_expand(&bgbox, buffer_map_xunits);
+ if (!gbox_overlaps_2d(lwgeom_gbox, &bgbox))
+ {
POSTGIS_DEBUG(3, "mvt_geom: geometry outside clip box");
return NULL;
}
- if (!gbox_contains_2d(bgbox, lwgeom_gbox)) {
- double x0 = bgbox->xmin;
- double y0 = bgbox->ymin;
- double x1 = bgbox->xmax;
- double y1 = bgbox->ymax;
+ if (!gbox_contains_2d(&bgbox, lwgeom_gbox))
+ {
+ double x0 = bgbox.xmin;
+ double y0 = bgbox.ymin;
+ double x1 = bgbox.xmax;
+ double y1 = bgbox.ymax;
#if POSTGIS_GEOS_VERSION < 35
LWPOLY *lwenv = lwpoly_construct_envelope(0, x0, y0, x1, y1);
lwgeom = lwgeom_intersection(lwgeom, lwpoly_as_lwgeom(lwenv));
@@ -730,23 +776,17 @@
return NULL;
/* if polygon(s) make valid and force clockwise as per MVT spec */
- if (lwgeom->type == POLYGONTYPE || lwgeom->type == MULTIPOLYGONTYPE) {
+ if (lwgeom->type == POLYGONTYPE ||
+ lwgeom->type == MULTIPOLYGONTYPE ||
+ lwgeom->type == COLLECTIONTYPE)
+ {
lwgeom = lwgeom_make_valid(lwgeom);
lwgeom_force_clockwise(lwgeom);
}
/* if geometry collection extract highest dimensional geometry type */
- if (lwgeom->type == COLLECTIONTYPE) {
- LWCOLLECTION *lwcoll = lwgeom_as_lwcollection(lwgeom);
- lwgeom = lwcollection_as_lwgeom(
- lwcollection_extract(lwcoll, max_type(lwcoll)));
- lwgeom = lwgeom_homogenize(lwgeom);
- /* if polygon(s) make valid and force clockwise as per MVT spec */
- if (lwgeom->type == POLYGONTYPE || lwgeom->type == MULTIPOLYGONTYPE) {
- lwgeom = lwgeom_make_valid(lwgeom);
- lwgeom_force_clockwise(lwgeom);
- }
- }
+ if (lwgeom->type == COLLECTIONTYPE)
+ lwgeom_to_basic_type(lwgeom);
if (lwgeom == NULL || lwgeom_is_empty(lwgeom))
return NULL;
More information about the postgis-tickets
mailing list