[postgis-tickets] r17169 - ST_AsMVTGeom: Transform coordinates space before clipping

Raul raul at rmr.ninja
Fri Jan 18 03:52:27 PST 2019


Author: algunenano
Date: 2019-01-18 03:52:27 -0800 (Fri, 18 Jan 2019)
New Revision: 17169

Modified:
   branches/2.4/NEWS
   branches/2.4/postgis/mvt.c
   branches/2.4/regress/mvt.sql
   branches/2.4/regress/mvt_expected
Log:
ST_AsMVTGeom: Transform coordinates space before clipping

References #4300



Modified: branches/2.4/NEWS
===================================================================
--- branches/2.4/NEWS	2019-01-17 23:22:17 UTC (rev 17168)
+++ branches/2.4/NEWS	2019-01-18 11:52:27 UTC (rev 17169)
@@ -1,7 +1,7 @@
 PostGIS 2.4.7
 2019/xx/xx
 
-  * Bug Fixes and Enchantments *
+  * Bug Fixes and Enhancements *
 
   - #4139, Make mixed-dimension ND index build tree correctly.
   WARNING: REINDEX your ND index on tables that have records with different M/Z
@@ -11,6 +11,7 @@
   - #4267, Enable Proj 6 deprecated APIs (Darafei Praliaskouski, Raúl Marín)
   - #4290, More robust distance calculations in geography (Paul Ramsey)
   - #4292, ST_AsMVT: parse JSON numeric values with decimals as doubles (Raúl Marín)
+  - #4300, ST_AsMVTGeom: Transform coordinates space before clipping (Raúl Marín)
 
 
 PostGIS 2.4.6

Modified: branches/2.4/postgis/mvt.c
===================================================================
--- branches/2.4/postgis/mvt.c	2019-01-17 23:22:17 UTC (rev 17168)
+++ branches/2.4/postgis/mvt.c	2019-01-18 11:52:27 UTC (rev 17169)
@@ -638,20 +638,70 @@
 
 	POSTGIS_DEBUGF(3, "parse_values n_tags %zd", ctx->feature->n_tags);
 }
-static int max_type(LWCOLLECTION *lwcoll)
+
+/* For a given geometry, look for the highest dimensional basic type, that is,
+ * point, line or polygon */
+static uint8
+lwgeom_get_basic_type(LWGEOM *geom)
 {
-	int i, max = POINTTYPE;
-	for (i = 0; i < lwcoll->ngeoms; i++) {
-		uint8_t type = lwcoll->geoms[i]->type;
-		if (type == POLYGONTYPE || type == MULTIPOLYGONTYPE)
-			return POLYGONTYPE;
-		else if (type == LINETYPE || type == MULTILINETYPE)
-			max = LINETYPE;
+	switch(geom->type)
+	{
+	case POINTTYPE:
+	case LINETYPE:
+	case POLYGONTYPE:
+		return geom->type;
+	case MULTIPOINTTYPE:
+	case MULTILINETYPE:
+	case MULTIPOLYGONTYPE:
+		return geom->type - 3; /* Based on LWTYPE positions */
+	case COLLECTIONTYPE:
+	{
+		uint32_t i;
+		uint8 type = 0;
+		LWCOLLECTION *g = (LWCOLLECTION*)geom;
+		for (i = 0; i < g->ngeoms; i++)
+		{
+			LWGEOM *sg = g->geoms[i];
+			type = Max(type, lwgeom_get_basic_type(sg));
+		}
+		return type;
 	}
-	return max;
+	default:
+		elog(ERROR, "%s: Invalid type (%d)", __func__, geom->type);
+	}
 }
 
 /**
+ * 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 inline LWGEOM *
+lwgeom_to_basic_type(LWGEOM *geom, uint8 original_type)
+{
+	LWGEOM *geom_out = geom;
+	if (lwgeom_get_type(geom) == COLLECTIONTYPE)
+	{
+		LWCOLLECTION *g = (LWCOLLECTION*)geom;
+		geom_out = (LWGEOM *)lwcollection_extract(g, original_type);
+	}
+
+	/* If a collection only contains 1 geometry return than instead */
+	if (lwgeom_is_collection(geom_out))
+	{
+		LWCOLLECTION *g = (LWCOLLECTION *)geom_out;
+		if (g->ngeoms == 1)
+		{
+			geom_out = g->geoms[0];
+		}
+	}
+
+	geom_out->srid = geom->srid;
+	return geom_out;
+}
+
+/**
  * Transform a geometry into vector tile coordinate space.
  *
  * Makes best effort to keep validity. Might collapse geometry into lower
@@ -665,11 +715,9 @@
 	LWGEOM *lwgeom_out = NULL;
 	double width = gbox->xmax - gbox->xmin;
 	double height = gbox->ymax - gbox->ymin;
-	double resx = width / extent;
 	double fx = extent / width;
 	double fy = -(extent / height);
-	double buffer_map_xunits = resx * buffer;
-	const GBOX *ggbox;
+	uint8_t basic_type;
 	POSTGIS_DEBUG(2, "mvt_geom called");
 
 	/* Short circuit out on EMPTY */
@@ -676,7 +724,6 @@
 	if (lwgeom_is_empty(lwgeom))
 		return NULL;
 
-	ggbox = lwgeom_get_bbox(lwgeom);
 	if (width == 0 || height == 0)
 		elog(ERROR, "mvt_geom: bounds width or height cannot be 0");
 
