From ac1b184fd1bc316f11b1a9f4312f9b6420fe04ad Mon Sep 17 00:00:00 2001 From: David Bitner Date: Wed, 29 Jun 2022 13:59:11 -0500 Subject: [PATCH] create magic naming to use simplified geom columns at different zoom levels --- tests/fixtures/landsat_wrs.sql | 5 ++++ timvt/dbmodel.py | 42 ++++++++++++++++++++++++++++------ timvt/layer.py | 17 +++++++------- 3 files changed, 49 insertions(+), 15 deletions(-) diff --git a/tests/fixtures/landsat_wrs.sql b/tests/fixtures/landsat_wrs.sql index 1a169b1..5e29475 100644 --- a/tests/fixtures/landsat_wrs.sql +++ b/tests/fixtures/landsat_wrs.sql @@ -16278,4 +16278,9 @@ INSERT INTO "public"."landsat_wrs" ("geom" , "id", "pr", "path", "row") VALUES ( INSERT INTO "public"."landsat_wrs" ("geom" , "id", "pr", "path", "row") VALUES ('0103000020E61000000100000017000000BC6F22318D605DC07C80DDAB547654C0F3D24D6210C45DC0286E204C957B54C0DDC88F035F0C5FC0B829A06DE98C54C0753D48E2C7315FC09F9D98E9E28E54C07BC08D5495B85FC0E454EE61009654C08A409C71D1C95FC09A4A0243E99654C0A69BC420B0DA5FC07958A835CD9754C0DF57961D7CDB5FC089CB9FC25A9754C0C9507DEADE3760C04E44E76E2C4454C0759DCE6E644560C0DFCF7431003554C014AE47E17A4860C0A8C64B37893154C054A8C4253C4160C0E4780CE0C93054C07217A5C72EFE5FC0E4031608F72954C0A0F1BB981CD35FC02C930A48BE2754C056DF13453C645EC042BE21B4D11454C05839B4C876565EC0CE1951DA1B1454C099EA298D36DA5DC03A92CB7F483F54C0F2D24D6210C45DC0705649C1FA4654C01D218633B4B25DC0EDB03A02034D54C0EDF8A16AD3415DC089250CFE3B7454C0713D0AD7A3405DC0226C787AA57454C075FFF55672505DC04126530F7B7554C0BC6F22318D605DC07C80DDAB547654C0', '28887', '223120', 223, 120); INSERT INTO "public"."landsat_wrs" ("geom" , "id", "pr", "path", "row") VALUES ('0103000020E6100000010000001B0000003FECA459962360C091C367A6834854C07BC08D5495B85FC0E454EE61009654C039B4C876BEB75FC0A60A4625759654C08A409C71D1C95FC09A4A0243E99654C0DF57961D7CDB5FC089CB9FC25A9754C052862FCA8F6D60C0F9B7F717C59D54C06E59EA5E023A61C0F9E8B00308A854C0D0A6DBDF544361C02A3A92CB7FA854C0713D0AD7A34C61C0DB8AFD65F7A854C0C595512BC74C61C02A3A92CB7FA854C053C32F1BED5461C008C74015EA8C54C0EE844B079E6061C0BDABF7DE556554C039B4C876BE6B61C0E4839ECDAA3F54C0A52A38320A6461C03A92CB7F483F54C0836FBD8474D360C09DF1269F133854C0B509E6153FC360C0BD060CCD443754C0BC6DA0345BA660C0E753CB2AD43554C0CCC21662BE9560C0DFCF7431003554C0B52E9B5A8B7A60C0A6684F22A53354C022B07268916D60C021E5CE8EFF3254C051ECE0780F5A60C08722FBA4063254C054A8C4253C4160C0E4780CE0C93054C0F6285C8FC23960C023DBF97E6A3054C086F2449CC73460C0E753CB2AD43554C0D07A9F4F582A60C01AEFDE732B4154C07FBFE1C2632460C0D9ED7566A44754C03FECA459962360C091C367A6834854C0', '28888', '223121', 223, 121); INSERT INTO "public"."landsat_wrs" ("geom" , "id", "pr", "path", "row") VALUES ('0103000020E610000001000000150000008741C1DF3E4261C09F9D98E9E28E54C06E59EA5E023A61C0F9E8B00308A854C060E5D022DB3961C02A3A92CB7FA854C0D0A6DBDF544361C02A3A92CB7FA854C0C595512BC74C61C02A3A92CB7FA854C0957652EC65A562C02A3A92CB7FA854C0D1156A63D8AE62C02A3A92CB7FA854C03108AC1C5AB862C02A3A92CB7FA854C032725EC032B862C07C3160A107A854C00AACBB5FF6AF62C09F9D98E9E28E54C05953467C77A162C0AC4E55D9A16254C0D9CEF753E39562C03A92CB7F483F54C0ECC2440D2B8E62C03A92CB7F483F54C0397EE4AF361562C03A92CB7F483F54C09C822CB52D0462C03A92CB7F483F54C0F66A508A07EE61C03A92CB7F483F54C08744D20F02DD61C03A92CB7F483F54C0A52A38320A6461C03A92CB7F483F54C0B81E85EB515C61C03A92CB7F483F54C0C9487904BE5061C05F101912A16254C08741C1DF3E4261C09F9D98E9E28E54C0', '28889', '223122', 223, 122); + + +SELECT AddGeometryColumn('public','landsat_wrs','geom_z7',3857,'GEOMETRY',2); +CREATE INDEX "landsat_wrs_geom_geom_z7_idx" ON "public"."landsat_wrs" USING GIST ("geom_z7"); +UPDATE public.landsat_wrs SET geom_z7 = ST_SnapToGrid(ST_SimplifyPreserveTopology(ST_Transform(geom, 3857), 1000), 1); COMMIT; diff --git a/timvt/dbmodel.py b/timvt/dbmodel.py index 06627c6..e9154ba 100644 --- a/timvt/dbmodel.py +++ b/timvt/dbmodel.py @@ -1,5 +1,5 @@ """tifeatures.dbmodel: database events.""" - +import re from typing import Any, Dict, List, Optional from buildpg import asyncpg @@ -73,14 +73,42 @@ def datetime_column(self, dtcol: Optional[str] = None): return None - def geometry_column(self, gcol: Optional[str] = None) -> Optional[GeometryColumn]: + def geometry_column( + self, gcol: Optional[str] = None, zoom: Optional[int] = None + ) -> Optional[GeometryColumn]: """Return the name of the first geometry column.""" + base_geom_column = None if self.geometry_columns is not None and len(self.geometry_columns) > 0: - for c in self.geometry_columns: - if gcol is None or c.name == gcol: - return c - - return None + geometry_columns = self.geometry_columns + else: + return None + + for c in geometry_columns: + if gcol is None or c.name == gcol: + base_geom_column = c + if not re.search(r"(?<=_z)[0-9]+$", c.name): + break + + # If zoom is set check check pregenerated simplified geometries with magic _z notation + zcol = base_geom_column + if zoom and base_geom_column: + maxz = None + + for c in geometry_columns: + if c.name != base_geom_column.name and c.name.startswith( + base_geom_column.name + ): + m = re.search(r"(?<=_z)[0-9]+$", c.name) + if m: + z = int(m.group(0)) + if z == zoom: + return c + if z < zoom and (maxz is None or maxz > z): + maxz = z + zcol = c + return zcol + else: + return base_geom_column @property def id_column_info(self) -> Column: # type: ignore diff --git a/timvt/layer.py b/timvt/layer.py index c1739a5..d3b5fe3 100644 --- a/timvt/layer.py +++ b/timvt/layer.py @@ -127,7 +127,8 @@ async def get_tile( ) geom = kwargs.get("geom", None) - geometry_column = self.geometry_column(geom) + geometry_column = self.geometry_column(geom, tile.z) + print("geometry_column set to", geometry_column) if not geometry_column: raise InvalidGeometryColumnName(f"Invalid Geometry Column: {geom}.") @@ -160,15 +161,15 @@ async def get_tile( coalesce(:tms_srid, 0) ), :seg_size - ) AS geom + ) AS btgeom ), bounds_geomcrs AS ( SELECT CASE WHEN coalesce(:tms_srid, 0) != 0 THEN - ST_Transform(bounds_tmscrs.geom, :geometry_srid) + ST_Transform(bounds_tmscrs.btgeom, :geometry_srid) ELSE - ST_Transform(bounds_tmscrs.geom, :tms_proj, :geometry_srid) - END as geom + ST_Transform(bounds_tmscrs.btgeom, :tms_proj, :geometry_srid) + END as bggeom FROM bounds_tmscrs ), mvtgeom AS ( @@ -178,7 +179,7 @@ async def get_tile( ELSE ST_Transform(t.:geometry_column, :tms_proj) END, - bounds_tmscrs.geom, + bounds_tmscrs.btgeom, :tile_resolution, :tile_buffer ) AS geom, :fields @@ -186,7 +187,7 @@ async def get_tile( -- Find where geometries intersect with input Tile -- Intersects test is made in table geometry's CRS (e.g WGS84) WHERE ST_Intersects( - t.:geometry_column, bounds_geomcrs.geom + t.:geometry_column, bounds_geomcrs.bggeom ) LIMIT :limit ) SELECT ST_AsMVT(mvtgeom.*) FROM mvtgeom @@ -209,7 +210,7 @@ async def get_tile( tile_buffer=int(buffer), limit=limit, ) - + print(q, p) return await conn.fetchval(q, *p)