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

Raul raul at rmr.ninja
Fri Jan 18 03:53:43 PST 2019


Author: algunenano
Date: 2019-01-18 03:53:43 -0800 (Fri, 18 Jan 2019)
New Revision: 17170

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

References #4300


Modified: branches/2.5/NEWS
===================================================================
--- branches/2.5/NEWS	2019-01-18 11:52:27 UTC (rev 17169)
+++ branches/2.5/NEWS	2019-01-18 11:53:43 UTC (rev 17170)
@@ -28,7 +28,7 @@
   - #4273, Tighter parsing of WKT (Paul Ramsey)
 
   - #4292, ST_AsMVT: parse JSON numeric values with decimals as doubles (Raúl Marín)
- 
+
   - #4300, ST_AsMVTGeom: Always return the simplest geometry (Raúl Marín)
 
   - #4301, ST_Subdivide: fix endless loop on coordinates near coincident to bounds
@@ -36,7 +36,9 @@
 
   - #4261, Use AccessShareLock in spatial_index_read_extent (Paul Ramsey)
 
+  - #4300, ST_AsMVTGeom: Transform coordinates space before clipping (Raúl Marín)
 
+
 PostGIS 2.5.1
 2018/11/18
 

Modified: branches/2.5/postgis/mvt.c
===================================================================
--- branches/2.5/postgis/mvt.c	2019-01-18 11:52:27 UTC (rev 17169)
+++ branches/2.5/postgis/mvt.c	2019-01-18 11:53:43 UTC (rev 17170)
@@ -790,6 +790,86 @@
 	return geom_out;
 }
 
+static LWGEOM *
+mvt_clip_and_validate_geos(LWGEOM *lwgeom, uint8_t basic_type, uint32_t extent, uint32_t buffer, bool clip_geom)
+{
+	LWGEOM *ng = lwgeom;
+
+	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, &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, &lwgeom_gbox))
+		{
+			LWGEOM *clipped_geom =
+			    lwgeom_clip_by_rect(lwgeom, bgbox.xmin, bgbox.ymin, bgbox.xmax, bgbox.ymax);
+			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
+			 * as invalid, which can cause clipping to return the complementary
+			 * geometry of what it should */
+			if ((basic_type == POLYGONTYPE) &&
+			    !gbox_contains_2d(&lwgeom_gbox, lwgeom_get_bbox(clipped_geom)))
+			{
+				/* 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;
+			}
+
+			ng = clipped_geom;
+		}
+	}
+
+	if (basic_type == POLYGONTYPE)
+	{
+		/* Force validation as per MVT spec */
+		ng = lwgeom_make_valid(ng);
+
+		/* In image coordinates CW actually comes out a CCW, so we reverse */
+		lwgeom_force_clockwise(ng);
+		lwgeom_reverse_in_place(ng);
+	}
+
+	/* Make sure we return the most basic type after simplification and validation */
+	ng = lwgeom_to_basic_type(ng, basic_type);
+	if (basic_type != lwgeom_get_basic_type(ng))
+	{
+		/* Drop type changes to play nice with MVT renderers */
+		POSTGIS_DEBUG(3, "mvt_geom: Dropping geometry after type change");
+		return NULL;
+	}
+
+	/* Clipping and validation might produce float values. Grid again into int
+	 * and pray that the output is still valid */
+	{
+		gridspec grid = {0, 0, 0, 0, 1, 1, 0, 0};
+		lwgeom_grid_in_place(ng, &grid);
+	}
+
+	return ng;
+}
+
 /**
  * Transform a geometry into vector tile coordinate space.
  *
@@ -801,8 +881,8 @@
 LWGEOM *mvt_geom(LWGEOM *lwgeom, const GBOX *gbox, uint32_t extent, uint32_t buffer,
 	bool clip_geom)
 {
-	AFFINE affine;
-	gridspec grid;
+	AFFINE affine = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+	gridspec grid = {0, 0, 0, 0, 1, 1, 0, 0};
 	double width = gbox->xmax - gbox->xmin;
 	double height = gbox->ymax - gbox->ymin;
 	double resx, resy, res, fx, fy;
@@ -810,6 +890,9 @@
 	const uint8_t basic_type = lwgeom_get_basic_type(lwgeom);
 	POSTGIS_DEBUG(2, "mvt_geom called");
 
+	/* Simplify it as soon as possible */
+	lwgeom = lwgeom_to_basic_type(lwgeom, basic_type);
+
 	/* Short circuit out on EMPTY */
 	if (lwgeom_is_empty(lwgeom))
 		return NULL;