@@ -683,95 +730,89 @@
 	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(ggbox, bgbox)) {
+	lwgeom_out = lwgeom_clone_deep(lwgeom);
+	basic_type = lwgeom_get_basic_type(lwgeom_out);
+
+	/* transform to tile coordinate space */
+	memset(&affine, 0, sizeof(affine));
+	affine.afac = fx;
+	affine.efac = fy;
+	affine.ifac = 1;
+	affine.xoff = -gbox->xmin * fx;
+	affine.yoff = -gbox->ymax * fy;
+	lwgeom_affine(lwgeom_out, &affine);
+
+	/* snap to integer precision, removing duplicate points */
+	memset(&grid, 0, sizeof(gridspec));
+	grid.ipx = 0;
+	grid.ipy = 0;
+	grid.xsize = 1;
+	grid.ysize = 1;
+	lwgeom_out = lwgeom_grid(lwgeom_out, &grid);
+
+	if (lwgeom_out == NULL || lwgeom_is_empty(lwgeom_out))
+		return NULL;
+
+	if (clip_geom)
+	{
+		GBOX bgbox, lwgeom_gbox;
+		gbox_init(&bgbox);
+		gbox_init(&lwgeom_gbox);
+		bgbox.xmax = bgbox.ymax = (double)extent + (double)buffer;
+		bgbox.xmin = bgbox.ymin = -(double)buffer;
+		FLAGS_SET_GEODETIC(lwgeom_gbox.flags, 0);
+		FLAGS_SET_GEODETIC(bgbox.flags, 0);
+		lwgeom_calculate_gbox(lwgeom_out, &lwgeom_gbox);
+
+ 		if (!gbox_overlaps_2d(&lwgeom_gbox, &bgbox))
+		{
 			POSTGIS_DEBUG(3, "mvt_geom: geometry outside clip box");
 			return NULL;
 		}
-		if (!gbox_contains_2d(bgbox, ggbox)) {
-			double x0 = bgbox->xmin;
-			double y0 = bgbox->ymin;
-			double x1 = bgbox->xmax;
-			double y1 = bgbox->ymax;
+
+ 		if (!gbox_contains_2d(&bgbox, &lwgeom_gbox))
+		{
+			LWGEOM *clipped_geom;
 #if POSTGIS_GEOS_VERSION < 35
-			LWPOLY *lwenv = lwpoly_construct_envelope(0, x0, y0, x1, y1);
-			lwgeom_out = lwgeom_intersection(lwgeom, lwpoly_as_lwgeom(lwenv));
+			LWPOLY *lwenv = lwpoly_construct_envelope(0, bgbox.xmin, bgbox.ymin, bgbox.xmax, bgbox.ymax);
+			clipped_geom = lwgeom_intersection(lwgeom_out, lwpoly_as_lwgeom(lwenv));
 			lwpoly_free(lwenv);
-			if (lwgeom_out == NULL || lwgeom_is_empty(lwgeom_out))
-			{
-				POSTGIS_DEBUG(3, "mvt_geom: no geometry after clip");
-				return NULL;
-			}
 #else
-			const GBOX pre_clip_box = *lwgeom_get_bbox(lwgeom);
-			LWGEOM *clipped_geom = lwgeom_clip_by_rect(lwgeom, x0, y0, x1, y1);
+			clipped_geom = lwgeom_clip_by_rect(lwgeom_out, bgbox.xmin, bgbox.ymin, bgbox.xmax, bgbox.ymax);
+#endif
 			if (clipped_geom == NULL || lwgeom_is_empty(clipped_geom))
 			{
 				POSTGIS_DEBUG(3, "mvt_geom: no geometry after clip");
 				return NULL;
 			}
-			/* For some polygons, the simplify step might have left them
+
+ 			/* For some polygons, the simplify step might have left them
 			 * as invalid, which can cause clipping to return the complementary
 			 * geometry of what it should */
-			if ((lwgeom->type == POLYGONTYPE ||
-				lwgeom->type == MULTIPOLYGONTYPE ||
-				lwgeom->type == COLLECTIONTYPE) &&
-			    !gbox_contains_2d(&pre_clip_box, lwgeom_get_bbox(clipped_geom)))
+			if ((basic_type == POLYGONTYPE) &&
+			    !gbox_contains_2d(&lwgeom_gbox, lwgeom_get_bbox(clipped_geom)))
 			{
-				/* Other options would be to fix the geometry and
-				 * retry or to calculate the difference between the
-				 * 2 boxes */
+				/* TODO: Adapt this when and if Exception Policies are introduced.
+				 * Other options would be to fix the geometry and retry
+				 * or to calculate the difference between the 2 boxes.
+				 */
 				POSTGIS_DEBUG(3, "mvt_geom: Invalid geometry after clipping");
 				lwgeom_free(clipped_geom);
 				return NULL;
 			}
-			lwgeom_out = clipped_geom;
-#endif
 
+ 			lwgeom_out = clipped_geom;
 		}
 	}
 
-	/* if no clip output deep clone original to avoid mutation */
-	if (lwgeom_out == NULL)
-		lwgeom_out = lwgeom_clone_deep(lwgeom);
-
-	/* transform to tile coordinate space */
-	memset(&affine, 0, sizeof(affine));
-	affine.afac = fx;
-	affine.efac = fy;
-	affine.ifac = 1;
-	affine.xoff = -gbox->xmin * fx;
-	affine.yoff = -gbox->ymax * fy;
-	lwgeom_affine(lwgeom_out, &affine);
-
-	/* snap to integer precision, removing duplicate points */
-	memset(&grid, 0, sizeof(gridspec));
-	grid.ipx = 0;
-	grid.ipy = 0;
-	grid.xsize = 1;
-	grid.ysize = 1;
-	lwgeom_out = lwgeom_grid(lwgeom_out, &grid);
-
 	if (lwgeom_out == NULL || lwgeom_is_empty(lwgeom_out))
 		return NULL;
 
 	/* if polygon(s) make valid and force clockwise as per MVT spec */
-	if (lwgeom_out->type == POLYGONTYPE ||
-	    lwgeom_out->type == MULTIPOLYGONTYPE)
+	if (basic_type == POLYGONTYPE)
 	{
 		lwgeom_out = lwgeom_make_valid(lwgeom_out);
 
-		/* Drop type changes to play nice with MVT renderers */
-		if (!(lwgeom_out->type == POLYGONTYPE ||
-		      lwgeom_out->type == MULTIPOLYGONTYPE ||
-		      lwgeom_out->type == COLLECTIONTYPE))
-		{
-			lwgeom_free(lwgeom_out);
-			return NULL;
-		}
-
 		/* Because we are in image coordinates, we need to go to CCW in */
 		/* order to get a CW output in image space */
 		lwgeom_force_clockwise(lwgeom_out);
@@ -778,32 +819,23 @@
 		lwgeom_reverse(lwgeom_out);
 	}
 
-	/* if geometry collection extract highest dimensional geometry type */
-	if (lwgeom_out->type == COLLECTIONTYPE) {
-		LWCOLLECTION *lwcoll = lwgeom_as_lwcollection(lwgeom_out);
-		lwgeom_out = lwcollection_as_lwgeom(lwcollection_extract(lwcoll, max_type(lwcoll)));
-		lwgeom_out = lwgeom_homogenize(lwgeom_out);
-		/* if polygon(s) make valid and force clockwise as per MVT spec */
-		if (lwgeom_out->type == POLYGONTYPE ||
-		    lwgeom_out->type == MULTIPOLYGONTYPE)
-		{
-			lwgeom_out = lwgeom_make_valid(lwgeom_out);
+	/* Make sure we return the most basic type after simplification and validation */
+	lwgeom_out = lwgeom_to_basic_type(lwgeom_out, basic_type);
+	if (basic_type != lwgeom_get_basic_type(lwgeom_out))
+	{
+		/* Drop type changes to play nice with MVT renderers */
+		POSTGIS_DEBUG(3, "mvt_geom: Dropping geometry after type change");
+		return NULL;
+	}
 
-			/* Drop type changes to play nice with MVT renderers */
-			if (!(lwgeom_out->type == POLYGONTYPE ||
-				lwgeom_out->type == MULTIPOLYGONTYPE))
-			{
-				lwgeom_free(lwgeom_out);
-				return NULL;
-			}
+	if (lwgeom_out == NULL || lwgeom_is_empty(lwgeom_out))
+		return NULL;
 
-			/* Because we are in image coordinates, we need to go to CCW in */
-			/* order to get a CW output in image space */
-			lwgeom_force_clockwise(lwgeom_out);
-			lwgeom_reverse(lwgeom_out);
-		}
-	}
 
+	/* Clipping and validation might produce float values. Grid again into int
+	 * and pray that the output is still valid */
+	lwgeom_out = lwgeom_grid(lwgeom_out, &grid);
+
 	if (lwgeom_out == NULL || lwgeom_is_empty(lwgeom_out))
 		return NULL;
 

Modified: branches/2.4/regress/mvt.sql
===================================================================
--- branches/2.4/regress/mvt.sql	2019-01-17 23:22:17 UTC (rev 17168)
+++ branches/2.4/regress/mvt.sql	2019-01-18 11:52:27 UTC (rev 17169)
@@ -1,48 +1,274 @@
 -- geometry preprocessing tests
-select 'PG1', ST_AsText(ST_Normalize(ST_AsMVTGeom(
+select 'PG1', ST_AsText(ST_AsMVTGeom(
 	ST_Point(1, 2),
 	ST_MakeBox2D(ST_Point(0, 0), ST_Point(4096, 4096)),
-	4096, 0, false)));
-select 'PG2', ST_AsText(ST_Normalize(ST_AsMVTGeom(
+	4096, 0, false));
+select 'PG2', ST_AsText(ST_AsMVTGeom(
 	ST_Point(1, 2),
 	ST_MakeBox2D(ST_Point(0, 0), ST_Point(4096*2, 4096*2)),
-	4096, 0, false)));
-select 'PG3', ST_AsText(ST_Normalize(ST_AsMVTGeom(
+	4096, 0, false));
+select 'PG3', ST_AsText(ST_AsMVTGeom(
 	ST_Point(1, 2),
 	ST_MakeBox2D(ST_Point(0, 0), ST_Point(4096/2, 4096/2)),
-	4096, 0, false)));
-select 'PG4', ST_AsText(ST_Normalize(ST_AsMVTGeom(
+	4096, 0, false));
+select 'PG4', ST_AsText(ST_AsMVTGeom(
 	ST_GeomFromText('POLYGON ((0 0, 10 0, 10 5, 0 -5, 0 0))'),
 	ST_MakeBox2D(ST_Point(0, 0), ST_Point(4096, 4096)),
-	4096, 0, false)));
-select 'PG5', ST_AsText(ST_Normalize(ST_AsMVTGeom(
+	4096, 0, false));
+select 'PG5', ST_AsText(ST_AsMVTGeom(
 	ST_GeomFromText('POLYGON ((0 0, 10 0, 10 5, 0 -5, 0 0))'),
 	ST_MakeBox2D(ST_Point(0, 0), ST_Point(4096*4096, 4096*4096)),
-	4096, 0, false)));
-select 'PG6', ST_AsText(ST_Normalize(ST_AsMVTGeom(
-	ST_GeomFromText('POLYGON ((762780 6474467, 717821 6797045, 1052826 6797045, 762780 6474467))'),
+	4096, 0, false));
+select 'PG6', ST_AsText(ST_AsMVTGeom(
+	ST_GeomFromText('POLYGON ((1052826 6797045, 762780 6474467, 717821 6797045, 1052826 6797045))'),
 	ST_MakeBox2D(ST_Point(626172.135625, 6261721.35625), ST_Point(1252344.27125, 6887893.49188)),
-	4096, 0, false)));
-select 'PG7', ST_AsText(ST_Normalize(ST_AsMVTGeom(
-    ST_GeomFromText('POLYGON((-7792023.4539488 1411512.60791779,-7785283.40665468 1406282.69482469,-7783978.88137195 1404858.20373788,-7782986.89858399 1402324.91434802,-7779028.02672366 1397370.31802772,
-        -7778652.06985644 1394387.75452545,-7779906.76953697 1393279.22658385,-7782212.33678782 1393293.14086794,-7784631.14401331 1394225.4151684,-7786257.27108231 1395867.40241344,-7783978.88137195 1395867.40241344,
-        -7783978.88137195 1396646.68250521,-7787752.03959369 1398469.72134299,-7795443.30325373 1405280.43988858,-7797717.16326269 1406217.73286975,-7798831.44531677 1406904.48130551,-7799311.5830898 1408004.24038921,
-        -7799085.10302919 1409159.72782477,-7798052.35381919 1411108.84582812,-7797789.63692662 1412213.40365339,-7798224.47868753 1414069.89725829,-7799003.5701851 1415694.42577482,-7799166.63587328 1416966.26267896,
-        -7797789.63692662 1417736.81850415,-7793160.38395328 1412417.61222784,-7792023.4539488 1411512.60791779))'),
-        ST_MakeBox2D(ST_Point(-20037508.34, 20037508.34), ST_Point(20037508.34, -20037508.34)),
-        4096, 10, true)));
-select 'PG8', ST_AsText(ST_Normalize(ST_AsMVTGeom(
-    ST_GeomFromText('GEOMETRYCOLLECTION(MULTIPOLYGON (((0 0, 10 0, 10 5, 0 -5, 0 0))))'),
-    ST_MakeBox2D(ST_Point(0, 0), ST_Point(4096, 4096)),
-    4096, 0, false)));
-select 'PG9', ST_AsText(ST_Normalize(ST_AsMVTGeom(
+	4096, 0, false));
+
+SELECT 'PG7', ST_AsText(ST_AsMVTGeom(
+	ST_GeomFromText('POLYGON((-7792023.4539488 1411512.60791779,-7785283.40665468 1406282.69482469,-7783978.88137195 1404858.20373788,-7782986.89858399 1402324.91434802,-7779028.02672366 1397370.31802772,
+	-7778652.06985644 1394387.75452545,-7779906.76953697 1393279.22658385,-7782212.33678782 1393293.14086794,-7784631.14401331 1394225.4151684,-7786257.27108231 1395867.40241344,-7783978.88137195 1395867.40241344,
+	-7783978.88137195 1396646.68250521,-7787752.03959369 1398469.72134299,-7795443.30325373 1405280.43988858,-7797717.16326269 1406217.73286975,-7798831.44531677 1406904.48130551,-7799311.5830898 1408004.24038921,
+	-7799085.10302919 1409159.72782477,-7798052.35381919 1411108.84582812,-7797789.63692662 1412213.40365339,-7798224.47868753 1414069.89725829,-7799003.5701851 1415694.42577482,-7799166.63587328 1416966.26267896,
+	-7797789.63692662 1417736.81850415,-7793160.38395328 1412417.61222784,-7792023.4539488 1411512.60791779))'),
+	ST_MakeBox2D(ST_Point(-20037508.34, -20037508.34), ST_Point(20037508.34, 20037508.34)),
+	4096, 10, true)) as g;
+
+select 'PG8', ST_AsText(ST_AsMVTGeom(
+	ST_GeomFromText('GEOMETRYCOLLECTION(MULTIPOLYGON (((0 0, 10 0, 10 5, 0 -5, 0 0))))'),
+	ST_MakeBox2D(ST_Point(0, 0), ST_Point(4096, 4096)),
+	4096, 0, false));
+select 'PG9', ST_Area(ST_AsMVTGeom(
 	ST_GeomFromText('POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))'),
 	ST_MakeBox2D(ST_Point(0, 0), ST_Point(5, 5)),
-	4096, 0, true)));
+	4096, 0, true));
+
+-- There shoulnd't be floating point values
+WITH geometry AS
+(
+	SELECT ST_AsMVTGeom(
+		ST_GeomFromText('POLYGON((5 0, 0 5, 0 0, 5 5, 5 0))'),
+		ST_MakeBox2D(ST_Point(0, 0), ST_Point(5, 5)),
+		5, 0, true) as g
+)
+SELECT  'PG9.1', ST_NumGeometries(g), ST_Area(g), ST_AsText(g) LIKE '%2.5%'as fvalue FROM geometry;
 SELECT 'PG10', ST_AsText(ST_AsMVTGeom(
 	'POINT EMPTY'::geometry,
 	'BOX(0 0,2 2)'::box2d));
 
