[postgis-tickets] r17587 - Add ST_TileEnvelope utility function
Paul Ramsey
pramsey at cleverelephant.ca
Wed Jul 10 01:44:52 PDT 2019
Author: pramsey
Date: 2019-07-10 13:44:52 -0700 (Wed, 10 Jul 2019)
New Revision: 17587
Modified:
trunk/NEWS
trunk/doc/reference_constructor.xml
trunk/doc/reference_output.xml
trunk/postgis/lwgeom_functions_basic.c
trunk/postgis/postgis.sql.in
trunk/regress/core/regress.sql
trunk/regress/core/regress_expected
Log:
Add ST_TileEnvelope utility function
Closes #4452
Modified: trunk/NEWS
===================================================================
--- trunk/NEWS 2019-07-09 15:43:19 UTC (rev 17586)
+++ trunk/NEWS 2019-07-10 20:44:52 UTC (rev 17587)
@@ -9,6 +9,7 @@
- #4445, Fix a bug in geometry_le (Raúl Marín)
- #4451, Fix the calculation of gserialized_max_header_size (Raúl Marín)
- #4450, Speed up ST_GeometryType (Raúl Marín)
+ - #4452, Add ST_TileEnvelope() (Paul Ramsey)
PostGIS 3.0.0alpha3
Modified: trunk/doc/reference_constructor.xml
===================================================================
--- trunk/doc/reference_constructor.xml 2019-07-09 15:43:19 UTC (rev 17586)
+++ trunk/doc/reference_constructor.xml 2019-07-10 20:44:52 UTC (rev 17587)
@@ -216,7 +216,7 @@
</refsection>
<refsection>
<title>See Also</title>
- <para><xref linkend="ST_MakePoint" />, <xref linkend="ST_MakeLine" />, <xref linkend="ST_MakePolygon" /></para>
+ <para><xref linkend="ST_MakePoint" />, <xref linkend="ST_MakeLine" />, <xref linkend="ST_MakePolygon" />, <xref linkend="ST_TileEnvelope" /></para>
</refsection>
</refentry>
@@ -756,4 +756,47 @@
</refsection>
</refentry>
+
+ <refentry id="ST_TileEnvelope">
+ <refnamediv>
+ <refname>ST_TileEnvelope</refname>
+ <refpurpose>Creates a rectangular Polygon in <ulink url="https://en.wikipedia.org/wiki/Web_Mercator_projection">Web Mercator</ulink> (SRID:3857) using the <ulink url="https://en.wikipedia.org/wiki/Tiled_web_map">XYZ tile system</ulink>.</refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv>
+ <funcsynopsis>
+ <funcprototype>
+ <funcdef>geometry <function>ST_TileEnvelope</function></funcdef>
+ <paramdef><type>integer</type> <parameter>tileZoom</parameter></paramdef>
+ <paramdef><type>integer</type> <parameter>tileX</parameter></paramdef>
+ <paramdef><type>integer</type> <parameter>tileY</parameter></paramdef>
+ <paramdef choice="opt"><type>geometry</type> <parameter>bounds=SRID=3857;LINESTRING(-20037508.342789 -20037508.342789,20037508.342789 20037508.342789)</parameter></paramdef>
+ </funcprototype>
+ </funcsynopsis>
+ </refsynopsisdiv>
+
+ <refsection>
+ <title>Description</title>
+
+ <para>Creates a rectangular Polygon in <ulink url="https://en.wikipedia.org/wiki/Web_Mercator_projection">Web Mercator</ulink> (SRID:3857) using the <ulink url="https://en.wikipedia.org/wiki/Tiled_web_map">XYZ tile system</ulink>. By default, the bounds are the in EPSG:3857 using the standard range of the Web Mercator system (-20037508.342789, 20037508.342789). The optional bounds parameter can be used to generate envelopes for any tiling scheme: provide a geometry that has the SRID and extent of the initial "zoom level zero" square within which the tile system is to be inscribed.</para>
+
+ <para>Availability: 3.0</para>
+
+ </refsection>
+
+ <refsection>
+ <title>Example: Building a tile envelope</title>
+ <programlisting>SELECT ST_AsText( ST_TileEnvelope(2, 1, 1) );
+
+st_astext
+------------------------------
+POLYGON((-10018754.1713945 0,-10018754.1713945 10018754.1713945,0 10018754.1713945,0 0,-10018754.1713945 0))
+</programlisting>
+ </refsection>
+ <refsection>
+ <title>See Also</title>
+ <para><xref linkend="ST_MakeEnvelope" /></para>
+ </refsection>
+ </refentry>
+
</sect1>
Modified: trunk/doc/reference_output.xml
===================================================================
--- trunk/doc/reference_output.xml 2019-07-09 15:43:19 UTC (rev 17586)
+++ trunk/doc/reference_output.xml 2019-07-10 20:44:52 UTC (rev 17587)
@@ -1093,6 +1093,7 @@
<title>See Also</title>
<para>
<xref linkend="ST_AsMVT" />,
+ <xref linkend="ST_TileEnvelope" />,
<xref linkend="PostGIS_Wagyu_Version" />
</para>
</refsection>
@@ -1181,24 +1182,22 @@
<refsection>
<title>Examples</title>
- <programlisting><![CDATA[SELECT ST_AsMVT(q, 'test', 4096, 'geom')
- 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_MakeBox2D(ST_Point(0, 0), ST_Point(4096, 4096)),
- 4096, 0, false) AS geom) AS q;
+ <programlisting><![CDATA[WITH mvtgeom AS
+(
+ SELECT ST_AsMVTGeom(geom, ST_TileEnvelope(12,513,412)) AS geom, name, description
+ FROM points_of_interest
+ WHERE ST_Intersects(geom, ST_TileEnvelope(12,513,412)
+)
+SELECT ST_AsMVT(mvtgeom.*)
+FROM mvtgeom;
+]]></programlisting>
- st_asmvt
---------------------------------------------------------------------
- \x1a320a0474657374121d1202000018032215095aa63f1a134631130a270f09280a121d0a14140f1a026331220228012880207802
-]]>
- </programlisting>
</refsection>
<refsection>
<title>See Also</title>
<para>
- <xref linkend="ST_AsMVTGeom" />
+ <xref linkend="ST_AsMVTGeom" />, <xref linkend="ST_TileEnvelope" />
</para>
</refsection>
</refentry>
Modified: trunk/postgis/lwgeom_functions_basic.c
===================================================================
--- trunk/postgis/lwgeom_functions_basic.c 2019-07-09 15:43:19 UTC (rev 17586)
+++ trunk/postgis/lwgeom_functions_basic.c 2019-07-10 20:44:52 UTC (rev 17587)
@@ -106,6 +106,7 @@
Datum optimistic_overlap(PG_FUNCTION_ARGS);
Datum ST_GeoHash(PG_FUNCTION_ARGS);
Datum ST_MakeEnvelope(PG_FUNCTION_ARGS);
+Datum ST_TileEnvelope(PG_FUNCTION_ARGS);
Datum ST_CollectionExtract(PG_FUNCTION_ARGS);
Datum ST_CollectionHomogenize(PG_FUNCTION_ARGS);
Datum ST_IsCollection(PG_FUNCTION_ARGS);
@@ -2064,6 +2065,67 @@
PG_RETURN_POINTER(result);
}
+
+PG_FUNCTION_INFO_V1(ST_TileEnvelope);
+Datum ST_TileEnvelope(PG_FUNCTION_ARGS)
+{
+ GSERIALIZED *bounds;
+ uint32_t zoomu;
+ int32_t x, y, zoom;
+ uint32_t worldTileSize;
+ double tileGeoSizeX, tileGeoSizeY;
+ double boundsWidth, boundsHeight;
+ double x1, y1, x2, y2;
+ /* This is broken, since 3857 doesn't mean "web mercator", it means
+ the contents of the row in spatial_ref_sys with srid = 3857.
+ For practical purposes this will work, but in good implementation
+ we should de-reference in spatial ref sys to confirm that the
+ srid of the object is EPSG:3857. */
+ int32_t srid;
+ GBOX bbox;
+
+ POSTGIS_DEBUG(2, "ST_TileEnvelope called");
+
+ zoom = PG_GETARG_INT32(0);
+ x = PG_GETARG_INT32(1);
+ y = PG_GETARG_INT32(2);
+
+ bounds = PG_GETARG_GSERIALIZED_P(3);
+ if(gserialized_get_gbox_p(bounds, &bbox) != LW_SUCCESS)
+ elog(ERROR, "%s: Empty bounds", __func__);
+ srid = gserialized_get_srid(bounds);
+
+ boundsWidth = bbox.xmax - bbox.xmin;
+ boundsHeight = bbox.ymax - bbox.ymin;
+ if (boundsWidth <= 0 || boundsHeight <= 0)
+ elog(ERROR, "%s: Geometric bounds are too small", __func__);
+
+ if (zoom < 0 || zoom >= 32)
+ elog(ERROR, "%s: Invalid tile zoom value, %d", __func__, zoom);
+
+ zoomu = (uint32_t)zoom;
+ worldTileSize = 0x01u << (zoomu > 31 ? 31 : zoomu);
+
+ if (x < 0 || (uint32_t)x >= worldTileSize)
+ elog(ERROR, "%s: Invalid tile x value, %d", __func__, x);
+ if (y < 0 || (uint32_t)y >= worldTileSize)
+ elog(ERROR, "%s: Invalid tile y value, %d", __func__, y);
+
+ tileGeoSizeX = boundsWidth / worldTileSize;
+ tileGeoSizeY = boundsHeight / worldTileSize;
+ x1 = bbox.xmin + tileGeoSizeX * (x);
+ x2 = bbox.xmin + tileGeoSizeX * (x+1);
+ y1 = bbox.ymax - tileGeoSizeY * (y+1);
+ y2 = bbox.ymax - tileGeoSizeY * (y);
+
+ PG_RETURN_POINTER(
+ geometry_serialize(
+ lwpoly_as_lwgeom(
+ lwpoly_construct_envelope(
+ srid, x1, y1, x2, y2))));
+}
+
+
PG_FUNCTION_INFO_V1(ST_IsCollection);
Datum ST_IsCollection(PG_FUNCTION_ARGS)
{
Modified: trunk/postgis/postgis.sql.in
===================================================================
--- trunk/postgis/postgis.sql.in 2019-07-09 15:43:19 UTC (rev 17586)
+++ trunk/postgis/postgis.sql.in 2019-07-10 20:44:52 UTC (rev 17587)
@@ -1679,6 +1679,13 @@
LANGUAGE 'c' IMMUTABLE STRICT _PARALLEL
_COST_LOW;
+-- Availability: 3.0.0
+CREATE OR REPLACE FUNCTION ST_TileEnvelope(zoom integer, x integer, y integer, bounds geometry DEFAULT 'SRID=3857;LINESTRING(-20037508.342789 -20037508.342789, 20037508.342789 20037508.342789)'::geometry)
+ RETURNS geometry
+ AS 'MODULE_PATHNAME', 'ST_TileEnvelope'
+ LANGUAGE 'c' IMMUTABLE STRICT _PARALLEL
+ _COST_LOW;
+
-- Availability: 1.2.2
CREATE OR REPLACE FUNCTION ST_MakePolygon(geometry, geometry[])
RETURNS geometry
Modified: trunk/regress/core/regress.sql
===================================================================
--- trunk/regress/core/regress.sql 2019-07-09 15:43:19 UTC (rev 17586)
+++ trunk/regress/core/regress.sql 2019-07-10 20:44:52 UTC (rev 17587)
@@ -264,6 +264,18 @@
select '225', ST_Expand('BOX(-2 3, -1 6'::BOX2D, 4, 2);
select '226', ST_SRID(ST_Expand('SRID=4326;POINT (0 0)'::geometry, 1))=4326;
+-- ST_TileEnvelope()
+select '227', ST_AsEWKT(ST_TileEnvelope(-1, 0, 0));
+select '228', ST_AsEWKT(ST_TileEnvelope(0, 0, 1));
+select '229', ST_AsEWKT(ST_TileEnvelope(0, 0, 0));
+select '230', ST_AsEWKT(ST_TileEnvelope(4, 8, 8));
+select '231', ST_AsEWKT(ST_TileEnvelope(4, 15, 15));
+select '232', ST_AsEWKT(ST_TileEnvelope(4, 8, 8, ST_MakeEnvelope(-100, -100, 100, 100, 0)));
+select '233', ST_AsEWKT(ST_TileEnvelope(4, 15, 15, ST_MakeEnvelope(-100, -100, 100, 100, 0)));
+select '234', ST_AsEWKT(ST_TileEnvelope(4, 0, 0, ST_MakeEnvelope(-100, -100, 100, 100, 0)));
+select '235', ST_AsEWKT(ST_TileEnvelope(4, 8, 8, ST_MakeEnvelope(-200, -100, 200, 100, 0)));
+
+
-- Drop test table
DROP table test;
Modified: trunk/regress/core/regress_expected
===================================================================
--- trunk/regress/core/regress_expected 2019-07-09 15:43:19 UTC (rev 17586)
+++ trunk/regress/core/regress_expected 2019-07-10 20:44:52 UTC (rev 17587)
@@ -194,3 +194,12 @@
224|
225|BOX(-6 1,3 8)
226|t
+ERROR: ST_TileEnvelope: Invalid tile zoom value, -1
+ERROR: ST_TileEnvelope: Invalid tile y value, 1
+229|SRID=3857;POLYGON((-20037510 -20037510,-20037510 20037510,20037510 20037510,20037510 -20037510,-20037510 -20037510))
+230|SRID=3857;POLYGON((0 -2504688.75,0 0,2504688.75 0,2504688.75 -2504688.75,0 -2504688.75))
+231|SRID=3857;POLYGON((17532821.25 -20037510,17532821.25 -17532821.25,20037510 -17532821.25,20037510 -20037510,17532821.25 -20037510))
+232|POLYGON((0 -12.5,0 0,12.5 0,12.5 -12.5,0 -12.5))
+233|POLYGON((87.5 -100,87.5 -87.5,100 -87.5,100 -100,87.5 -100))
+234|POLYGON((-100 87.5,-100 100,-87.5 100,-87.5 87.5,-100 87.5))
+235|POLYGON((0 -12.5,0 0,25 0,25 -12.5,0 -12.5))
More information about the postgis-tickets
mailing list