@@ -834,53 +917,7 @@
 	if (lwgeom_is_empty(lwgeom))
 		return NULL;
 
-	if (clip_geom)
-	{
-		// We need to add an extra half pixel to include the points that
-		// fall into the bbox only after the coordinate transformation
-		double buffer_map_xunits = nextafterf(res, 0.0) + resx * buffer;
-		GBOX bgbox;
-		const GBOX *lwgeom_gbox = lwgeom_get_bbox(lwgeom);
-		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;
-			const GBOX pre_clip_box = *lwgeom_get_bbox(lwgeom);
-			LWGEOM *clipped_geom = lwgeom_clip_by_rect(lwgeom, x0, y0, x1, y1);
-			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
-			 * as invalid, which can cause clipping to return the complementary
-			 * geometry of what it should */
-			if ((basic_type == POLYGONTYPE) &&
-			    !gbox_contains_2d(&pre_clip_box, lwgeom_get_bbox(clipped_geom)))
-			{
-				/* 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 = clipped_geom;
-		}
-	}
-
 	/* transform to tile coordinate space */
-	memset(&affine, 0, sizeof(affine));
 	affine.afac = fx;
 	affine.efac = fy;
 	affine.ifac = 1;
@@ -889,37 +926,12 @@
 	lwgeom_affine(lwgeom, &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_grid_in_place(lwgeom, &grid);
 
 	if (lwgeom == NULL || lwgeom_is_empty(lwgeom))
 		return NULL;
 
-
-	if (basic_type == POLYGONTYPE)
-	{
-		/* Force validation as per MVT spec */
-		lwgeom = lwgeom_make_valid(lwgeom);
-
-		/* In image coordinates CW actually comes out a CCW, so we reverse */
-		lwgeom_force_clockwise(lwgeom);
-		lwgeom_reverse_in_place(lwgeom);
-	}
-
-	/* if geometry collection extract highest dimensional geometry type */
-	lwgeom = lwgeom_to_basic_type(lwgeom, basic_type);
-
-	if (basic_type != lwgeom_get_basic_type(lwgeom))
-	{
-		/* Drop type changes to play nice with MVT renderers */
-		POSTGIS_DEBUG(3, "mvt_geom: Dropping geometry after type change");
-		return NULL;
-	}
-
+	lwgeom = mvt_clip_and_validate_geos(lwgeom, basic_type, extent, buffer, clip_geom);
 	if (lwgeom == NULL || lwgeom_is_empty(lwgeom))
 		return NULL;
 

Modified: branches/2.5/regress/mvt.sql
===================================================================
--- branches/2.5/regress/mvt.sql	2019-01-18 11:52:27 UTC (rev 17169)
+++ branches/2.5/regress/mvt.sql	2019-01-18 11:53:43 UTC (rev 17170)
@@ -20,10 +20,11 @@
 	ST_MakeBox2D(ST_Point(0, 0), ST_Point(4096*4096, 4096*4096)),
 	4096, 0, false));
 select 'PG6', ST_AsText(ST_AsMVTGeom(
-	ST_GeomFromText('POLYGON ((762780 6474467, 717821 6797045, 1052826 6797045, 762780 6474467))'),
+	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_AsMVTGeom(
+
+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,
@@ -30,15 +31,26 @@
 	-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));
+	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_AsText(ST_AsMVTGeom(
+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));
+
+-- 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));
@@ -45,7 +57,7 @@
 
 -- Clockwise Polygon
 SELECT 'PG11', ST_AsText(ST_AsMVTGeom(
-	ST_GeomFromText('POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))'),
+	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));
 
@@ -59,7 +71,7 @@
 -- Input: Exterior CW, interior CW
 -- Output: CW, CCW
 SELECT 'PG13', ST_AsText(ST_AsMVTGeom(
-	ST_GeomFromText('POLYGON((0 0, 0 10, 10 10, 10 0, 0 0), (1 1, 1 9, 9 9, 9 1, 1 1))'),
+	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));
 