+-- Clockwise Polygon
+SELECT 'PG11', ST_AsText(ST_AsMVTGeom(
+	ST_GeomFromText('POLYGON((10 10, 10 0, 0 0, 0 10, 10 10))'),
+	ST_MakeBox2D(ST_Point(0, 0), ST_Point(10, 10)),
+	10, 0, false));
+
+-- Same as PG11 but CCW
+SELECT 'PG12', ST_AsText(ST_AsMVTGeom(
+	ST_GeomFromText('POLYGON((0 0, 10 0, 10 10, 0 10, 0 0))'),
+	ST_MakeBox2D(ST_Point(0, 0), ST_Point(10, 10)),
+	10, 0, false));
+
+--- POLYGONS WITH INTERIOR RINGS
+-- Input: Exterior CW, interior CW
+-- Output: CW, CCW
+SELECT 'PG13', ST_AsText(ST_AsMVTGeom(
+	ST_GeomFromText('POLYGON((10 10, 10 0, 0 0, 0 10, 10 10), (9 9, 9 1, 1 1, 1 9, 9 9))'),
+	ST_MakeBox2D(ST_Point(0, 0), ST_Point(10, 10)),
+	10, 0, false));
+
+-- Input: Exterior CW, interior CCW
+-- Output: CW, CCW
+SELECT 'PG14', ST_AsText(ST_AsMVTGeom(
+	ST_GeomFromText('POLYGON((10 10, 10 0, 0 0, 0 10, 10 10), (1 1, 9 1, 9 9, 1 9, 1 1))'),
+	ST_MakeBox2D(ST_Point(0, 0), ST_Point(10, 10)),
+	10, 0, false));
+
+-- Input: Exterior CCW, interior CW
+-- Output: CW, CCW
+SELECT 'PG15', ST_AsText(ST_AsMVTGeom(
+	ST_GeomFromText('POLYGON((0 0, 10 0, 10 10, 0 10, 0 0), (9 9, 9 1, 1 1, 1 9, 9 9))'),
+	ST_MakeBox2D(ST_Point(0, 0), ST_Point(10, 10)),
+	10, 0, false));
+
+-- Input: Exterior CCW, interior CW
+-- Output: CW, CCW
+SELECT 'PG16', ST_AsText(ST_AsMVTGeom(
+	ST_GeomFromText('POLYGON((0 0, 10 0, 10 10, 0 10, 0 0), (9 9, 9 1, 1 1, 1 9, 9 9))'),
+	ST_MakeBox2D(ST_Point(0, 0), ST_Point(10, 10)),
+	10, 0, false));
+
+-- Input: CW, CW, CW, CW
+-- Output: CW, CCW, CW, CCW
+SELECT 'PG17', ST_Area(ST_AsMVTGeom(
+	ST_GeomFromText('POLYGON(
+		(10 10, 10 0, 0 0, 0 10, 10 10),
+		(9 9, 1 9, 1 1, 9 1, 9 9),
+		(8 8, 8 2, 2 2, 2 8, 8 8),
+		(7 7, 7 3, 3 3, 3 7, 7 7))'),
+	ST_MakeBox2D(ST_Point(0, 0), ST_Point(10, 10)),
+	10, 0, false));
+
+-- Multipoint
+SELECT 'PG18', ST_AsText(ST_AsMVTGeom(
+	ST_GeomFromText('MULTIPOINT(1 1, 3 2)'),
+	ST_MakeBox2D(ST_Point(0, 0), ST_Point(10, 10)),
+	10, 0, false));
+
+SELECT 'PG19', ST_AsText(ST_AsMVTGeom(
+	ST_GeomFromText('MULTIPOINT(25 17, 26 18)'),
+	ST_MakeBox2D(ST_Point(0, 0), ST_Point(4096, 4096)),
+	4096, 0, false));
+
+SELECT 'PG20', ST_AsText(ST_AsMVTGeom(
+	ST_GeomFromText('MULTIPOINT(10 10, 10 10)'),
+	ST_MakeBox2D(ST_Point(0, 0), ST_Point(4096, 4096)),
+	4096, 0, false));
+
+-- Linestring
+SELECT 'PG21', ST_AsText(ST_AsMVTGeom(
+	ST_GeomFromText('LINESTRING(1 1, 5 5)'),
+	ST_MakeBox2D(ST_Point(0, 0), ST_Point(10, 10)),
+	10, 0, false));
+
+SELECT 'PG22', ST_AsText(ST_AsMVTGeom(
+	ST_GeomFromText('LINESTRING(1 9, 1.01 9.01)'),
+	ST_MakeBox2D(ST_Point(0, 0), ST_Point(10, 10)),
+	10, 0, false));
+
+-- Multiline
+SELECT 'PG23', ST_AsText(ST_AsMVTGeom(
+	ST_GeomFromText('MULTILINESTRING((1 1, 5 5),(2 8, 5 5))'),
+	ST_MakeBox2D(ST_Point(0, 0), ST_Point(10, 10)),
+	10, 0, false));
+
+SELECT 'PG24', ST_AsText(ST_AsMVTGeom(
+	ST_GeomFromText('MULTILINESTRING((1 1, 5 5),(1 1, 5 5))'),
+	ST_MakeBox2D(ST_Point(0, 0), ST_Point(10, 10)),
+	10, 0, false));
+
+SELECT 'PG25', ST_AsText(ST_AsMVTGeom(
+	ST_GeomFromText('MULTILINESTRING((1 1, 501 501, 1001 1001),(2 2, 502 502, 1002 1002))'),
+	ST_MakeBox2D(ST_Point(0, 0), ST_Point(4096, 4096)),
+	4096, 0, false));
+
+-- Clipping right in the borders
+SELECT 'PG26', ST_AsText(ST_AsMVTGeom(
+	ST_Point(-1, -1),
+	ST_MakeBox2D(ST_Point(0, 0), ST_Point(10, 10)),
+	10, 1, true));
+
+SELECT 'PG27', ST_AsText(ST_AsMVTGeom(
+	ST_Point(-1, 11),
+	ST_MakeBox2D(ST_Point(0, 0), ST_Point(10, 10)),
+	10, 1, true));
+
+SELECT 'PG28', ST_AsText(ST_AsMVTGeom(
+	ST_Point(11, -1),
+	ST_MakeBox2D(ST_Point(0, 0), ST_Point(10, 10)),
+	10, 1, true));
+
+SELECT 'PG29', ST_AsText(ST_AsMVTGeom(
+	ST_Point(11, 11),
+	ST_MakeBox2D(ST_Point(0, 0), ST_Point(10, 10)),
+	10, 1, true));
+
+SELECT 'PG30', ST_AsText(ST_AsMVTGeom(
+	ST_Point(11.5, 11.5),
+	ST_MakeBox2D(ST_Point(0, 0), ST_Point(10, 10)),
+	10, 1, true));
+
+SELECT 'PG31', ST_AsText(ST_AsMVTGeom(
+	ST_Point(11.49, 11.49),
+	ST_MakeBox2D(ST_Point(0, 0), ST_Point(10, 10)),
+	10, 1, true));
+
+SELECT 'PG32', ST_AsText(ST_AsMVTGeom(
+	ST_Point(-1.5, -1.5),
+	ST_MakeBox2D(ST_Point(0, 0), ST_Point(10, 10)),
+	10, 1, true));
+
+SELECT 'PG33', ST_AsText(ST_AsMVTGeom(
+	ST_Point(-1.49, -1.49),
+	ST_MakeBox2D(ST_Point(0, 0), ST_Point(10, 10)),
+	10, 1, true));
+
+SELECT 'PG34', ST_AsText(ST_AsMVTGeom(
+	ST_Point(-1.5, 11.5),
+	ST_MakeBox2D(ST_Point(0, 0), ST_Point(10, 10)),
+	10, 1, true));
+
+SELECT 'PG35', ST_AsText(ST_AsMVTGeom(
+	ST_Point(4352.49, -256.49),
+	ST_MakeBox2D(ST_Point(0, 0), ST_Point(4096, 4096)),
+	4096, 256, true));
+
+SELECT 'PG36', ST_AsText(ST_AsMVTGeom(
+	ST_Point(4352.49, -256.51),
+	ST_MakeBox2D(ST_Point(0, 0), ST_Point(4096, 4096)),
+	4096, 256, true));
+
+SELECT 'PG37', ST_AsText(ST_AsMVTGeom(
+	ST_Point(4352.51, -256.49),
+	ST_MakeBox2D(ST_Point(0, 0), ST_Point(4096, 4096)),
+	4096, 256, true));
+
+SELECT 'PG38', ST_AsText(ST_AsMVTGeom(
+	ST_Point(4352.51, -256.51),
+	ST_MakeBox2D(ST_Point(0, 0), ST_Point(4096, 4096)),
+	4096, 256, true));
+
+SELECT 'PG39 - ON ', ST_AsText(ST_AsMVTGeom(
+	ST_GeomFromText('POLYGON((100 100, 100 90, 94 90, 94 96, 90 96, 90 80, 100 80, 100 0, 0 0, 0 100, 100 100))'),
+	ST_MakeBox2D(ST_Point(0, 0), ST_Point(100, 100)),
+	10, 0, true));
+
+SELECT 'PG39 - OFF', ST_AsText(ST_AsMVTGeom(
+	ST_GeomFromText('POLYGON((100 100, 100 90, 94 90, 94 96, 90 96, 90 80, 100 80, 100 0, 0 0, 0 100, 100 100))'),
+	ST_MakeBox2D(ST_Point(0, 0), ST_Point(100, 100)),
+	10, 0, false));
+
+-- Clipping isn't done since all points fall into the tile after grid
+SELECT 'PG40 - ON ', ST_AsText(ST_AsMVTGeom(
+	ST_GeomFromText('LINESTRING(0 0, 2 20, -2 40, -4 60, 4 80, 0 100)'),
+	ST_MakeBox2D(ST_Point(0, 0), ST_Point(100, 100)),
+	10, 0, true));
+
+SELECT 'PG40 - OFF', ST_AsText(ST_AsMVTGeom(
+	ST_GeomFromText('LINESTRING(0 0, 2 20, -2 40, -4 60, 4 80, 0 100)'),
+	ST_MakeBox2D(ST_Point(0, 0), ST_Point(100, 100)),
+	10, 0, false));
+
+-- Clipping isn't done since all points fall into the tile after grid
+SELECT 'PG41 - ON ', ST_AsText(ST_AsMVTGeom(
+	ST_GeomFromText('LINESTRING(0 0, 2 20, -2 40, -4 60, 4 80, 0 100, 10 100)'),
+	ST_MakeBox2D(ST_Point(0, 0), ST_Point(100, 100)),
+	10, 0, true));
+
+SELECT 'PG41 - OFF', ST_AsText(ST_AsMVTGeom(
+	ST_GeomFromText('LINESTRING(0 0, 2 20, -2 40, -4 60, 4 80, 0 100, 10 100)'),
+	ST_MakeBox2D(ST_Point(0, 0), ST_Point(100, 100)),
+	10, 0, false));
+
+SELECT 'PG42 - ON ', ST_AsText(ST_AsMVTGeom(
+	ST_GeomFromText('LINESTRING(0 0, 2 20, -2 40, -4 60, 4 80, 0 100, 11 100)'),
+	ST_MakeBox2D(ST_Point(0, 0), ST_Point(100, 100)),
+	10, 0, true));
+
+SELECT 'PG42 - OFF', ST_AsText(ST_AsMVTGeom(
+	ST_GeomFromText('LINESTRING(0 0, 2 20, -2 40, -4 60, 4 80, 0 100, 11 100)'),
+	ST_MakeBox2D(ST_Point(0, 0), ST_Point(100, 100)),
+	10, 0, false));
+
+-- Invalid polygon (intersection)
+SELECT 'PG43 - ON ', ST_AsText(ST_AsMVTGeom(
+	ST_GeomFromText('POLYGON((-10 -10, 110 110, -10 110, 110 -10, -10 -10))'),
+	ST_MakeBox2D(ST_Point(0, 0), ST_Point(100, 100)),
+	10, 0, true));
+
+SELECT 'PG43 - OFF', ST_AsText(ST_AsMVTGeom(
+	ST_GeomFromText('POLYGON((-10 -10, 110 110, -10 110, 110 -10, -10 -10))'),
+	ST_MakeBox2D(ST_Point(0, 0), ST_Point(100, 100)),
+	10, 0, false));
+
 -- Geometry type change
 SELECT 'PG44', ST_AsEWKT(ST_AsMVTGeom(
 	'SRID=3857;MULTIPOLYGON(((-8238038.43842083 4974073.00356281,-8238058.59985694 4974035.91194892,-8238046.74211362 4974077.68076013,-8238038.43842083 4974073.00356281)))'::geometry,
@@ -59,120 +285,279 @@
 	16,
 	true));
 
