Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Artifact ID: | fc842978ba0d7b9506859f68d4e4e2db8628dc3a |
---|---|
Page Name: | About ST_Subdivide() |
Date: | 2019-02-15 19:44:20 |
Original User: | sandro |
Parent: | d7e14cd8a2a43e43aa2da8bc53be3464964753f7 (diff) |
Next | 22f4f550841c61347fc9eddb86d9cdbc1fe4201c |
Content
About ST_Subdivide()Since version 5.0.0 SpatiaLite supports ST_Subdivide(), an advanced SQL function already available on PostGIS.The implementation is strictly similar in both Spatial DBMSes because on PostgIS the function is built on the top of the internal lwgeom library, and on SpatiaLite is built on the top of librttopo that simply is a more universal porting of lwgeom outside PostGIS. A short rationale: processing huge geometries having an impressive number of Vertices (many thousands or even more) is an intrinsically slow process. Subdividing them into many smaller parts (still preserving full topological consistency) usually helps to restore a satisfying processing speed. This is exactly the intended scope of ST_Subdivide():
Basic ExamplesThe following examples are based on the am_reg_multipart Shapefile freely available for download from here (search for Ambiti Amministrativi - Administrative Boundaries).This one supports a very accurate and precise map representation, and the main exterior ring has more than 100,000+ Vertices. It's a very good example of a Geometry so huge to make extremely slow computing any Spatial operator (as e.g. ST_Intersects, ST_Touches, ST_Covers and so on).
However, a big caveat should be always considered about the multi-part collections returned by ST_Subdivide(). At least in the case of MultiPolygons any collection returned by ST_Subdivide() is inherently invalid, as the following SQL query demonstrates: SELECT ST_IsValid(ST_Subdivide(geometry)) FROM tuscany; --------- 0It's not at all difficult undestanding why this happens. Accordingly to standard OGC/SFS rules two single-part Polygons belonging to the same MultiPolygon are alwayes forbidden to reciprocally touch. More precisely: they can only touch on specific point(s), but they can never share a common boundary.
Advanced ExamplesNow we'll go to explore the real effectiveness of ST_Subdivide() in one of the most common Spatial Problems: identifying all intersections between a dataset of the POINT type and a huge Polygon/Multipolygon.During this second test we'll use the following datasets:
A first naive attempSELECT Count(*) FROM civici AS c LEFT JOIN tuscany AS t ON (ST_Intersects(c.geometry, t.geometry) = 1); SELECT Count(*) FROM civici AS c LEFT JOIN tuscany AS t ON (ST_Intersects(c.geometry, t.geometry) = 1 AND c.rowid IN ( SELECT rowid FROM SpatialIndex WHERE f_table_name = 'civici' AND search_frame = t.geometry));The only difference between the above two SQL queries is in that the second one explicitly calls the Spatial Index. Actual findings:
A second attemp based on ST_Subdivide() and VirtualElementaryCREATE TABLE xx (id INTEGER PRIMARY KEY); SELECT AddGeometryColumn('xx', 'geom', 3003, 'MULTIPOLYGON', 'XY'); INSERT INTO xx VALUES (1, NULL);We'll start first by creating a convenience Table intended to temporarily store the result of ST_Subdivide(). This Table is very simple:
UPDATE xx SET geom = (SELECT ST_Subdivide(geometry, 2048) FROM tuscany) WHERE id = 1; SELECT Count(*) FROM ElementaryGeometries AS t JOIN civici AS c ON (ST_Intersects(c.geometry, t.geometry) = 1 AND c.rowid IN ( SELECT rowid FROM SpatialIndex WHERE f_table_name = 'civici' AND search_frame = t.geometry)) WHERE f_table_name = 'xx' AND origin_rowid = 1; ---------------- 1480991 (in 38.094 seconds) UPDATE xx SET geom = (SELECT ST_Subdivide(geometry, 512) FROM tuscany) WHERE id = 1; SELECT Count(*) FROM ElementaryGeometries AS t JOIN civici AS c ON (ST_Intersects(c.geometry, t.geometry) = 1 AND c.rowid IN ( SELECT rowid FROM SpatialIndex WHERE f_table_name = 'civici' AND search_frame = t.geometry)) WHERE f_table_name = 'xx' AND origin_rowid = 1; ---------------- 1480991 (in 12.617 seconds) UPDATE xx SET geom = (SELECT ST_Subdivide(geometry) FROM tuscany) WHERE id = 1; SELECT Count(*) FROM ElementaryGeometries AS t JOIN civici AS c ON (ST_Intersects(c.geometry, t.geometry) = 1 AND c.rowid IN ( SELECT rowid FROM SpatialIndex WHERE f_table_name = 'civici' AND search_frame = t.geometry)) WHERE f_table_name = 'xx' AND origin_rowid = 1; ---------------- 1480991 (in 9.534 seconds)Quick evalutation:
|