def layer_srs(self, layer): """ Return a list tuples with title and name of all SRS for the layer. The title of SRS that are native to the layer are suffixed with a '*'. """ cached_srs = [] for map_layer in layer.map_layers: # TODO unify map_layers interface if isinstance(map_layer, SRSConditional): for srs_key in map_layer.srs_map.keys(): cached_srs.append(srs_key.srs_code) elif isinstance(map_layer, CacheMapLayer): cached_srs.append(map_layer.grid.srs.srs_code) elif isinstance(map_layer, ResolutionConditional): cached_srs.append(map_layer.srs.srs_code) elif isinstance(map_layer, WMSSource): if map_layer.supported_srs: for supported_srs in map_layer.supported_srs: cached_srs.append(supported_srs.srs_code) uncached_srs = [] for srs_code in self.srs: if srs_code not in cached_srs: uncached_srs.append(srs_code) sorted_cached_srs = sorted(cached_srs, key=lambda srs: get_epsg_num(srs)) sorted_uncached_srs = sorted(uncached_srs, key=lambda srs: get_epsg_num(srs)) sorted_cached_srs = [(s + '*', s) for s in sorted_cached_srs] sorted_uncached_srs = [(s, s) for s in sorted_uncached_srs] return sorted_cached_srs + sorted_uncached_srs
def _verify_gpkg_contents(self): with sqlite3.connect(self.geopackage_file) as db: cur = db.execute("""SELECT * FROM gpkg_contents WHERE table_name = ?""" , (self.table_name,)) results = cur.fetchone() if not results: # Table doesn't exist in gpkg_contents _initialize_gpkg will add it. return False gpkg_data_type = results[1] gpkg_srs_id = results[9] cur = db.execute("""SELECT * FROM gpkg_spatial_ref_sys WHERE srs_id = ?""" , (gpkg_srs_id,)) gpkg_coordsys_id = cur.fetchone()[3] if gpkg_data_type.lower() != "tiles": log.info("The geopackage table name already exists for a data type other than tiles.") raise ValueError("table_name is improperly configured.") if gpkg_coordsys_id != get_epsg_num(self.tile_grid.srs.srs_code): log.info( "The geopackage {0} table name {1} already exists and has an SRS of {2}, which does not match the configured" \ " Mapproxy SRS of {3}.".format(self.geopackage_file, self.table_name, gpkg_coordsys_id, get_epsg_num(self.tile_grid.srs.srs_code))) raise ValueError("srs is improperly configured.") return True
def tile_grid_for_epsg(epsg, bbox=None, tile_size=(256, 256), res=None): """ Create a tile grid that matches the given epsg code: :param epsg: the epsg code :type epsg: 'EPSG:0000', '0000' or 0000 :param bbox: the bbox of the grid :param tile_size: the size of each tile :param res: a list with all resolutions """ epsg = get_epsg_num(epsg) if epsg in geodetic_epsg_codes: return TileGrid(epsg, is_geodetic=True, bbox=bbox, tile_size=tile_size, res=res) return TileGrid(epsg, bbox=bbox, tile_size=tile_size, res=res)
def _initialize_gpkg(self): log.info('initializing Geopackage file %s', self.geopackage_file) db = sqlite3.connect(self.geopackage_file) if self.wal: db.execute('PRAGMA journal_mode=wal') proj = get_epsg_num(self.tile_grid.srs.srs_code) stmts = [ """ CREATE TABLE IF NOT EXISTS gpkg_contents (table_name TEXT NOT NULL PRIMARY KEY, -- The name of the tiles, or feature table data_type TEXT NOT NULL, -- Type of data stored in the table: "features" per clause Features (http://www.geopackage.org/spec/#features), "tiles" per clause Tiles (http://www.geopackage.org/spec/#tiles), or an implementer-defined value for other data tables per clause in an Extended GeoPackage identifier TEXT UNIQUE, -- A human-readable identifier (e.g. short name) for the table_name content description TEXT DEFAULT '', -- A human-readable description for the table_name content last_change DATETIME NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ','now')), -- Timestamp value in ISO 8601 format as defined by the strftime function %Y-%m-%dT%H:%M:%fZ format string applied to the current time min_x DOUBLE, -- Bounding box minimum easting or longitude for all content in table_name min_y DOUBLE, -- Bounding box minimum northing or latitude for all content in table_name max_x DOUBLE, -- Bounding box maximum easting or longitude for all content in table_name max_y DOUBLE, -- Bounding box maximum northing or latitude for all content in table_name srs_id INTEGER, -- Spatial Reference System ID: gpkg_spatial_ref_sys.srs_id; when data_type is features, SHALL also match gpkg_geometry_columns.srs_id; When data_type is tiles, SHALL also match gpkg_tile_matrix_set.srs.id CONSTRAINT fk_gc_r_srs_id FOREIGN KEY (srs_id) REFERENCES gpkg_spatial_ref_sys(srs_id)) """, """ CREATE TABLE IF NOT EXISTS gpkg_spatial_ref_sys (srs_name TEXT NOT NULL, -- Human readable name of this SRS (Spatial Reference System) srs_id INTEGER NOT NULL PRIMARY KEY, -- Unique identifier for each Spatial Reference System within a GeoPackage organization TEXT NOT NULL, -- Case-insensitive name of the defining organization e.g. EPSG or epsg organization_coordsys_id INTEGER NOT NULL, -- Numeric ID of the Spatial Reference System assigned by the organization definition TEXT NOT NULL, -- Well-known Text representation of the Spatial Reference System description TEXT) """, """ CREATE TABLE IF NOT EXISTS gpkg_tile_matrix (table_name TEXT NOT NULL, -- Tile Pyramid User Data Table Name zoom_level INTEGER NOT NULL, -- 0 <= zoom_level <= max_level for table_name matrix_width INTEGER NOT NULL, -- Number of columns (>= 1) in tile matrix at this zoom level matrix_height INTEGER NOT NULL, -- Number of rows (>= 1) in tile matrix at this zoom level tile_width INTEGER NOT NULL, -- Tile width in pixels (>= 1) for this zoom level tile_height INTEGER NOT NULL, -- Tile height in pixels (>= 1) for this zoom level pixel_x_size DOUBLE NOT NULL, -- In t_table_name srid units or default meters for srid 0 (>0) pixel_y_size DOUBLE NOT NULL, -- In t_table_name srid units or default meters for srid 0 (>0) CONSTRAINT pk_ttm PRIMARY KEY (table_name, zoom_level), CONSTRAINT fk_tmm_table_name FOREIGN KEY (table_name) REFERENCES gpkg_contents(table_name)) """, """ CREATE TABLE IF NOT EXISTS gpkg_tile_matrix_set (table_name TEXT NOT NULL PRIMARY KEY, -- Tile Pyramid User Data Table Name srs_id INTEGER NOT NULL, -- Spatial Reference System ID: gpkg_spatial_ref_sys.srs_id min_x DOUBLE NOT NULL, -- Bounding box minimum easting or longitude for all content in table_name min_y DOUBLE NOT NULL, -- Bounding box minimum northing or latitude for all content in table_name max_x DOUBLE NOT NULL, -- Bounding box maximum easting or longitude for all content in table_name max_y DOUBLE NOT NULL, -- Bounding box maximum northing or latitude for all content in table_name CONSTRAINT fk_gtms_table_name FOREIGN KEY (table_name) REFERENCES gpkg_contents(table_name), CONSTRAINT fk_gtms_srs FOREIGN KEY (srs_id) REFERENCES gpkg_spatial_ref_sys (srs_id)) """, """ CREATE TABLE IF NOT EXISTS [{0}] (id INTEGER PRIMARY KEY AUTOINCREMENT, -- Autoincrement primary key zoom_level INTEGER NOT NULL, -- min(zoom_level) <= zoom_level <= max(zoom_level) for t_table_name tile_column INTEGER NOT NULL, -- 0 to tile_matrix matrix_width - 1 tile_row INTEGER NOT NULL, -- 0 to tile_matrix matrix_height - 1 tile_data BLOB NOT NULL, -- Of an image MIME type specified in clauses Tile Encoding PNG, Tile Encoding JPEG, Tile Encoding WEBP UNIQUE (zoom_level, tile_column, tile_row)) """.format(self.table_name) ] for stmt in stmts: db.execute(stmt) db.execute("PRAGMA foreign_keys = 1;") # List of WKT execute statements and data.(""" wkt_statement = """ INSERT OR REPLACE INTO gpkg_spatial_ref_sys ( srs_id, organization, organization_coordsys_id, srs_name, definition) VALUES (?, ?, ?, ?, ?) """ wkt_entries = [(3857, 'epsg', 3857, 'WGS 84 / Pseudo-Mercator', """ PROJCS["WGS 84 / Pseudo-Mercator",GEOGCS["WGS 84",DATUM["WGS_1984",SPHEROID["WGS 84",6378137,298.257223563,\ AUTHORITY["EPSG","7030"]],AUTHORITY["EPSG","6326"]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],\ UNIT["degree",0.0174532925199433,AUTHORITY["EPSG","9122"]],AUTHORITY["EPSG","4326"]],\ PROJECTION["Mercator_1SP"],PARAMETER["central_meridian",0],PARAMETER["scale_factor",1],PARAMETER["false_easting",0],\ PARAMETER["false_northing",0],UNIT["metre",1,AUTHORITY["EPSG","9001"]],AXIS["X",EAST],AXIS["Y",NORTH],\ AUTHORITY["EPSG","3857"]]\ """), (4326, 'epsg', 4326, 'WGS 84', """ GEOGCS["WGS 84",DATUM["WGS_1984",SPHEROID["WGS 84",6378137,298.257223563,AUTHORITY["EPSG","7030"]],\ AUTHORITY["EPSG","6326"]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],UNIT["degree",0.0174532925199433,\ AUTHORITY["EPSG","9122"]],AUTHORITY["EPSG","4326"]]\ """), (-1, 'NONE', -1, ' ', 'undefined'), (0, 'NONE', 0, ' ', 'undefined')] if get_epsg_num(self.tile_grid.srs.srs_code) not in [4326, 3857]: wkt_entries.append( (proj, 'epsg', proj, 'Not provided', "Added via Mapproxy.")) db.commit() # Add geopackage version to the header (1.0) db.execute("PRAGMA application_id = 1196437808;") db.commit() for wkt_entry in wkt_entries: try: db.execute(wkt_statement, (wkt_entry[0], wkt_entry[1], wkt_entry[2], wkt_entry[3], wkt_entry[4])) except sqlite3.IntegrityError: log.info("srs_id already exists.".format(wkt_entry[0])) db.commit() # Ensure that tile table exists here, don't overwrite a valid entry. try: db.execute( """ INSERT INTO gpkg_contents ( table_name, data_type, identifier, description, min_x, max_x, min_y, max_y, srs_id) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?); """, (self.table_name, "tiles", self.table_name, "Created with Mapproxy.", self.tile_grid.bbox[0], self.tile_grid.bbox[2], self.tile_grid.bbox[1], self.tile_grid.bbox[3], proj)) except sqlite3.IntegrityError: pass db.commit() # Ensure that tile set exists here, don't overwrite a valid entry. try: db.execute( """ INSERT INTO gpkg_tile_matrix_set (table_name, srs_id, min_x, max_x, min_y, max_y) VALUES (?, ?, ?, ?, ?, ?); """, (self.table_name, proj, self.tile_grid.bbox[0], self.tile_grid.bbox[2], self.tile_grid.bbox[1], self.tile_grid.bbox[3])) except sqlite3.IntegrityError: pass db.commit() tile_size = self.tile_grid.tile_size for grid, resolution, level in zip(self.tile_grid.grid_sizes, self.tile_grid.resolutions, range(20)): db.execute( """INSERT OR REPLACE INTO gpkg_tile_matrix (table_name, zoom_level, matrix_width, matrix_height, tile_width, tile_height, pixel_x_size, pixel_y_size) VALUES(?, ?, ?, ?, ?, ?, ?, ?) """, (self.table_name, level, grid[0], grid[1], tile_size[0], tile_size[1], resolution, resolution)) db.commit() db.close()
def _initialize_gpkg(self): log.info('initializing Geopackage file %s', self.geopackage_file) db = sqlite3.connect(self.geopackage_file) if self.wal: db.execute('PRAGMA journal_mode=wal') proj = get_epsg_num(self.tile_grid.srs.srs_code) stmts = [""" CREATE TABLE IF NOT EXISTS gpkg_contents (table_name TEXT NOT NULL PRIMARY KEY, -- The name of the tiles, or feature table data_type TEXT NOT NULL, -- Type of data stored in the table: "features" per clause Features (http://www.geopackage.org/spec/#features), "tiles" per clause Tiles (http://www.geopackage.org/spec/#tiles), or an implementer-defined value for other data tables per clause in an Extended GeoPackage identifier TEXT UNIQUE, -- A human-readable identifier (e.g. short name) for the table_name content description TEXT DEFAULT '', -- A human-readable description for the table_name content last_change DATETIME NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ','now')), -- Timestamp value in ISO 8601 format as defined by the strftime function %Y-%m-%dT%H:%M:%fZ format string applied to the current time min_x DOUBLE, -- Bounding box minimum easting or longitude for all content in table_name min_y DOUBLE, -- Bounding box minimum northing or latitude for all content in table_name max_x DOUBLE, -- Bounding box maximum easting or longitude for all content in table_name max_y DOUBLE, -- Bounding box maximum northing or latitude for all content in table_name srs_id INTEGER, -- Spatial Reference System ID: gpkg_spatial_ref_sys.srs_id; when data_type is features, SHALL also match gpkg_geometry_columns.srs_id; When data_type is tiles, SHALL also match gpkg_tile_matrix_set.srs.id CONSTRAINT fk_gc_r_srs_id FOREIGN KEY (srs_id) REFERENCES gpkg_spatial_ref_sys(srs_id)) """, """ CREATE TABLE IF NOT EXISTS gpkg_spatial_ref_sys (srs_name TEXT NOT NULL, -- Human readable name of this SRS (Spatial Reference System) srs_id INTEGER NOT NULL PRIMARY KEY, -- Unique identifier for each Spatial Reference System within a GeoPackage organization TEXT NOT NULL, -- Case-insensitive name of the defining organization e.g. EPSG or epsg organization_coordsys_id INTEGER NOT NULL, -- Numeric ID of the Spatial Reference System assigned by the organization definition TEXT NOT NULL, -- Well-known Text representation of the Spatial Reference System description TEXT) """, """ CREATE TABLE IF NOT EXISTS gpkg_tile_matrix (table_name TEXT NOT NULL, -- Tile Pyramid User Data Table Name zoom_level INTEGER NOT NULL, -- 0 <= zoom_level <= max_level for table_name matrix_width INTEGER NOT NULL, -- Number of columns (>= 1) in tile matrix at this zoom level matrix_height INTEGER NOT NULL, -- Number of rows (>= 1) in tile matrix at this zoom level tile_width INTEGER NOT NULL, -- Tile width in pixels (>= 1) for this zoom level tile_height INTEGER NOT NULL, -- Tile height in pixels (>= 1) for this zoom level pixel_x_size DOUBLE NOT NULL, -- In t_table_name srid units or default meters for srid 0 (>0) pixel_y_size DOUBLE NOT NULL, -- In t_table_name srid units or default meters for srid 0 (>0) CONSTRAINT pk_ttm PRIMARY KEY (table_name, zoom_level), CONSTRAINT fk_tmm_table_name FOREIGN KEY (table_name) REFERENCES gpkg_contents(table_name)) """, """ CREATE TABLE IF NOT EXISTS gpkg_tile_matrix_set (table_name TEXT NOT NULL PRIMARY KEY, -- Tile Pyramid User Data Table Name srs_id INTEGER NOT NULL, -- Spatial Reference System ID: gpkg_spatial_ref_sys.srs_id min_x DOUBLE NOT NULL, -- Bounding box minimum easting or longitude for all content in table_name min_y DOUBLE NOT NULL, -- Bounding box minimum northing or latitude for all content in table_name max_x DOUBLE NOT NULL, -- Bounding box maximum easting or longitude for all content in table_name max_y DOUBLE NOT NULL, -- Bounding box maximum northing or latitude for all content in table_name CONSTRAINT fk_gtms_table_name FOREIGN KEY (table_name) REFERENCES gpkg_contents(table_name), CONSTRAINT fk_gtms_srs FOREIGN KEY (srs_id) REFERENCES gpkg_spatial_ref_sys (srs_id)) """, """ CREATE TABLE IF NOT EXISTS [{0}] (id INTEGER PRIMARY KEY AUTOINCREMENT, -- Autoincrement primary key zoom_level INTEGER NOT NULL, -- min(zoom_level) <= zoom_level <= max(zoom_level) for t_table_name tile_column INTEGER NOT NULL, -- 0 to tile_matrix matrix_width - 1 tile_row INTEGER NOT NULL, -- 0 to tile_matrix matrix_height - 1 tile_data BLOB NOT NULL, -- Of an image MIME type specified in clauses Tile Encoding PNG, Tile Encoding JPEG, Tile Encoding WEBP UNIQUE (zoom_level, tile_column, tile_row)) """.format(self.table_name) ] for stmt in stmts: db.execute(stmt) db.execute("PRAGMA foreign_keys = 1;") # List of WKT execute statements and data.(""" wkt_statement = """ INSERT OR REPLACE INTO gpkg_spatial_ref_sys ( srs_id, organization, organization_coordsys_id, srs_name, definition) VALUES (?, ?, ?, ?, ?) """ wkt_entries = [(3857, 'epsg', 3857, 'WGS 84 / Pseudo-Mercator', """ PROJCS["WGS 84 / Pseudo-Mercator",GEOGCS["WGS 84",DATUM["WGS_1984",SPHEROID["WGS 84",6378137,298.257223563,\ AUTHORITY["EPSG","7030"]],AUTHORITY["EPSG","6326"]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],\ UNIT["degree",0.0174532925199433,AUTHORITY["EPSG","9122"]],AUTHORITY["EPSG","9122"]]AUTHORITY["EPSG","4326"]],\ PROJECTION["Mercator_1SP"],PARAMETER["central_meridian",0],PARAMETER["scale_factor",1],PARAMETER["false_easting",0],\ PARAMETER["false_northing",0],UNIT["metre",1,AUTHORITY["EPSG","9001"]],AXIS["X",EAST],AXIS["Y",NORTH]\ """ ), (4326, 'epsg', 4326, 'WGS 84', """ GEOGCS["WGS 84",DATUM["WGS_1984",SPHEROID["WGS 84",6378137,298.257223563,AUTHORITY["EPSG","7030"]],\ AUTHORITY["EPSG","6326"]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],UNIT["degree",0.0174532925199433,\ AUTHORITY["EPSG","9122"]],AUTHORITY["EPSG","4326"]]\ """ ), (-1, 'NONE', -1, ' ', 'undefined'), (0, 'NONE', 0, ' ', 'undefined') ] if get_epsg_num(self.tile_grid.srs.srs_code) not in [4326, 3857]: wkt_entries.append((proj, 'epsg', proj, 'Not provided', "Added via Mapproxy.")) db.commit() # Add geopackage version to the header (1.0) db.execute("PRAGMA application_id = 1196437808;") db.commit() for wkt_entry in wkt_entries: try: db.execute(wkt_statement, (wkt_entry[0], wkt_entry[1], wkt_entry[2], wkt_entry[3], wkt_entry[4])) except sqlite3.IntegrityError: log.info("srs_id already exists.".format(wkt_entry[0])) db.commit() # Ensure that tile table exists here, don't overwrite a valid entry. try: db.execute(""" INSERT INTO gpkg_contents ( table_name, data_type, identifier, description, min_x, max_x, min_y, max_y, srs_id) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?); """, (self.table_name, "tiles", self.table_name, "Created with Mapproxy.", self.tile_grid.bbox[0], self.tile_grid.bbox[2], self.tile_grid.bbox[1], self.tile_grid.bbox[3], proj)) except sqlite3.IntegrityError: pass db.commit() # Ensure that tile set exists here, don't overwrite a valid entry. try: db.execute(""" INSERT INTO gpkg_tile_matrix_set (table_name, srs_id, min_x, max_x, min_y, max_y) VALUES (?, ?, ?, ?, ?, ?); """, ( self.table_name, proj, self.tile_grid.bbox[0], self.tile_grid.bbox[2], self.tile_grid.bbox[1], self.tile_grid.bbox[3])) except sqlite3.IntegrityError: pass db.commit() tile_size = self.tile_grid.tile_size for grid, resolution, level in zip(self.tile_grid.grid_sizes, self.tile_grid.resolutions, range(20)): db.execute("""INSERT OR REPLACE INTO gpkg_tile_matrix (table_name, zoom_level, matrix_width, matrix_height, tile_width, tile_height, pixel_x_size, pixel_y_size) VALUES(?, ?, ?, ?, ?, ?, ?, ?) """, (self.table_name, level, grid[0], grid[1], tile_size[0], tile_size[1], resolution, resolution)) db.commit() db.close()