+-- Geometry type change of one geometry of the multipolygon used to fallback to multilinestring
+SELECT 'PG46', St_AsEWKT(ST_AsMVTGeom(
+	'SRID=3857;MULTIPOLYGON(((-8230285.21085987 4984959.60349704,-8230324.85567616 4984496.35685962,-8230307.1114228 4984654.46474466,-8230285.21085987 4984959.60349704)),((-8230327.54013683 4984444.33052449,-8230327.23971431 4984450.39401942,-8230327.26833036 4984449.87731981,-8230327.54013683 4984444.33052449)))'::geometry,
+	'SRID=3857;POLYGON((-8238077.16046316 4989809.20645631,-8238077.16046316 4980025.2668358,-8228293.22084265 4980025.2668358,-8228293.22084265 4989809.20645631,-8238077.16046316 4989809.20645631))'::geometry,
+	4096,
+	16,
+	true));
+
+-- Check polygon clipping
+--- Outside the tile
+SELECT 'PG47', ST_AsText(ST_AsMVTGeom(
+	ST_GeomFromText('POLYGON((-10 -10, -10 -5, -5 -5, -5 -10, -10 -10))'),
+	ST_MakeBox2D(ST_Point(0, 0), ST_Point(100, 100)),
+	100, 0, true));
+
+--- Outside the tile
+SELECT 'PG48', ST_AsText(ST_AsMVTGeom(
+	ST_GeomFromText('POLYGON((10 -10, 10 -5, 5 -5, 5 -10, 10 -10))'),
+	ST_MakeBox2D(ST_Point(0, 0), ST_Point(100, 100)),
+	100, 0, true));
+
+--- Outside the tile
+SELECT 'PG49', ST_AsText(ST_AsMVTGeom(
+	ST_GeomFromText('POLYGON((110 110, 110 105, 105 105, 105 110, 110 110))'),
+	ST_MakeBox2D(ST_Point(0, 0), ST_Point(100, 100)),
+	100, 0, true));
+
+--- Outside the tile
+SELECT 'PG50', ST_AsText(ST_AsMVTGeom(
+	ST_GeomFromText('POLYGON((10 -5, 10 0, 5 0, 5 -5, 10 -5))'),
+	ST_MakeBox2D(ST_Point(0, 0), ST_Point(100, 100)),
+	100, 0, true));
+
+--- Fully covers the tile
+SELECT 'PG51', ST_Area(ST_AsMVTGeom(
+	ST_GeomFromText('POLYGON((-10 110, -10 -10, 110 -10, 110 110, -10 110))'),
+	ST_MakeBox2D(ST_Point(0, 0), ST_Point(100, 100)),
+	100, 0, true));
+
+--- Partially in the tile
+SELECT 'PG52', ST_Area(ST_AsMVTGeom(
+	ST_GeomFromText('POLYGON((20 -10, 110 -10, 110 110, 20 110, 20 -10))'),
+	ST_MakeBox2D(ST_Point(0, 0), ST_Point(100, 100)),
+	100, 0, true));
+
+--- Partially in the tile
+SELECT 'PG53', ST_Area(ST_AsMVTGeom(
+	ST_GeomFromText('POLYGON((-20 10, 20 10, 20 40, -20 40, -20 10))'),
+	ST_MakeBox2D(ST_Point(0, 0), ST_Point(100, 100)),
+	100, 0, true));
+
+-- Simplification
+SELECT 'PG54', ST_AsText(ST_AsMVTGeom(
+	ST_GeomFromText('POLYGON((0 10, 100 10, 100 10.3, 0 10))'),
+	ST_MakeBox2D(ST_Point(0, 0), ST_Point(100, 100)),
+	100, 0, true));
+
+SELECT 'PG55', ST_AsText(ST_AsMVTGeom(
+	ST_GeomFromText('POLYGON((0 99.9, 99.9 99.9, 99.9 150, 0 150, 0 99.9))'),
+	ST_MakeBox2D(ST_Point(0, 0), ST_Point(100, 100)),
+	100, 0, true));
+
+SELECT 'PG56', ST_AsText(ST_AsMVTGeom(
+	ST_GeomFromText('POLYGON((0 0, 99.6 100, 100 99.6, 0 0))'),
+	ST_MakeBox2D(ST_Point(0, 0), ST_Point(100, 100)),
+	100, 0, true));
+
+-- This clips in float
+SELECT 'PG57', ST_AsText(ST_AsMVTGeom(
+	ST_GeomFromText('POLYGON((0 0, 0 99, 1 101, 100 100, 100 0, 0 0))'),
+	ST_MakeBox2D(ST_Point(0, 0), ST_Point(100, 100)),
+	100, 0, true));
+
+-- Geometrycollection test
+SELECT 'PG58', ST_AsText(ST_AsMVTGeom(
+	ST_GeomFromText('GEOMETRYCOLLECTION(MULTIPOLYGON(((0 0, 10 0, 10 10, 0 10, 0 0))), POINT(50 50))'),
+	ST_MakeBox2D(ST_Point(0, 0), ST_Point(100, 100)),
+	100, 0, true));
+
+SELECT 'PG59', ST_AsText(ST_AsMVTGeom(
+	ST_GeomFromText('GEOMETRYCOLLECTION(POINT(50 50), LINESTRING(10 10, 20 20), MULTIPOLYGON(((0 0, 10 0, 10 10, 0 10, 0 0))))'),
+	ST_MakeBox2D(ST_Point(0, 0), ST_Point(100, 100)),
+	100, 0, true));
+
+SELECT 'PG60', ST_AsText(ST_AsMVTGeom(
+	ST_GeomFromText('GEOMETRYCOLLECTION(POINT(50 50), GEOMETRYCOLLECTION(POINT(50 50), MULTIPOLYGON(((0 0, 10 0, 10 10, 0 10, 0 0)))))'),
+	ST_MakeBox2D(ST_Point(0, 0), ST_Point(100, 100)),
+	100, 0, true));
+
+SELECT 'PG61', ST_AsText(ST_AsMVTGeom(
+	ST_GeomFromText('GEOMETRYCOLLECTION(POINT(50 50), MULTIPOLYGON(((100 100, 110 100, 110 110, 100 110, 100 100))))'),
+	ST_MakeBox2D(ST_Point(0, 0), ST_Point(100, 100)),
+	100, 0, true));
+
+SELECT 'PG62', ST_AsText(ST_AsMVTGeom(
+	ST_GeomFromText('GEOMETRYCOLLECTION(LINESTRING(10 10, 20 20), POLYGON((0 0, 10 0, 10 10, 0 10, 0 0)), LINESTRING(20 20, 15 15))'),
+	ST_MakeBox2D(ST_Point(0, 0), ST_Point(100, 100)),
+	100, 0, true));
+
+SELECT 'PG63', ST_AsText(ST_AsMVTGeom(
+	ST_GeomFromText('GEOMETRYCOLLECTION(LINESTRING(10 10, 20 20), POLYGON((90 90, 110 90, 110 110, 90 110, 90 90)), LINESTRING(20 20, 15 15))'),
+	ST_MakeBox2D(ST_Point(0, 0), ST_Point(100, 100)),
+	100, 0, true));
+
+SELECT 'PG64', ST_AsText(ST_AsMVTGeom(
+	ST_GeomFromText('GEOMETRYCOLLECTION(MULTIPOLYGON EMPTY, POINT(50 50))'),
+	ST_MakeBox2D(ST_Point(0, 0), ST_Point(100, 100)),
+	100, 0, true));
+
 -- geometry encoding tests
 SELECT 'TG1', encode(ST_AsMVT(q, 'test', 4096, 'geom'), 'base64') FROM (SELECT 1 AS c1,
-    ST_Normalize(ST_AsMVTGeom(ST_GeomFromText('POINT(25 17)'),
-    ST_MakeBox2D(ST_Point(0, 0), ST_Point(4096, 4096)), 4096, 0, false)) AS geom) AS q;
+	ST_AsMVTGeom(ST_GeomFromText('POINT(25 17)'),
+		ST_MakeBox2D(ST_Point(0, 0), ST_Point(4096, 4096)), 4096, 0, false) AS geom) AS q;
 SELECT 'TG2', encode(ST_AsMVT(q, 'test', 4096, 'geom'), 'base64') FROM (SELECT 1 AS c1,
-    ST_Normalize(ST_AsMVTGeom(ST_GeomFromText('MULTIPOINT(25 17, 26 18)'),
-    ST_MakeBox2D(ST_Point(0, 0), ST_Point(4096, 4096)), 4096, 0, false)) AS geom) AS q;
+	ST_AsMVTGeom(ST_GeomFromText('MULTIPOINT(25 17, 26 18)'),
+		ST_MakeBox2D(ST_Point(0, 0), ST_Point(4096, 4096)), 4096, 0, false) AS geom) AS q;
 SELECT 'TG3', encode(ST_AsMVT(q, 'test', 4096, 'geom'), 'base64') FROM (SELECT 1 AS c1,
-    ST_Normalize(ST_AsMVTGeom(ST_GeomFromText('LINESTRING(0 0, 1000 1000)'),
-    ST_MakeBox2D(ST_Point(0, 0), ST_Point(4096, 4096)), 4096, 0, false)) AS geom) AS q;
+	ST_AsMVTGeom(ST_GeomFromText('LINESTRING(0 0, 1000 1000)'),
+		ST_MakeBox2D(ST_Point(0, 0), ST_Point(4096, 4096)), 4096, 0, false) AS geom) AS q;
 SELECT 'TG4', encode(ST_AsMVT(q, 'test', 4096, 'geom'), 'base64') FROM (SELECT 1 AS c1,
-    ST_Normalize(ST_AsMVTGeom(ST_GeomFromText('LINESTRING(0 0, 500 500, 1000 1000)'),
-    ST_MakeBox2D(ST_Point(0, 0), ST_Point(4096, 4096)), 4096, 0, false)) AS geom) AS q;
+	ST_AsMVTGeom(ST_GeomFromText('LINESTRING(0 0, 500 500, 1000 1000)'),
+		ST_MakeBox2D(ST_Point(0, 0), ST_Point(4096, 4096)), 4096, 0, false) AS geom) AS q;
 SELECT 'TG5', encode(ST_AsMVT(q, 'test', 4096, 'geom'), 'base64') FROM (SELECT 1 AS c1,
-    ST_Normalize(ST_AsMVTGeom(ST_GeomFromText('MULTILINESTRING((1 1, 501 501, 1001 1001),(2 2, 502 502, 1002 1002))'),
-    ST_MakeBox2D(ST_Point(0, 0), ST_Point(4096, 4096)), 4096, 0, false)) AS geom) AS q;
+	ST_AsMVTGeom(ST_GeomFromText('MULTILINESTRING((1 1, 501 501, 1001 1001),(2 2, 502 502, 1002 1002))'),
+		ST_MakeBox2D(ST_Point(0, 0), ST_Point(4096, 4096)), 4096, 0, false) AS geom) AS q;
 SELECT 'TG6', encode(ST_AsMVT(q, 'test', 4096, 'geom'), 'base64') FROM (SELECT 1 AS c1,
-    ST_Normalize(ST_AsMVTGeom(ST_GeomFromText('POLYGON ((35 10, 45 45, 15 40, 10 20, 35 10), (20 30, 35 35, 30 20, 20 30))'),
-    ST_MakeBox2D(ST_Point(0, 0), ST_Point(4096, 4096)), 4096, 0, false)) AS geom) AS q;
+	ST_AsMVTGeom(ST_GeomFromText('POLYGON ((45 45, 15 40, 10 20, 35 10, 45 45), (35 35, 30 20, 20 30, 35 35))'),
+		ST_MakeBox2D(ST_Point(0, 0), ST_Point(4096, 4096)), 4096, 0, false) AS geom) AS q;
 SELECT 'TG7', encode(ST_AsMVT(q, 'test', 4096, 'geom'), 'base64') FROM (SELECT 1 AS c1,
-    ST_Normalize(ST_AsMVTGeom(ST_GeomFromText('MULTIPOLYGON (((40 40, 20 45, 45 30, 40 40)), ((20 35, 10 30, 10 10, 30 5, 45 20, 20 35), (30 20, 20 15, 20 25, 30 20)))'),
-    ST_MakeBox2D(ST_Point(0, 0), ST_Point(4096, 4096)), 4096, 0, false)) AS geom) AS q;
+	ST_AsMVTGeom(ST_GeomFromText('MULTIPOLYGON(((20 35, 10 30, 10 10, 30 5, 45 20, 20 35), (20 25, 30 20, 20 15, 20 25)), ((20 45, 45 30, 40 40, 20 45)))'),
+		ST_MakeBox2D(ST_Point(0, 0), ST_Point(4096, 4096)), 4096, 0, false) AS geom) AS q;
 SELECT 'TG8', encode(ST_AsMVT(q, 'test', 4096, 'geom'), 'base64') FROM (SELECT 1 AS c1,
-    ST_Normalize(ST_AsMVTGeom(ST_GeomFromText('POINT(25 17)'),
-    ST_MakeBox2D(ST_Point(0, 0), ST_Point(4096, 4096)), 4096, 0, false)) AS geom) AS q;
+	ST_AsMVTGeom(ST_GeomFromText('POINT(25 17)'),
+		ST_MakeBox2D(ST_Point(0, 0), ST_Point(4096, 4096)), 4096, 0, false) AS geom) AS q;
 SELECT 'TG9', encode(ST_AsMVT(q, 'test', 4096, 'geom'), 'base64') FROM (SELECT 1 AS c1,
-    ST_Normalize(ST_AsMVTGeom(ST_GeomFromText('MULTIPOINT(25 17, -26 -18)'),
-    ST_MakeBox2D(ST_Point(0, 0), ST_Point(4096, 4096)), 4096, 0, false)) AS geom) AS q;
+	ST_AsMVTGeom(ST_GeomFromText('MULTIPOINT(25 17, -26 -18)'),
+		ST_MakeBox2D(ST_Point(0, 0), ST_Point(4096, 4096)), 4096, 0, false) AS geom) AS q;
 
 -- attribute encoding tests
 SELECT 'TA1', encode(ST_AsMVT(q, 'test', 4096, 'geom'), 'base64') FROM (SELECT 1 AS c1, 'abcd'::text AS c2,
-    ST_Normalize(ST_AsMVTGeom(ST_GeomFromText('POINT(25 17)'),
-    ST_MakeBox2D(ST_Point(0, 0), ST_Point(4096, 4096)), 4096, 0, false)) AS geom) AS q;
+	ST_AsMVTGeom(ST_GeomFromText('POINT(25 17)'),
+		ST_MakeBox2D(ST_Point(0, 0), ST_Point(4096, 4096)), 4096, 0, false) AS geom) AS q;
 SELECT 'TA2', encode(ST_AsMVT(q, 'test', 4096, 'geom'), 'base64') FROM (SELECT 1.1::double precision AS c1,
-    ST_Normalize(ST_AsMVTGeom(ST_GeomFromText('POINT(25 17)'),
-    ST_MakeBox2D(ST_Point(0, 0), ST_Point(4096, 4096)), 4096, 0, false)) AS geom) AS q;
+	ST_AsMVTGeom(ST_GeomFromText('POINT(25 17)'),
+		ST_MakeBox2D(ST_Point(0, 0), ST_Point(4096, 4096)), 4096, 0, false) AS geom) AS q;
 SELECT 'TA3', encode(ST_AsMVT(q, 'test',  4096, 'geom'), 'base64') FROM (SELECT NULL::integer AS c1,
-    ST_Normalize(ST_AsMVTGeom(ST_GeomFromText('POINT(25 17)'),
-    ST_MakeBox2D(ST_Point(0, 0), ST_Point(4096, 4096)), 4096, 0, false)) AS geom) AS q;
+	ST_AsMVTGeom(ST_GeomFromText('POINT(25 17)'),
+		ST_MakeBox2D(ST_Point(0, 0), ST_Point(4096, 4096)), 4096, 0, false) AS geom) AS q;
 SELECT 'TA4', encode(ST_AsMVT(q, 'test', 4096, 'geom'), 'base64') FROM (
-    SELECT 1 AS c1, ST_Normalize(ST_AsMVTGeom(ST_GeomFromText('POINT(25 17)'),
-    ST_MakeBox2D(ST_Point(0, 0), ST_Point(4096, 4096)), 4096, 0, false)) AS geom
-    UNION
-    SELECT 2 AS c1, ST_Normalize(ST_AsMVTGeom(ST_GeomFromText('POINT(25 17)'),
-    ST_MakeBox2D(ST_Point(0, 0), ST_Point(4096, 4096)), 4096, 0, false)) AS geom) AS q;
+	SELECT 1 AS c1, ST_AsMVTGeom(ST_GeomFromText('POINT(25 17)'),
+		ST_MakeBox2D(ST_Point(0, 0), ST_Point(4096, 4096)), 4096, 0, false) AS geom
+	UNION
+	SELECT 2 AS c1, ST_AsMVTGeom(ST_GeomFromText('POINT(25 17)'),
+		ST_MakeBox2D(ST_Point(0, 0), ST_Point(4096, 4096)), 4096, 0, false) AS geom ORDER BY c1) AS q;
 SELECT 'TA5', encode(ST_AsMVT(q, 'test', 4096, 'geom'), 'base64') FROM (SELECT
-    ST_Normalize(ST_AsMVTGeom(ST_GeomFromText('POINT(25 17)'),
-    ST_MakeBox2D(ST_Point(0, 0), ST_Point(4096, 4096)), 4096, 0, false)) AS geom, 1 AS c1, 'abcd'::text AS c2) AS q;
+	ST_AsMVTGeom(ST_GeomFromText('POINT(25 17)'),
+		ST_MakeBox2D(ST_Point(0, 0), ST_Point(4096, 4096)), 4096, 0, false) AS geom, 1 AS c1, 'abcd'::text AS c2) AS q;
 SELECT 'TA6', encode(ST_AsMVT(q, 'test', 4096, 'geom'), 'base64') FROM (SELECT 1 AS c1, -1 AS c2,
-    ST_Normalize(ST_AsMVTGeom(ST_GeomFromText('POINT(25 17)'),
-    ST_MakeBox2D(ST_Point(0, 0), ST_Point(4096, 4096)), 4096, 0, false)) AS geom) AS q;
+	ST_AsMVTGeom(ST_GeomFromText('POINT(25 17)'),
+		ST_MakeBox2D(ST_Point(0, 0), ST_Point(4096, 4096)), 4096, 0, false) AS geom) AS q;
 SELECT 'TA7', encode(ST_AsMVT(q, 'test', 4096, 'geom'), 'base64') FROM (
-    SELECT 'test' AS c1, ST_Normalize(ST_AsMVTGeom(ST_GeomFromText('POINT(25 17)'),
-    ST_MakeBox2D(ST_Point(0, 0), ST_Point(4096, 4096)), 4096, 0, false)) AS geom
-    UNION
-    SELECT 'test' AS c1, ST_Normalize(ST_AsMVTGeom(ST_GeomFromText('POINT(26 18)'),
-    ST_MakeBox2D(ST_Point(0, 0), ST_Point(4096, 4096)), 4096, 0, false)) AS geom
-    UNION
-    SELECT 'othertest' AS c1, ST_Normalize(ST_AsMVTGeom(ST_GeomFromText('POINT(26 18)'),
-    ST_MakeBox2D(ST_Point(0, 0), ST_Point(4096, 4096)), 4096, 0, false)) AS geom) AS q;
+	SELECT 'test' AS c1, 1 AS c2, ST_AsMVTGeom(ST_GeomFromText('POINT(25 17)'),
+		ST_MakeBox2D(ST_Point(0, 0), ST_Point(4096, 4096)), 4096, 0, false) AS geom
+	UNION
+	SELECT 'test' AS c1, 2 AS c2, ST_AsMVTGeom(ST_GeomFromText('POINT(26 18)'),
+		ST_MakeBox2D(ST_Point(0, 0), ST_Point(4096, 4096)), 4096, 0, false) AS geom
+	UNION
+	SELECT 'othertest' AS c1, 3 AS c2, ST_AsMVTGeom(ST_GeomFromText('POINT(26 18)'),
+		ST_MakeBox2D(ST_Point(0, 0), ST_Point(4096, 4096)), 4096, 0, false) AS geom ORDER BY c2) AS q;
 SELECT 'TA8', encode(ST_AsMVT(q, 'test', 4096, 'geom'), 'base64') FROM (
-    SELECT 1::int AS c1, ST_Normalize(ST_AsMVTGeom(ST_GeomFromText('POINT(25 17)'),
-    ST_MakeBox2D(ST_Point(0, 0), ST_Point(4096, 4096)), 4096, 0, false)) AS geom
-    UNION
-    SELECT 1::int AS c1, ST_Normalize(ST_AsMVTGeom(ST_GeomFromText('POINT(26 18)'),
-    ST_MakeBox2D(ST_Point(0, 0), ST_Point(4096, 4096)), 4096, 0, false)) AS geom
-    UNION
-    SELECT 2::int AS c1, ST_Normalize(ST_AsMVTGeom(ST_GeomFromText('POINT(26 18)'),
-    ST_MakeBox2D(ST_Point(0, 0), ST_Point(4096, 4096)), 4096, 0, false)) AS geom) AS q;
+	SELECT 1::int AS c1, 1 AS c2, ST_AsMVTGeom(ST_GeomFromText('POINT(25 17)'),
+		ST_MakeBox2D(ST_Point(0, 0), ST_Point(4096, 4096)), 4096, 0, false) AS geom
+	UNION
+	SELECT 1::int AS c1, 2 AS c2, ST_AsMVTGeom(ST_GeomFromText('POINT(26 18)'),
+		ST_MakeBox2D(ST_Point(0, 0), ST_Point(4096, 4096)), 4096, 0, false) AS geom
+	UNION
+	SELECT 2::int AS c1, 3 AS c2, ST_AsMVTGeom(ST_GeomFromText('POINT(26 18)'),
+		ST_MakeBox2D(ST_Point(0, 0), ST_Point(4096, 4096)), 4096, 0, false) AS geom ORDER BY c2) AS q;
 SELECT 'TA9', length(ST_AsMVT(q))
 FROM (
 	SELECT 1 AS c1, -1 AS c2,
-    ST_Normalize(ST_AsMVTGeom(
+	ST_AsMVTGeom(
 		'POINT(25 17)'::geometry,
 		ST_MakeBox2D(ST_Point(0, 0), ST_Point(4, 4))
-	)) AS geom
+	) AS geom
 ) AS q;
 SELECT 'TA10', length(ST_AsMVT(q))
 FROM (
 	SELECT 1 AS c1, -1 AS c2,
-    ST_Normalize(ST_AsMVTGeom(
+	ST_AsMVTGeom(
 		'POINT(25 17)'::geometry,
 		ST_MakeBox2D(ST_Point(0, 0), ST_Point(48, 48))
-	)) AS geom
+	) AS geom
 ) AS q;
 