@@ -66,7 +78,7 @@
 -- Input: Exterior CW, interior CCW
 -- Output: CW, CCW
 SELECT 'PG14', ST_AsText(ST_AsMVTGeom(
-	ST_GeomFromText('POLYGON((0 0, 0 10, 10 10, 10 0, 0 0), (1 1, 9 1, 9 9, 1 9, 1 1))'),
+	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));
 
@@ -73,7 +85,7 @@
 -- 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), (1 1, 1 9, 9 9, 9 1, 1 1))'),
+	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));
 
@@ -80,18 +92,18 @@
 -- 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), (1 1, 1 9, 9 9, 9 1, 1 1))'),
+	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_AsText(ST_AsMVTGeom(
+SELECT 'PG17', ST_Area(ST_AsMVTGeom(
 	ST_GeomFromText('POLYGON(
-		(0 0, 0 10, 10 10, 10 0, 0 0),
-		(1 1, 1  9,  9  9,  9 1, 1 1),
-		(2 2, 2  8,  8  8,  8 2, 2 2),
-		(3 3, 3  7,  7  7,  7 3, 3 3))'),
+		(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));
 
@@ -190,27 +202,27 @@
 	4096, 256, true));
 
 SELECT 'PG36', ST_AsText(ST_AsMVTGeom(
-	ST_Point(4352.49, -256.50),
+	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.50, -256.49),
+	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.50, -256.50),
+	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((0 100, 100 100, 100 90, 94 90, 94 96, 90 96, 90 80, 100 80, 100 0, 0 0, 0 100))'),
+	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((0 100, 100 100, 100 90, 94 90, 94 96, 90 96, 90 80, 100 80, 100 0, 0 0, 0 100))'),
+	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));
 