+-- Strings and text
+SELECT 'TA11', encode(ST_AsMVT(q, 'test', 4096, 'geom'), 'base64') FROM (
+	SELECT 'AbcDfg'::varchar AS cstring,
+	       'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus sed nulla augue. Pellentesque ut vulputate ex. Nunc et odio placerat, lacinia lectus sed, fermentum sapien. Sed massa velit, ullamcorper et est quis, congue rhoncus orci. Suspendisse in ante varius, convallis enim ut, fermentum amet.'::text as ctext,
+	       ST_AsMVTGeom(ST_GeomFromText('POINT(25 17)'),
+		ST_MakeBox2D(ST_Point(0, 0), ST_Point(4096, 4096)), 4096, 0, false) AS geom
+) AS q;
 
+
+-- Check null attributes
+SELECT 'TA12', encode(ST_AsMVT(q, 'test', 4096, 'geom'), 'base64') FROM (
+	SELECT 1::int AS c1, NULL::double precision AS c2, ST_AsMVTGeom(ST_GeomFromText('POINT(25 17)'),
+		ST_MakeBox2D(ST_Point(0, 0), ST_Point(4096, 4096)), 4096, 0, false) AS geom
+	UNION
+	SELECT NULL AS c1, 2.0 AS c2, ST_AsMVTGeom(ST_GeomFromText('POINT(26 18)'),
+		ST_MakeBox2D(ST_Point(0, 0), ST_Point(4096, 4096)), 4096, 0, false) AS geom
+) AS q;
+
+SELECT 'TA13', encode(ST_AsMVT(q, 'test', 4096, 'geom'), 'base64') FROM (
+	SELECT 1::int AS c1, NULL::double precision AS c2, ST_AsMVTGeom(ST_GeomFromText('POINT(25 17)'),
+		ST_MakeBox2D(ST_Point(0, 0), ST_Point(4096, 4096)), 4096, 0, false) AS geom
+	UNION
+	SELECT 5 AS c1, 2.0 AS c2, null AS geom
+) AS q;
+
+-- Extra geometry as parameter (casted as string)
+SELECT 'TA14', encode(ST_AsMVT(q, 'test', 4096, 'geom'), 'base64') FROM
+(
+	SELECT geom, St_Expand(geom, 10) as other_geom FROM
+	(
+		SELECT 'SRID=3857;MULTILINESTRING((105209.784484008 5267849.91657293,102374.204885822 5266414.05020624,99717.9874419115 5267379.35282178,90157.5689699989 5266091.78724987,86186.0622890498 5271349.34154337,78713.0972659854 5272871.78773217,76281.8581230672 5277951.00736649,81783.372341432 5289800.59747023))'::geometry as geom
+	) _sq
+) AS q;
+
+-- Numeric: Currently being casted as strings
+SELECT 'TA15', encode(ST_AsMVT(q, 'test', 4096, 'geom'), 'base64') FROM
+(
+	SELECT 1::numeric AS c1, '12.232389283223239'::numeric AS c2,
+	       '1' AS cstring, ST_AsMVTGeom(ST_GeomFromText('POINT(25 17)'),
+			ST_MakeBox2D(ST_Point(0, 0), ST_Point(4096, 4096)), 4096, 0, false) AS geom
+) AS q;
+
 -- default values tests
 SELECT 'D1', encode(ST_AsMVT(q, 'test', 4096, 'geom'), 'base64') FROM (SELECT 1 AS c1, 'abcd'::text AS c2,
-    ST_Normalize(ST_AsMVTGeom(ST_GeomFromText('POINT(25 17)'),
-    ST_MakeBox2D(ST_Point(0, 0), ST_Point(4096, 4096)), 4096, 0, false)) AS geom) AS q;
+	ST_AsMVTGeom(ST_GeomFromText('POINT(25 17)'),
+		ST_MakeBox2D(ST_Point(0, 0), ST_Point(4096, 4096)), 4096, 0, false) AS geom) AS q;
 SELECT 'D2', encode(ST_AsMVT(q, 'test', 4096), 'base64') FROM (SELECT 1 AS c1, 'abcd'::text AS c2,
-    ST_Normalize(ST_AsMVTGeom(ST_GeomFromText('POINT(25 17)'),
-    ST_MakeBox2D(ST_Point(0, 0), ST_Point(4096, 4096)), 4096, 0, false)) AS geom) AS q;
+	ST_AsMVTGeom(ST_GeomFromText('POINT(25 17)'),
+		ST_MakeBox2D(ST_Point(0, 0), ST_Point(4096, 4096)), 4096, 0, false) AS geom) AS q;
 SELECT 'D3', encode(ST_AsMVT(q, 'test'), 'base64') FROM (SELECT 1 AS c1, 'abcd'::text AS c2,
-    ST_Normalize(ST_AsMVTGeom(ST_GeomFromText('POINT(25 17)'),
-    ST_MakeBox2D(ST_Point(0, 0), ST_Point(4096, 4096)), 4096, 0, false)) AS geom) AS q;
+	ST_AsMVTGeom(ST_GeomFromText('POINT(25 17)'),
+		ST_MakeBox2D(ST_Point(0, 0), ST_Point(4096, 4096)), 4096, 0, false) AS geom) AS q;
 SELECT 'D4', encode(ST_AsMVT(q), 'base64') FROM (SELECT 1 AS c1, 'abcd'::text AS c2,
-    ST_Normalize(ST_AsMVTGeom(ST_GeomFromText('POINT(25 17)'),
-    ST_MakeBox2D(ST_Point(0, 0), ST_Point(4096, 4096)), 4096, 0, false)) AS geom) AS q;
-select 'D5', ST_AsText(ST_Normalize(ST_AsMVTGeom(
+	ST_AsMVTGeom(ST_GeomFromText('POINT(25 17)'),
+		ST_MakeBox2D(ST_Point(0, 0), ST_Point(4096, 4096)), 4096, 0, false) AS geom) AS q;
+select 'D5', ST_AsText(ST_AsMVTGeom(
 	ST_Point(1, 2),
 	ST_MakeBox2D(ST_Point(0, 0), ST_Point(4096, 4096)),
-	4096, 0)));
-select 'D6', ST_AsText(ST_Normalize(ST_AsMVTGeom(
+	4096, 0));
+select 'D6', ST_AsText(ST_AsMVTGeom(
 	ST_Point(1, 2),
 	ST_MakeBox2D(ST_Point(0, 0), ST_Point(4096, 4096)),
-	4096)));
-select 'D7', ST_AsText(ST_Normalize(ST_AsMVTGeom(
+	4096));
+select 'D7', ST_AsText(ST_AsMVTGeom(
 	ST_Point(1, 2),
-	ST_MakeBox2D(ST_Point(0, 0), ST_Point(4096, 4096)))));
+	ST_MakeBox2D(ST_Point(0, 0), ST_Point(4096, 4096))));
 
 -- unsupported input
 SELECT 'TU2';
 SELECT encode(ST_AsMVT(1, 'test', 4096, 'geom'), 'base64');
 SELECT 'TU3', encode(ST_AsMVT(q, 'test', 4096, 'geom'), 'base64')