@@ -275,12 +287,113 @@
 
 -- Geometry type change of one geometry of the multipolygon used to fallback to multilinestring
 SELECT 'PG46', St_AsEWKT(ST_AsMVTGeom(
-	'SRID=3857;MULTIPOLYGON(((-8230324.85567616 4984496.35685962,-8230307.1114228 4984654.46474466,-8230285.21085987 4984959.60349704,-8230324.85567616 4984496.35685962)),((-8230327.54013683 4984444.33052449,-8230327.23971431 4984450.39401942,-8230327.26833036 4984449.87731981,-8230327.54013683 4984444.33052449)))'::geometry,
+	'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_AsMVTGeom(ST_GeomFromText('POINT(25 17)'),
@@ -298,10 +411,10 @@
 	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_AsMVTGeom(ST_GeomFromText('POLYGON ((35 10, 45 45, 15 40, 10 20, 35 10), (20 30, 35 35, 30 20, 20 30))'),
+	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_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_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_AsMVTGeom(ST_GeomFromText('POINT(25 17)'),
@@ -441,7 +554,7 @@
 	FROM (SELECT NULL::integer AS c1, NULL AS geom) AS q;
 
 -- Ticket #3922
-SELECT '#3922', St_AsEWKT(ST_AsMVTGeom(
+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,
@@ -448,4 +561,3 @@
 		0,
 		true
 		));
-

Modified: branches/2.5/regress/mvt_expected
===================================================================
--- branches/2.5/regress/mvt_expected	2019-01-18 11:52:27 UTC (rev 17169)
+++ branches/2.5/regress/mvt_expected	2019-01-18 11:53:43 UTC (rev 17170)
@@ -3,18 +3,19 @@
 PG3|POINT(2 4092)
 PG4|MULTIPOLYGON(((5 4096,10 4091,10 4096,5 4096)),((5 4096,0 4101,0 4096,5 4096)))
 PG5|
-PG6|POLYGON((894 2704,600 594,2791 594,894 2704))
+PG6|POLYGON((2791 594,894 2704,600 594,2791 594))
 PG7|POLYGON((1252 1904,1253 1905,1253 1906,1251 1904,1252 1904))
 PG8|MULTIPOLYGON(((5 4096,10 4091,10 4096,5 4096)),((5 4096,0 4101,0 4096,5 4096)))
-PG9|POLYGON((0 4096,0 0,4096 0,4096 4096,0 4096))
+PG9|16777216
+PG9.1|2|12.5|f
 PG10|
-PG11|POLYGON((0 10,0 0,10 0,10 10,0 10))
+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((0 10,0 0,10 0,10 10,0 10),(1 9,9 9,9 1,1 1,1 9))
-PG14|POLYGON((0 10,0 0,10 0,10 10,0 10),(1 9,9 9,9 1,1 1,1 9))
-PG15|POLYGON((0 10,0 0,10 0,10 10,0 10),(1 9,9 9,9 1,1 1,1 9))
-PG16|POLYGON((0 10,0 0,10 0,10 10,0 10),(1 9,9 9,9 1,1 1,1 9))
-PG17|MULTIPOLYGON(((0 10,0 0,10 0,10 10,0 10),(1 9,9 9,9 1,1 1,1 9)),((2 8,2 2,8 2,8 8,2 8),(3 7,7 7,7 3,3 3,3 7)))
+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|POINT(10 4086)
@@ -36,8 +37,8 @@
 PG36|
 PG37|
 PG38|
-PG39 - ON |POLYGON((0 0,10 0,9 2,10 2,10 10,0 10,0 0))
-PG39 - OFF|POLYGON((0 0,10 0,9 2,10 2,10 10,0 10,0 0))
+PG39 - ON |POLYGON((10 0,9 2,10 2,10 10,0 10,0 0,10 0))
+PG39 - OFF|POLYGON((10 0,9 2,10 2,10 10,0 10,0 0,10 0))
 PG40 - ON |LINESTRING(0 10,0 0)
 PG40 - OFF|LINESTRING(0 10,0 0)
 PG41 - ON |LINESTRING(0 10,0 4,0 2,0 0,1 0)
@@ -44,18 +45,36 @@
 PG41 - OFF|LINESTRING(0 10,0 4,0 2,0 0,1 0)
 PG42 - ON |LINESTRING(0 10,0 0,1 0)
 PG42 - OFF|LINESTRING(0 10,0 0,1 0)
-PG43 - ON |MULTIPOLYGON(((5 5,0 0,10 0,5 5)),((0 10,5 5,10 10,0 10)))
+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((3245 2224,3262 2030,3253 2158,3245 2224))
+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|GiMKBHRlc3QSDhICAAAYASIGETLePwIBGgJjMSICKAEogCB4Ag==
 TG3|GiYKBHRlc3QSERICAAAYAiIJCQCAQArQD88PGgJjMSICKAEogCB4Ag==
 TG4|GiYKBHRlc3QSERICAAAYAiIJCQCAQArQD88PGgJjMSICKAEogCB4Ag==
 TG5|GjAKBHRlc3QSGxICAAAYAiITCQL+PwrQD88PCc0Pzg8K0A/PDxoCYzEiAigBKIAgeAI=
-TG6|GjIKBHRlc3QSHRICAAAYAyIVCUbsPxoxEwonPAkPCTEeEhQUCh0PGgJjMSICKAEogCB4Ag==
-TG7|Gj0KBHRlc3QSKBICAAAYAyIgCVCwPxIKFDEdDwkAFCIyHh0eJwkAJw8JKBQSEwkAFA8aAmMxIgIo
+TG6|GjIKBHRlc3QSHRICAAAYAyIVCVqmPxoTRjETCicPCSgKEh0KFBQPGgJjMSICKAEogCB4Ag==
+TG7|Gj0KBHRlc3QSKBICAAAYAyIgCSi6PyIyHh0eJwkAJw8JFAoSABQUCQ8JEzESKAoKFA8aAmMxIgIo
 ASiAIHgC
 TG8|GiEKBHRlc3QSDBICAAAYASIECTLePxoCYzEiAigBKIAgeAI=
 TG9|GiMKBHRlc3QSDhICAAAYASIGETLeP2VGGgJjMSICKAEogCB4Ag==
@@ -98,4 +117,4 @@
 TU2
 ERROR:  pgis_asmvt_transfn: parameter row cannot be other than a rowtype
 TU3|
-#3922|POLYGON((2613 3664,2615 3662,2616 3662,2617 3665,2615 3665,2615 3664,2613 3664))
+#3922|6.5



More information about the postgis-tickets mailing list