-    FROM (SELECT NULL::integer AS c1, NULL AS geom) AS q;
+	FROM (SELECT NULL::integer AS c1, NULL AS geom) AS q;
+
+-- Ticket #3922
+SELECT '#3922', St_Area(ST_AsMVTGeom(
+		st_geomfromtwkb('\x06000104a501d0a7db06dad0940120ee030660229604109c010ed6011246143e76201a22b401a601f001b801580ef40122d803ca01de0cf00e80049204ac02b602be0138ca08bc02d605d201d2013cb804a401be013c9c03cd028608c106f001c1018601c7011e970125f10207439b02850a76ff0415030d0725431973132f227768671a5f133f17290865e405ba0154ab030415348502cc038d120c37d326c706850896109f01e201350f6f0a1903930165830121412d052928651d2b0d0f1107170b490c33120f010f0813034f47f50259190181031b3713ed04d901bd01439b02639507c10201021062054c1d3c101e6a0c2000684e6a7c1a681f443d160f044f0f490f03020b08051c01080c0e18013a012801380e08005808522d3a4c1c062a0f0e192a190a3b22194803261c1376122ac201d8011a101c065a17a8011c303206460c164a18a4015c56620801162d1404a402c601262a143002421222290f7b581d0719011d0311002908250a25021d030f0111030f05a3014315050d05110383011b9d011f3309a70347170325058b03417515130361190b4e19b40105fe208810041314041018270705c0039d0416251a1213241b0ffd02f5029408d001990218110607100c070a0b0819031c263432302454322a1e262a101e2a521426101c0c10101210
 121e18341c321c2c1c26222230162a10320c280e3202080e26123e0a2c041a002805360002051e010807161b281b1e1312010213101b14150e0906130c331e3518250e250c230a1d0a110e091407140718031a0008031a03140112093a199a01199801052e04100a0c120a4a0c7e1e2406220c4e20b60236c8013014020c0510090a110e1b0e11140d18021c08261054261417080f082504a702ea012c58068801180e0f1477209301082f062f00271f0b4b17170311020d100b180d180b0c1502190019031f09512d9b01592a1f120d0c0f0a15126b0637060f100b16032c0a2a1410120c120a240014011a03160314001482010100810900311753478d0117218b02b3027a692223745b2a111e031e130403061902691aa50118752ea70158045818562cae0170202614200e2e208a012e6c4a154c33448b01242f34651e2b221d481f2017122334a1010a510f2b6d8d021d5f073304351233242bce01772a251c3106291b4b032110351c2324239c016f260f5c138a01074e14261422282844221c7a24779a022db90127450b174319b501019b015a61b00105782a4e2a7615741305313a14422a4a079c01519001c9019c013388017352291c371c4110497e26442a8a0108502a2e2e19100980011984010b0e01840136042e1a6a22781f32356813280104370a5b12a5012b533e07482
 44e3e54355c064a45880115289d01103904453e810127290b5103a70152174841680b10254814402a4e305e82017232581792010522512e2516370023380b9801125434584c2a3e5202042f4e390f2f0e050205001f0801380d00430515421744fd01311b16614c038001241a482c3e44061e0a3881012605244d0e2d5d291a192c5710759d01284b20150f752308530a7f198101113d145d1f13534727290a291f490f4b0215246b196929752d2f2581012675371d432f090c4d2c0d080b141f0a0034051401110735152921055940010a023c0c0c35030519270825382f104512753e014001ae013b041708356ced012a0f7c2d041d0415631507e501012f0a491327411d1b310811072947493d0843125f4b7b16'),
+		'SRID=3347;POLYGON((3658201 658873,3658201 5958872.97428571,8958201.49428571 5958872.97428571,8958201.49428571 658873,3658201 658873))'::geometry,
+		4096,
+		0,
+		true
+		));

Modified: branches/2.4/regress/mvt_expected
===================================================================
--- branches/2.4/regress/mvt_expected	2019-01-17 23:22:17 UTC (rev 17168)
+++ branches/2.4/regress/mvt_expected	2019-01-18 11:52:27 UTC (rev 17169)
@@ -1,23 +1,81 @@
 PG1|POINT(1 4094)
 PG2|POINT(0 4095)
 PG3|POINT(2 4092)
-PG4|MULTIPOLYGON(((5 4096,10 4096,10 4091,5 4096)),((0 4096,0 4101,5 4096,0 4096)))
+PG4|MULTIPOLYGON(((5 4096,10 4091,10 4096,5 4096)),((5 4096,0 4101,0 4096,5 4096)))
 PG5|
-PG6|POLYGON((600 594,894 2704,2791 594,600 594))
-PG7|POLYGON((1251 1904,1252 1905,1253 1906,1253 1905,1252 1904,1251 1904))
-PG8|MULTIPOLYGON(((5 4096,10 4096,10 4091,5 4096)),((0 4096,0 4101,5 4096,0 4096)))
-PG9|POLYGON((0 0,0 4096,4096 4096,4096 0,0 0))
+PG6|POLYGON((2791 594,894 2704,600 594,2791 594))
+PG7|POLYGON((1251 1904,1252 1904,1253 1905,1253 1906,1252 1905,1251 1904))
+PG8|MULTIPOLYGON(((5 4096,10 4091,10 4096,5 4096)),((5 4096,0 4101,0 4096,5 4096)))
+PG9|16777216
+PG9.1|2|12.5|f
 PG10|
+PG11|POLYGON((10 0,10 10,0 10,0 0,10 0))
+PG12|POLYGON((0 10,0 0,10 0,10 10,0 10))
+PG13|POLYGON((10 0,10 10,0 10,0 0,10 0),(9 1,1 1,1 9,9 9,9 1))
+PG14|POLYGON((10 0,10 10,0 10,0 0,10 0),(1 9,9 9,9 1,1 1,1 9))
+PG15|POLYGON((0 10,0 0,10 0,10 10,0 10),(9 1,1 1,1 9,9 9,9 1))
+PG16|POLYGON((0 10,0 0,10 0,10 10,0 10),(9 1,1 1,1 9,9 9,9 1))
+PG17|56
+PG18|MULTIPOINT(1 9,3 8)
+PG19|MULTIPOINT(25 4079,26 4078)
+PG20|MULTIPOINT(10 4086,10 4086)
+PG21|LINESTRING(1 9,5 5)
+PG22|
+PG23|MULTILINESTRING((1 9,5 5),(2 2,5 5))
+PG24|MULTILINESTRING((1 9,5 5),(1 9,5 5))
+PG25|MULTILINESTRING((1 4095,501 3595,1001 3095),(2 4094,502 3594,1002 3094))
+PG26|POINT(-1 11)
+PG27|POINT(-1 -1)
+PG28|POINT(11 11)
+PG29|POINT(11 -1)
+PG30|
+PG31|POINT(11 -1)
+PG32|
+PG33|POINT(-1 11)
+PG34|
+PG35|POINT(4352 4352)
+PG36|
+PG37|
+PG38|
+PG39 - ON |POLYGON((9 1,9 2,10 2,10 10,0 10,0 0,9 0,10 0,10 1,9 1))
+PG39 - OFF|POLYGON((9 1,9 2,10 2,10 10,0 10,0 0,9 0,10 0,10 1,9 1))
+PG40 - ON |LINESTRING(0 10,0 8,0 6,0 4,0 2,0 0)
+PG40 - OFF|LINESTRING(0 10,0 8,0 6,0 4,0 2,0 0)
+PG41 - ON |LINESTRING(0 10,0 8,0 6,0 4,0 2,0 0,1 0)
+PG41 - OFF|LINESTRING(0 10,0 8,0 6,0 4,0 2,0 0,1 0)
+PG42 - ON |LINESTRING(0 10,0 8,0 6,0 4,0 2,0 0,1 0)
+PG42 - OFF|LINESTRING(0 10,0 8,0 6,0 4,0 2,0 0,1 0)
+PG43 - ON |MULTIPOLYGON(((5 5,0 0,10 0,5 5)),((5 5,10 10,0 10,5 5)))
+PG43 - OFF|MULTIPOLYGON(((5 5,-1 -1,11 -1,5 5)),((5 5,11 11,-1 11,5 5)))
 PG44|
 PG45|
+PG46|SRID=3857;POLYGON((3262 2030,3253 2158,3245 2224,3262 2030))
+PG47|
+PG48|
+PG49|
+PG50|
+PG51|10000
+PG52|8000
+PG53|600
+PG54|
+PG55|
+PG56|
+PG57|POLYGON((0 1,0 0,100 0,100 100,0 100,0 1))
+PG58|POLYGON((0 100,0 90,10 90,10 100,0 100))
+PG59|POLYGON((0 100,0 90,10 90,10 100,0 100))
+PG60|POLYGON((0 100,0 90,10 90,10 100,0 100))
+PG61|
+PG62|POLYGON((0 100,0 90,10 90,10 100,0 100))
+PG63|POLYGON((90 0,100 0,100 10,90 10,90 0))
+PG64|
 TG1|GiEKBHRlc3QSDBICAAAYASIECTLePxoCYzEiAigBKIAgeAI=
-TG2|GiMKBHRlc3QSDhICAAAYASIGETTcPwECGgJjMSICKAEogCB4Ag==
+TG2|GiMKBHRlc3QSDhICAAAYASIGETLePwIBGgJjMSICKAEogCB4Ag==
 TG3|GiYKBHRlc3QSERICAAAYAiIJCQCAQArQD88PGgJjMSICKAEogCB4Ag==
 TG4|GioKBHRlc3QSFRICAAAYAiINCQCAQBLoB+cH6AfnBxoCYzEiAigBKIAgeAI=
-TG5|GjgKBHRlc3QSIxICAAAYAiIbCQT8PxLoB+cH6AfnBwnRD9IPEugH5wfoB+cHGgJjMSICKAEogCB4
+TG5|GjgKBHRlc3QSIxICAAAYAiIbCQL+PxLoB+cH6AfnBwnND84PEugH5wfoB+cHGgJjMSICKAEogCB4
 Ag==
-TG6|GjIKBHRlc3QSHRICAAAYAyIVCRTYPxoyFBRFOwoPCQoUEh4JCR4PGgJjMSICKAEogCB4Ag==
-TG7|Gj0KBHRlc3QSKBICAAAYAyIgCRTEPyIAKCgKHh0xHQ8JABQSFAoTCg8JADsSMh4JEw8aAmMxIgIo
+TG6|GjIKBHRlc3QSHRICAAAYAyIVCVqmPxoTRjETCicPCSgKEh0KFBQPGgJjMSICKAEogCB4Ag==
+TG7|Gj0KBHRlc3QSKBICAAAYAyIgCSi6PyIyHh0eJwkAJw8JFAoSABQUCQ8JEzESKAoKFA8aAmMxIgIo
 ASiAIHgC
 TG8|GiEKBHRlc3QSDBICAAAYASIECTLePxoCYzEiAigBKIAgeAI=
 TG9|GiMKBHRlc3QSDhICAAAYASIGETLeP2VGGgJjMSICKAEogCB4Ag==
@@ -27,12 +85,29 @@
 TA4|GjMKBHRlc3QSDBICAAAYASIECTLePxIMEgIAARgBIgQJMt4/GgJjMSICKAEiAigCKIAgeAI=
 TA5|Gi8KBHRlc3QSDhIEAAABARgBIgQJMt4/GgJjMRoCYzIiAigBIgYKBGFiY2QogCB4Ag==
 TA6|GisKBHRlc3QSDhIEAAABARgBIgQJMt4/GgJjMRoCYzIiAigBIgIwASiAIHgC
-TA7|Gk4KBHRlc3QSDBICAAAYASIECTTcPxIMEgIAARgBIgQJMt4/EgwSAgABGAEiBAk03D8aAmMxIgsK
-CW90aGVydGVzdCIGCgR0ZXN0KIAgeAI=
-TA8|GkEKBHRlc3QSDBICAAAYASIECTLePxIMEgIAABgBIgQJNNw/EgwSAgABGAEiBAk03D8aAmMxIgIo
-ASICKAIogCB4Ag==
+TA7|GmQKBHRlc3QSDhIEAAABARgBIgQJMt4/Eg4SBAAAAQIYASIECTTcPxIOEgQAAwEEGAEiBAk03D8a
+AmMxGgJjMiIGCgR0ZXN0IgIoASICKAIiCwoJb3RoZXJ0ZXN0IgIoAyiAIHgC
+TA8|Gk8KBHRlc3QSDhIEAAABABgBIgQJMt4/Eg4SBAAAAQEYASIECTTcPxIOEgQAAQECGAEiBAk03D8a
+AmMxGgJjMiICKAEiAigCIgIoAyiAIHgC
 TA9|0
 TA10|49
+TA11|GucCCgR0ZXN0Eg4SBAAAAQEYASIECTLePxoHY3N0cmluZxoFY3RleHQiCAoGQWJjRGZnIq8CCqwC
+TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyIGFkaXBpc2NpbmcgZWxpdC4g
+UGhhc2VsbHVzIHNlZCBudWxsYSBhdWd1ZS4gUGVsbGVudGVzcXVlIHV0IHZ1bHB1dGF0ZSBleC4g
+TnVuYyBldCBvZGlvIHBsYWNlcmF0LCBsYWNpbmlhIGxlY3R1cyBzZWQsIGZlcm1lbnR1bSBzYXBp
+ZW4uIFNlZCBtYXNzYSB2ZWxpdCwgdWxsYW1jb3JwZXIgZXQgZXN0IHF1aXMsIGNvbmd1ZSByaG9u
+Y3VzIG9yY2kuIFN1c3BlbmRpc3NlIGluIGFudGUgdmFyaXVzLCBjb252YWxsaXMgZW5pbSB1dCwg
+ZmVybWVudHVtIGFtZXQuKIAgeAI=
+TA12|Gj4KBHRlc3QSDBICAAAYASIECTLePxIMEgIBARgBIgQJNNw/GgJjMRoCYzIiAigBIgkZAAAAAAAA
+AEAogCB4Ag==
+TA13|GiUKBHRlc3QSDBICAAAYASIECTLePxoCYzEaAmMyIgIoASiAIHgC
+TA14|GpACCgR0ZXN0Ei8SAgAAGAIiJwny6wyShoMFOqUstRbBKYoPr5UBjxSFPpRS4XTkF/8lsE/8VZK5
+ARoKb3RoZXJfZ2VvbSLFAQrCATAxMDMwMDAwMjAxMTBGMDAwMDAxMDAwMDAwMDUwMDAwMDBEOTQw
+REZCQUZEOUVGMjQwNDc0RDYyNzJBODE2NTQ0MUQ5NDBERkJBRkQ5RUYyNDBDN0YzM0NBNkQ0MkQ1
+NDQxNkExQTNGOEQzQ0IwRjk0MEM3RjMzQ0E2RDQyRDU0NDE2QTFBM0Y4RDNDQjBGOTQwNDc0RDYy
+NzJBODE2NTQ0MUQ5NDBERkJBRkQ5RUYyNDA0NzRENjI3MkE4MTY1NDQxKIAgeAI=
+TA15|GkkKBHRlc3QSEBIGAAABAQIAGAEiBAky3j8aAmMxGgJjMhoHY3N0cmluZyIDCgExIhQKEjEyLjIz
+MjM4OTI4MzIyMzIzOSiAIHgC
 D1|Gi8KBHRlc3QSDhIEAAABARgBIgQJMt4/GgJjMRoCYzIiAigBIgYKBGFiY2QogCB4Ag==
 D2|Gi8KBHRlc3QSDhIEAAABARgBIgQJMt4/GgJjMRoCYzIiAigBIgYKBGFiY2QogCB4Ag==
 D3|Gi8KBHRlc3QSDhIEAAABARgBIgQJMt4/GgJjMRoCYzIiAigBIgYKBGFiY2QogCB4Ag==
@@ -43,3 +118,4 @@
 TU2
 ERROR:  pgis_asmvt_transfn: parameter row cannot be other than a rowtype
 TU3|
+#3922|7.5



More information about the postgis-tickets mailing list