3/29/24About 15 min
Core Code
wmts_main.py
import web
import sys
sys.path.append('.')
import datetime
from utils.oss_util import oss_util
from utils.tile_util import tile_util
from utils.vivid_download import Vivid_WMTS
from utils.vivid_db import vivid_db
from etc import *
accessKey = ''
accessSecretKey = ''
bucketName = ''
oss_obj = oss_util(accessKey, accessSecretKey, bucketName)
urls = (
    '/wmts', 'wmts_ctrl',
    '/WMTS', 'wmts_ctrl',
    '/wmts/(.*)/(.*)/(.*)/(.*)/(.*).jpg', 'wmts_ctrl_resurl',
    '/WMTS/(.*)/(.*)/(.*)/(.*)/(.*).jpg', 'wmts_ctrl_resurl',
)
app = web.application(urls, globals())
def get_oss_key(ilayer, row, col):
    return f'image/{ilayer}/{row}/{col}.jpg'
tile_obj = tile_util()
vivid_obj = Vivid_WMTS("access_key", 'prefix', "account", "password")
vivid_sqlite_obj = vivid_db(wmts_sqlite)
class wmts_tile_service:
    def getTile(self, layer, tilematrix, row, col):
        #return self.getGoogleTile(layer, tilematrix, row, col)
        return self.getVividTile(layer, tilematrix, row, col)
    
    def getVividTile(self, layer, tilematrix, row, col):
        #return self.getTileFromOSS(layer, tilematrix, row, col)
        return self.getTileFromSqlite(tilematrix, row, col)
        
    def getTileFromSqlite(self, tilematrix, row, col):
        return vivid_sqlite_obj.get_tile(int(tilematrix)-1, int(row), int(col))
    
    def getTileFromOSS(self, layer, tilematrix, row, col):
        quad = tile_obj.WMTS2Quad(int(tilematrix)-1, int(row), int(col))
        key = vivid_obj.get_oss_url(quad)
        print(key)
        if oss_obj.is_exists(key):
            print(f'{tilematrix}-{row}-{col}', quad,key, ' found '*10)
            #img = vivid_obj.get(quad)
            return oss_obj.get_obj(key)
        print(quad,key, 'not found')
        return None
    
    def getGoogleTile(self, layer, tilematrix, row, col):
        # Get max row of google wmts
        maxr = 2**int(tilematrix)
        # switch the position
        row = 2**(int(tilematrix)-1) - row
        # Convert the swtched index to google index
        row = int(maxr/4 + row)-1
        return oss_obj.get_obj(get_oss_key(tilematrix, row, col))
        
    def __convertwmts2dbindex__(self, wmts_tilematrix, wmts_r, wmts_c):
        if int(wmts_tilematrix) < 1:
            return None
        level = int(wmts_tilematrix)  #google level
        col = wmts_c                #google column
        maxr = 2**level          #google max row num
        row = (maxr/2-(wmts_r+1)) + maxr / 4          #google row
        
        return int(level), int(row), int(col)
        
    def getCapabilities(self):
        rc = None
        capabilityBase = ''
        content = None
        with open('template/getCapabilities.xml', 'r', encoding='utf-8') as fr:
            content = fr.read()
        return content.replace("127.0.0.1:8045", f"{wmts_ip}:{wmts_port}")
class wmts_service_list_ctrl:
    def __init__(self):
        pass
    def GET(self):
        val = 'webpy get test'
        web.header("Access-Control-Allow-Origin", "*")
        web.header('content-type','text/json')
        return tile_service().getTileDB()
    
    def POST(self):
        val = 'webpy dg_meta'
        web.header("Access-Control-Allow-Origin", "*")
        web.header('content-type','text')
        return val
#tile404 = None
#with open('404.png','rb') as fr:
#    tile404 = fr.read()
    
def get404Tile():
    global tile404
    return None
class wmts_ctrl_resurl:
    def __init__(self):
        pass
    #def GET(self, layer):
    def GET(self, layer, tilematrixset, TileMatrix, TileRow, TileCol):
        val = 'webpy get test'
        web.header("Access-Control-Allow-Origin", "*")
        rc = None
        starttime = datetime.datetime.now()
        layer     = layer
        tilelevel = TileMatrix
        tilecol   = TileCol
        tilerow   = TileRow
        if not(tilelevel is None or layer is None):
            web.header('content-type','image/jpeg')
            rc = wmts_tile_service().getTile(layer, tilelevel, int(tilerow), int(tilecol))
            endtime = datetime.datetime.now()
            pass
        print(rc)
        #if rc is None:
        #    rc = get404Tile()
        if rc is None:
            print(f'{tilelevel}-{tilerow}-{tilecol} not  found {"#"*10}')
            web.notfound()
        else:
            return rc
    def POST(self):
        val = 'webpy dg_meta'
        web.header("Access-Control-Allow-Origin", "*")
        web.header('content-type','text')
        return val
# 获取所有支持的图层列表
class wmts_ctrl:
    def __init__(self):
        pass
    def GET(self):
        val = 'webpy get test'
        web.header("Access-Control-Allow-Origin", "*")
        rc = None
        content = ''
        starttime = datetime.datetime.now()
        self.__kvp__ = dict(web.input())
        service   = self.__getValue__('service')
        layer     = self.__getValue__('layer')
        style     = self.__getValue__('style')
        tilematrixset = self.__getValue__('tilematrixset')
        req       = self.__getValue__('Request')
        version   = self.__getValue__('Version')
        format    = self.__getValue__('Format')
        tileMatrix = self.__getValue__('TileMatrix')
        tilecol   = self.__getValue__('TileCol')
        tilerow   = self.__getValue__('TileRow')
        
        #print(self.__kvp__)
        if not(service is None or req is None):
            if service.upper() == 'WMTS':
                if req.upper() == 'GetCapabilities'.upper():
                    web.header('content-type','text/xml')
                    rc = wmts_tile_service().getCapabilities()
                elif req.upper() == 'GetTile'.upper():
                    web.header('content-type','image/png')
                    print('Get Tile')
                    rc = wmts_tile_service().getTile(layer, tileMatrix, int(tilerow), int(tilecol))
                    endtime = datetime.datetime.now()
                    pass
                elif req.upper() == 'GetFeatureInfo'.upper():
                    pass
        
        #if rc is None:
        #    rc = get404Tile()
        
        #print(rc)
        #if rc is None:
        #    rc = get404Tile()
        if rc is None:
            print(f'{tileMatrix}-{tilerow}-{tilecol} not  found {"#"*10}')
            web.notfound()
        else:
            return rc
    
    def __getCapabilitiesContent__(self):
        rc = None
        capabilityBase = ''
        with open('getCapabilities.xml', 'r') as fr:
            content = fr.read()
            capabilityBase = content
        layerTemplate = ''
        with open('layerTemplate.xml', 'r') as fr:
            layerTemplate = fr.read()
        
        if len(capabilityBase) > 0 and len(layerTemplate)> 0:
            layers = ''
            for l in layers_conf:
                layers += layerTemplate.format(l['id'], l['title'], l['abstract'],TileMatrixSet='{TileMatrixSet}',TileMatrix='{TileMatrix}',TileRow='{TileRow}', TileCol='{TileCol}')
            rc = capabilityBase.format(layers)
        return rc
            
    
    def __getValue__(self, key):
        kvp = self.__kvp__
        rc = None
        for item in kvp.keys():
            if item.upper() == key.upper():
                rc = kvp[item]
                break
        return rc
    
    def POST(self):
        val = 'webpy dg_meta'
        return self.GET()
    def __getimg__(self, layer, level, row, col):
        return wmts_tile_service().getTile(layer, level, row, col)
if __name__=="__main__":
    web.internalerror = web.debugerror
    app.run()utils/tile_util
import math
'''
The code of quad
-------
3  |  2
-------
0  |  1
-------
The first layer of the earth will be split into 
| 0 | 1 |
---------------------------------------------------
The code of WMTS will start from the left-top corner.
The zero layer will split into
| 0-0-0 | 0-1-0 |
The first layer 
| 1-0-0 | 1-1-0 | 1-2-0 | 1-3-0 |
---------------------------------
| 1-0-1 | 1-1-1 | 1-2-1 | 1-3-1 |
'''
class tile_util:
    def __getGeojsonTemplate__(self, name):
        return {
            "type": "FeatureCollection",
            "name": name,
            "crs": {
                "type": "name",
                "properties": {
                    "name": "urn:ogc:def:crs:OGC:1.3:CRS84"
                }
            },
            "features": []
        }
    
    def WMTS2Quad(self, ilayer, row, col):
        '''
        @desc Convert WMTS index into quad index
        @param ilayer WMTS layer number (from 0)
        @param row    WMTS layer tiley number
        @param col    WMTS layer tilex number
        @return The quad index correspond to wmts index
        '''
        offset = 180/2**ilayer
        lat = 90 - (row+0.5)*offset
        lng = (col+0.5)*offset - 180
        return self.getTileQuad(lng, lat, ilayer+1)
    
    def Quad2WMTS(self, quad):
        '''
        @desc Convert quad index into WMTS index
        @parm quad quad index
        @return The WMTS index (layer, col/x, row/y)
        '''
        tilew = 360/(2**len(quad))
        centerx = 0
        centery = 0
        for i in range(len(quad)):
            tilew = 360/(2**(i+1))
            if i == 0:
                if quad[i] == '0':
                    centerx = -90
                    centery = 0
                else:
                    centerx = 90
                    centery = 0
            else:
                if quad[i] == '0':
                    centerx -= tilew/2
                    centery -= tilew/2
                if quad[i] == '1':
                    centerx += tilew/2
                    centery -= tilew/2
                if quad[i] == '2':
                    centerx += tilew/2
                    centery += tilew/2
                if quad[i] == '3':
                    centerx -= tilew/2
                    centery += tilew/2
        wmtsl = len(quad)-1
        wmts_tilew = 180/(2**wmtsl)
        #print(centerx, centery, wmts_tilew)
        tilex = math.floor((centerx+180)/wmts_tilew)
        tiley = math.floor(-(centery-90)/wmts_tilew)
        return wmtsl, tilex, tiley
    
    # Get the sub block list of quad until the specified level
    def getWMTSSubTile(self, quad, level):
        rc = list()
        if len(quad) < level-1:
            rc.extend(self.getWMTSSubTile(quad+'0', level))
            rc.extend(self.getWMTSSubTile(quad+'1', level))
            rc.extend(self.getWMTSSubTile(quad+'2', level))
            rc.extend(self.getWMTSSubTile(quad+'3', level))
            return rc
        elif len(quad) >= level:
            return rc
        else:
            return [quad + '0', quad + '1', quad + '2', quad + '3', ]
    
    # Get the quad number on specified level according to latitude and longtitude.
    def getTileQuad(self, lng, lat, level):
        #level += 1 # Because of quad start from 0, thus the number of quad should plus 1
        minx = -180
        maxx = 180
        miny = -90
        maxy = 90
        
        centerx = 0
        centery = 0
        tilew = 180
        ret = ''
        for l in range(level):
            if l <= 0:
                if lng <= 0:
                    centerx = -90
                    centery = 0
                    ret += '0'
                else:
                    centerx = 90
                    centery = 0
                    ret += '1'
            else:
                if lng < centerx and lat < centery:
                    ret += '0'
                    centerx -= tilew/2
                    centery -= tilew/2
                elif lng > centerx and lat < centery:
                    ret += '1'
                    centerx += tilew/2
                    centery -= tilew/2
                elif lng > centerx and lat > centery:
                    ret += '2'
                    centerx += tilew/2
                    centery += tilew/2
                else:
                    ret += '3'
                    centerx -= tilew/2
                    centery += tilew/2
            tilew /= 2
        return ret
    
    def getBoundingBox(self, quad):
        '''
        Get the bounding box of quad block
        '''
        l, x, y = self.Quad2WMTS(quad)
        tilew  = 180/(2**l)
        maxx = x*tilew + tilew - 180
        minx = x*tilew + 0 -180
        maxy = 90 - (y*tilew + 0)
        miny = 90 - (y*tilew + tilew)
        return minx, maxx, miny, maxy 
    
    def getGeojson(self, quad, targetLevel = None):
        '''
        Get the geojson of quad if the targetLevel is not specified.
        Get the geojson for all sub block until targetLevel regard as quad as a base block
        '''
        rc = None
        if targetLevel:
            rc = self.__getGeojsonTemplate__(f'{quad}-{targetLevel}')
            subs = self.getWMTSSubTile(quad, targetLevel)
            for i in subs:
                rc['features'].append(self.__getFeatureJson__(i))
        else:
            rc = self.__getGeojsonTemplate__(f'{quad}')
            rc['features'].append(self.__getFeatureJson__(quad))
        return rc
    
    def __getFeatureJson__(self, quad):
        '''
        Get the geojson of quad
        '''
        ret = {
                "type": "Feature",
                "properties": dict(),
                "geometry": {
                    "type": "Polygon",
                    "coordinates": list()
                }
            }
        minx, maxx, miny, maxy  = self.getBoundingBox(quad)
        ret['geometry']['coordinates'].append( [[minx, miny], [minx, maxy], [maxx, maxy], [maxx, miny], [minx, miny]])
        ret['properties']['quad'] = quad
        ret['properties']['wmts'] = self.Quad2WMTS(quad)
        return retutils/oss_util
# -*- coding: utf-8 -*-
import oss2
# https://github.com/aliyun/aliyun-oss-python-sdk
class oss_util:
    def __init__(self, accesskey, asscesssecret, bucketname, endpoint='oss-cn-shenzhen.aliyuncs.com'):
        #oss-cn-shenzhen.aliyuncs.com, oss-cn-shenzhen-internal.aliyuncs.com
        self.__bucketname__ = bucketname
        self.__endpoint__ = endpoint
        self.__accesskey__ = accesskey
        self.__asscesssecret__ = asscesssecret
        self.__auth__ = oss2.Auth(self.__accesskey__, self.__asscesssecret__)
        self.__bucket__ = oss2.Bucket(self.__auth__, self.__endpoint__, self.__bucketname__)
    
    def upload(self, key, obj):
        self.__bucket__.put_object(key, obj)
    
    def get_obj(self, key):
        try:
            return self.__bucket__.get_object(key).read()
        except oss2.exceptions.NoSuchKey as e:
            pass
        
    def del_obj(self, key):
        self.__bucket__.delete_object(key)
    
    def is_exists(self, key):
        return self.__bucket__.object_exists(key)
        
    def iterator(self, prefix):
        return oss2.ObjectIterator(self.__bucket__, prefix)utils/dg_download
import requests as req
import random
import datetime as dt
import sys
import math
import threading
import time
import json
import sys
import os
import gzip
sys.path.append('.')
from .tile_util import *
from .thread_util import *
class dg_downloader:
    def __init__(self, connectid, type_name, token=None, version='2.0.0', format='application%2Fjson'):
        self.base_url = 'https://securewatch.digitalglobe.com'
        self.tile_obj = tile_util()
        self.__token__ = token
        self.__connectid__ = connectid
        self.__type_name__ = type_name
        self.__version__   = version
        self.__format__    = format
        
        # 模板参数说明
        # @param connectId the connect id
        # @param type_name layername
        # @param lat_min   the minimum latitude
        # @param lng_min   the minimum longtitude
        # @param lat_max   the maximum latitude
        # @param lng_max   the minimum longtitude
        # @param version   the ogc service version (such as:2.0.0)
        # @param format    the output format,(such as:application/json)
        self.wfs_template = self.base_url + '/catalogservice/wfsaccess?CONNECTID={connectId}&SERVICE=WFS&REQUEST=GetFeature&VERSION={version}&TYPENAMES={type_name}&TYPENAME={type_name}&STARTINDEX=0&COUNT=1000000&SRSNAME=urn:ogc:def:crs:EPSG::4326&BBOX={lat_min},{lng_min},{lat_max},{lng_max},urn:ogc:def:crs:EPSG::4326&outputFormat={format}'
    def __del__(self):
        pass
        
    def downlaod(self, base_tile, target_level, filename):
        '''
        @param base_tile    The base tile()
        @param target_level
        @param filename
        The data is retrived from server block by block. The base_tile will determine a big blog for downloading, the target_level define which level will continue split the base_tile.
        '''
        self._base_tile_ = base_tile
        sub_tiles = self.tile_obj.getWMTSSubTile(base_tile, target_level)
        output_file = {
            'log': open(f'{filename}.geojson', 'w'),
            'locker': threading.Lock()
        }
        
        th_pool = thread_util(20)
        
        for sub_tile in sub_tiles:
            lng_min, lng_max, lat_min, lat_max  = self.tile_obj.getBoundingBox(sub_tile)
            version   = self.__version__
            format    = self.__format__
            type_name = self.__type_name__
            connectId = self.__connectid__
            
            url = eval(f'f"{self.wfs_template}"')
            req_param = sub_tile
            print(url)
            th_pool.process(self.thread_req, (url, req_param, output_file), req_param)
        th_pool.wait()
        with output_file['locker']:
            output_file['log'].close()
        
    def thread_req(self, url, req_param, output_file):
        #print(url)
        ret = self.getRespInfo(url, req_param)
        #print(ret)
        with output_file['locker']:
            output_file['log'].write(f'{ret}\n')
        
    def getRespInfo(self, url, req_param):
        resp = None
        rc = None
        try:
            headers= {
                'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7',
                'Accept-Encoding': 'gzip, deflate, br',
                'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6',
                'Authorization': self.__token__,
                'Sec-Ch-Ua': '"Chromium";v="116", "Not)A;Brand";v="24", "Microsoft Edge";v="116"',
                'Sec-Ch-Ua-Platform': '"Windows"',
                'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36 Edg/116.0.1938.76'
            }
            resp = req.get(url, headers = headers)
            
            if resp:
                resp_code = resp.status_code
                if 200 == resp_code:
                    #print(resp.text)
                    content = resp.text
                    #content = gzip.decompress(resp.content).decode()
                    rc = f'{req_param}|{content}'
                resp.close()
        except Exception as e:
            pass
        return rcutils/thread_util
import threading
class thread_util:
    def __init__(self, thread_max = 20):
        self.__thread_pool__ = list()
        self.__thread_max__ = 1
        if thread_max:
            self.__thread_max__ = thread_max
    
    def process(self, target, args, name):
        th = threading.Thread(target=target, args=args, name= name)
        self.__thread_pool__.append(th)
        th.start()
        self.__update_thread__()
    
    def wait(self):
        self.__update_thread__(1)
    
    def __update_thread__(self, count = None):
        c = self.__thread_max__
        if count:
            c = count
        while len(self.__thread_pool__) >= c:
            dead_pool = []
            for th in self.__thread_pool__:
                if not th.is_alive():
                    dead_pool.append(th)
            for item in dead_pool:
                self.__thread_pool__.remove(item)
            #time.sleep(0.1)utils/vivid_db
import threading
import sqlite3
import os
from .tile_util import tile_util
class vivid_db:
    _instance_lock = threading.Lock()
    def __init__(self, dbfile):
        if hasattr(self, 'tile_dbs'):
            return
        self.tile_dbs = dict()
        if os.path.exists(dbfile):
            print(f"connect {dbfile}")
            self.__db__ = sqlite3.connect(dbfile, check_same_thread = False)
            self.__locker__ = threading.Lock()
        else:
            raise f"{dbfile} does not exist"
            
    #Single Class
    def __new__(cls, *args, **kwargs):
        if not hasattr(eval(cls.__name__), "_instance"):
            with eval(cls.__name__)._instance_lock:
                if not hasattr(eval(cls.__name__), "_instance"):
                    eval(cls.__name__)._instance = object.__new__(cls)
        return eval(cls.__name__)._instance
    
    def __del__(self):
        if self.__db__:
            self.__db__.close()
        pass
    
    def get_tbl_name(self, level, row, col):
        rc = None
        if level <= 7:
            rc = self.get_tile_id(level, row, col)[:1]
        elif level <= 11:
            rc = self.get_tile_id(level, row, col)[:5]
        elif level <= 15:
            rc = self.get_tile_id(level, row, col)[:9]
        elif level <= 19:
            rc = self.get_tile_id(level, row, col)[:13]
        return f"tile_{rc}"
    
    def get_create_tbl_sql(self, level, row, col):
        return f'''create table if not exists {self.get_tbl_name(level, row, col)}(oid varchar(50) PRIMARY KEY, img blob);'''
    
    def get_tile_id(self, level, row, col):
        return tile_util().WMTS2Quad(level, row, col)
    
    def get_tile(self, level, row, col):
        oid = self.get_tile_id(level, row, col)
        tbl = self.get_tbl_name(level, row, col)
        rc = None
        with self.__locker__:
            c = self.__db__.cursor()   # 创建游标
            try:
                print(f"select img from {tbl} where oid='{oid}'")
                c.execute(f"select img from {tbl} where oid='{oid}'")   #查询快试图数据
                rc = c.fetchone()[0]
            except Exception as e:
                print(e)
            finally:
                c.close()
        return rc
    
    def insert_tile(self, level, row, col, img):
        with self.__locker__:
            db_cursor = self.__db__.cursor()
            oid = self.get_tile_id(level, row, col)
            tbl = self.get_tbl_name(level, row, col)
            #print(self.get_create_tbl_sql(level, row, col))
            db_cursor.execute(self.get_create_tbl_sql(level, row, col))
            db_cursor.execute(f"INSERT INTO {tbl}(oid, img) VALUES (?, ?)", (oid, img))#存入图片
            self.__db__.commit()
            db_cursor.close()
    
    def insert_tiles(self, tiles):
        with self.__locker__:
            db_cursor = self.__db__.cursor()
            for tile in tiles:
                level, row, col, img = tile
                db_cursor.execute(self.get_create_tbl_sql(level, row, col))
                oid = self.get_tile_id(level, row, col)
                tbl = self.get_tbl_name(level, row, col)
                db_cursor.execute(f"INSERT INTO {tbl}(oid, img) VALUES (?, ?)", (oid, img))#存入图片
            self.__db__.commit()
            db_cursor.close()utils/vivid_download
from .tile_util import tile_util
import requests as req
from base64 import b64encode
from functools import reduce
# Authorization token is using base 64 to encode
def basic_auth(username, password):
    token = b64encode(f"{username}:{password}".encode('utf-8')).decode("ascii")
    return f'Basic {token}'
class Vivid_WMTS:
    def __init__(self, connectid, tilematrixset, username, password):
        self.__tile_util__ = tile_util()
        self.__base_url__ = 'https://securewatch.digitalglobe.com'
        self.__uri__ = '/earthservice/wmtsaccess'
        self.__connectid__ = connectid
        self.__tilematrixset__ = tilematrixset
        self.__username__ = username
        self.__password__ = password
        self.__params__ = {
            'CONNECTID':self.__connectid__,
            'SERVICE':'WMTS',
            'REQUEST':'GetTile',
            'VERSION':'1.0.0',
            'LAYER':'DigitalGlobe:ImageryTileService',
            'STYLE':'_null',
            'FORMAT':'image/jpeg',
            'TILEMATRIXSET':self.__tilematrixset__, #'EPSG:4326',
            'TILEMATRIX':'EPSG:4326:11',
            'TILEROW':'575',
            'TILECOL':'3363',
        }
    
    def get_url(self, quad):
        ilayer, col, row = self.__tile_util__.Quad2WMTS(quad)
        self.__params__["TILEMATRIX"] = f'{self.__params__["TILEMATRIXSET"]}:{ilayer}'
        self.__params__["TILEROW"] = row
        self.__params__["TILECOL"] = col
        param_obj = self.__params__
        params = reduce(lambda x, key: f"{key}={param_obj[key]}" if len(x) == 0 else f"{x}&{key}={param_obj[key]}", param_obj,"")
        return f"{self.__base_url__}{self.__uri__}?{params}"
    
    def getHeaders(self):
        return {"Authorization":basic_auth(self.__username__, self.__password__)}
    
    def get_oss_url(self, quad):
        ilayer, col, row = self.__tile_util__.Quad2WMTS(quad)
        if ilayer >= 7 and ilayer<=12:
            return f'wmts/vivid/imagerytileservice/4326/default/jpg/7-12/{quad[:5]}/{ilayer}/{row}-{col}.jpg'
        elif ilayer >= 13:
            return f'wmts/vivid/imagerytileservice/4326/default/jpg/13-19/{quad[:10]}/{ilayer}/{row}-{col}.jpg'
        elif ilayer >= 3:
            return f'wmts/vivid/imagerytileservice/4326/default/jpg/3-6/{quad[:2]}/{ilayer}/{row}-{col}.jpg'
        elif ilayer < 3:
            return f'wmts/vivid/imagerytileservice/4326/default/jpg/0-2/{ilayer}/{row}-{col}.jpg'
    
    def get(self, quad):
        url = self.get_url(quad)
        try:
            resp = req.get(url, headers=self.getHeaders())
            if len(resp.content) == 689:
                return None
            return resp.content
        except Exception as e:
            print(e)Conf
etc/init
wmts_ip = "127.0.0.1"
wmts_port=89
wmts_sqlite="vivid_tiles.db"template/getCapabilities.xml
<?xml version="1.0" encoding="UTF-8"?>
<Capabilities xmlns="http://www.opengis.net/wmts/1.0" 
    xmlns:ows="http://www.opengis.net/ows/1.1" 
    xmlns:xlink="http://www.w3.org/1999/xlink" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns:gml="http://www.opengis.net/gml" 
    xsi:schemaLocation="http://www.opengis.net/wmts/1.0 http://schemas.opengis.net/wmts/1.0.0/wmtsGetCapabilities_response.xsd" 
    version="1.0.0">
    <ows:ServiceIdentification>
        <ows:ServiceType>WMTS</ows:ServiceType>
        <ows:ServiceTypeVersion>1.0.0</ows:ServiceTypeVersion>
        <ows:Title>wmts service</ows:Title>
        <ows:Abstract/>
        <ows:Keywords>
            <ows:Keyword>geodetic</ows:Keyword>
            <ows:Keyword>mercator</ows:Keyword>
            <ows:Keyword>OGC</ows:Keyword>
            <ows:Keyword>WMTS</ows:Keyword>
        </ows:Keywords>
        <ows:Fees>none</ows:Fees>
        <ows:AccessConstraints>false</ows:AccessConstraints>
    </ows:ServiceIdentification>
    <ows:ServiceProvider>
        <ows:ProviderName>Haiyue</ows:ProviderName>
        <ows:ProviderSite xlink:href="http://www.newmapgis.com"/>
        <ows:ServiceContact>
            <ows:IndividualName>Haiyue</ows:IndividualName>
            <ows:PositionName>Adelaide</ows:PositionName>
            <ows:ContactInfo>
                <ows:Phone>
                    <ows:Voice>xxxx</ows:Voice>
                    <ows:Facsimile>xxxx</ows:Facsimile>
                </ows:Phone>
                <ows:Address>
                    <ows:Country>Australia</ows:Country>
                    <ows:City>Adelaide</ows:City>
                    <ows:PostalCode>xxxx</ows:PostalCode>
                    <ows:PostalAddress>xxxx</ows:PostalAddress>
                    <ows:ElectronicMailAddress>nutterair1989@gmail.com</ows:ElectronicMailAddress>
                </ows:Address>
            </ows:ContactInfo>
        </ows:ServiceContact>
    </ows:ServiceProvider>
    <ows:OperationsMetadata>
        <ows:Operation name="GetCapabilities">
            <ows:DCP>
                <ows:HTTP>
                    <ows:Get xlink:href="http://127.0.0.1:8045/wmts?">
                        <ows:Constraint name="GetEncoding">
                            <ows:AllowedValues>
                                <ows:Value>KVP</ows:Value>
                            </ows:AllowedValues>
                        </ows:Constraint>
                    </ows:Get>
                </ows:HTTP>
            </ows:DCP>
        </ows:Operation>
        <ows:Operation name="GetTile">
            <ows:DCP>
                <ows:HTTP>
                    <ows:Get xlink:href="http://127.0.0.1:8045/wmts?">
                        <ows:Constraint name="GetEncoding">
                            <ows:AllowedValues>
                                <ows:Value>KVP</ows:Value>
                            </ows:AllowedValues>
                        </ows:Constraint>
                    </ows:Get>
                </ows:HTTP>
            </ows:DCP>
        </ows:Operation>
    </ows:OperationsMetadata>
    <Contents>
        <Layer>
            <ows:Title>ge_wmts</ows:Title>
            <ows:WGS84BoundingBox>
                <ows:LowerCorner>-180.0 -90.0</ows:LowerCorner>
                <ows:UpperCorner>180.0 90.0</ows:UpperCorner>
            </ows:WGS84BoundingBox>
            <ows:Identifier>ge_wmts</ows:Identifier>
            <Style isDefault="true">
                <ows:Identifier>_null</ows:Identifier>
            </Style>
            <Format>image/jpeg</Format>
            <TileMatrixSetLink>
                <TileMatrixSet>WGS84</TileMatrixSet>
            </TileMatrixSetLink>
        </Layer>
        <TileMatrixSet>
            <ows:Identifier>WGS84</ows:Identifier>
            <ows:BoundingBox crs="urn:ogc:def:crs:EPSG:6.3:4326">
                <ows:LowerCorner>-90.000000 -180.000000</ows:LowerCorner>
                <ows:UpperCorner>90.000000 180.000000</ows:UpperCorner>
            </ows:BoundingBox>
            <ows:SupportedCRS>urn:ogc:def:crs:EPSG:6.3:4326</ows:SupportedCRS>
            <WellKnownScaleSet>urn:ogc:def:wkss:OGC:1.0:GoogleCRS84Quad</WellKnownScaleSet>
            <!--TileMatrix>
                <ows:Identifier>0</ows:Identifier>
                <ScaleDenominator>279541132.01435887813568115234</ScaleDenominator>
                <TopLeftCorner>90.000000 -180.000000</TopLeftCorner>
                <TileWidth>256</TileWidth>
                <TileHeight>256</TileHeight>
                <MatrixWidth>2</MatrixWidth>
                <MatrixHeight>1</MatrixHeight>
            </TileMatrix-->
            <TileMatrix>
                <ows:Identifier>2</ows:Identifier>
                <ScaleDenominator>139770566.00717943906784057617</ScaleDenominator>
                <TopLeftCorner>90.000000 -180.000000</TopLeftCorner>
                <TileWidth>256</TileWidth>
                <TileHeight>256</TileHeight>
                <MatrixWidth>4</MatrixWidth>
                <MatrixHeight>2</MatrixHeight>
            </TileMatrix>
            <TileMatrix>
                <ows:Identifier>3</ows:Identifier>
                <ScaleDenominator>69885283.00358971953392028809</ScaleDenominator>
                <TopLeftCorner>90.000000 -180.000000</TopLeftCorner>
                <TileWidth>256</TileWidth>
                <TileHeight>256</TileHeight>
                <MatrixWidth>8</MatrixWidth>
                <MatrixHeight>4</MatrixHeight>
            </TileMatrix>
            <TileMatrix>
                <ows:Identifier>4</ows:Identifier>
                <ScaleDenominator>34942641.50179485976696014404</ScaleDenominator>
                <TopLeftCorner>90.000000 -180.000000</TopLeftCorner>
                <TileWidth>256</TileWidth>
                <TileHeight>256</TileHeight>
                <MatrixWidth>16</MatrixWidth>
                <MatrixHeight>8</MatrixHeight>
            </TileMatrix>
            <TileMatrix>
                <ows:Identifier>5</ows:Identifier>
                <ScaleDenominator>17471320.75089742988348007202</ScaleDenominator>
                <TopLeftCorner>90.000000 -180.000000</TopLeftCorner>
                <TileWidth>256</TileWidth>
                <TileHeight>256</TileHeight>
                <MatrixWidth>32</MatrixWidth>
                <MatrixHeight>16</MatrixHeight>
            </TileMatrix>
            <TileMatrix>
                <ows:Identifier>6</ows:Identifier>
                <ScaleDenominator>8735660.37544871494174003601</ScaleDenominator>
                <TopLeftCorner>90.000000 -180.000000</TopLeftCorner>
                <TileWidth>256</TileWidth>
                <TileHeight>256</TileHeight>
                <MatrixWidth>64</MatrixWidth>
                <MatrixHeight>32</MatrixHeight>
            </TileMatrix>
            <TileMatrix>
                <ows:Identifier>7</ows:Identifier>
                <ScaleDenominator>4367830.18772435747087001801</ScaleDenominator>
                <TopLeftCorner>90.000000 -180.000000</TopLeftCorner>
                <TileWidth>256</TileWidth>
                <TileHeight>256</TileHeight>
                <MatrixWidth>128</MatrixWidth>
                <MatrixHeight>64</MatrixHeight>
            </TileMatrix>
            <TileMatrix>
                <ows:Identifier>8</ows:Identifier>
                <ScaleDenominator>2183915.09386217873543500900</ScaleDenominator>
                <TopLeftCorner>90.000000 -180.000000</TopLeftCorner>
                <TileWidth>256</TileWidth>
                <TileHeight>256</TileHeight>
                <MatrixWidth>256</MatrixWidth>
                <MatrixHeight>128</MatrixHeight>
            </TileMatrix>
            <TileMatrix>
                <ows:Identifier>9</ows:Identifier>
                <ScaleDenominator>1091957.54693108936771750450</ScaleDenominator>
                <TopLeftCorner>90.000000 -180.000000</TopLeftCorner>
                <TileWidth>256</TileWidth>
                <TileHeight>256</TileHeight>
                <MatrixWidth>512</MatrixWidth>
                <MatrixHeight>256</MatrixHeight>
            </TileMatrix>
            <TileMatrix>
                <ows:Identifier>10</ows:Identifier>
                <ScaleDenominator>545978.77346554468385875225</ScaleDenominator>
                <TopLeftCorner>90.000000 -180.000000</TopLeftCorner>
                <TileWidth>256</TileWidth>
                <TileHeight>256</TileHeight>
                <MatrixWidth>1024</MatrixWidth>
                <MatrixHeight>512</MatrixHeight>
            </TileMatrix>
            <TileMatrix>
                <ows:Identifier>11</ows:Identifier>
                <ScaleDenominator>272989.38673277234192937613</ScaleDenominator>
                <TopLeftCorner>90.000000 -180.000000</TopLeftCorner>
                <TileWidth>256</TileWidth>
                <TileHeight>256</TileHeight>
                <MatrixWidth>2048</MatrixWidth>
                <MatrixHeight>1024</MatrixHeight>
            </TileMatrix>
            <TileMatrix>
                <ows:Identifier>12</ows:Identifier>
                <ScaleDenominator>136494.69336638617096468806</ScaleDenominator>
                <TopLeftCorner>90.000000 -180.000000</TopLeftCorner>
                <TileWidth>256</TileWidth>
                <TileHeight>256</TileHeight>
                <MatrixWidth>4096</MatrixWidth>
                <MatrixHeight>2048</MatrixHeight>
            </TileMatrix>
            <TileMatrix>
                <ows:Identifier>13</ows:Identifier>
                <ScaleDenominator>68247.34668319308548234403</ScaleDenominator>
                <TopLeftCorner>90.000000 -180.000000</TopLeftCorner>
                <TileWidth>256</TileWidth>
                <TileHeight>256</TileHeight>
                <MatrixWidth>8192</MatrixWidth>
                <MatrixHeight>4096</MatrixHeight>
            </TileMatrix>
            <TileMatrix>
                <ows:Identifier>14</ows:Identifier>
                <ScaleDenominator>34123.67334159654274117202</ScaleDenominator>
                <TopLeftCorner>90.000000 -180.000000</TopLeftCorner>
                <TileWidth>256</TileWidth>
                <TileHeight>256</TileHeight>
                <MatrixWidth>16384</MatrixWidth>
                <MatrixHeight>8192</MatrixHeight>
            </TileMatrix>
            <TileMatrix>
                <ows:Identifier>15</ows:Identifier>
                <ScaleDenominator>17061.83667079825318069197</ScaleDenominator>
                <TopLeftCorner>90.000000 -180.000000</TopLeftCorner>
                <TileWidth>256</TileWidth>
                <TileHeight>256</TileHeight>
                <MatrixWidth>32768</MatrixWidth>
                <MatrixHeight>16384</MatrixHeight>
            </TileMatrix>
            <TileMatrix>
                <ows:Identifier>16</ows:Identifier>
                <ScaleDenominator>8530.91833539912659034599</ScaleDenominator>
                <TopLeftCorner>90.000000 -180.000000</TopLeftCorner>
                <TileWidth>256</TileWidth>
                <TileHeight>256</TileHeight>
                <MatrixWidth>65536</MatrixWidth>
                <MatrixHeight>32768</MatrixHeight>
            </TileMatrix>
            <TileMatrix>
                <ows:Identifier>17</ows:Identifier>
                <ScaleDenominator>4265.45916769956329517299</ScaleDenominator>
                <TopLeftCorner>90.000000 -180.000000</TopLeftCorner>
                <TileWidth>256</TileWidth>
                <TileHeight>256</TileHeight>
                <MatrixWidth>131072</MatrixWidth>
                <MatrixHeight>65536</MatrixHeight>
            </TileMatrix>
            <TileMatrix>
                <ows:Identifier>18</ows:Identifier>
                <ScaleDenominator>2132.72958384978574031265</ScaleDenominator>
                <TopLeftCorner>90.000000 -180.000000</TopLeftCorner>
                <TileWidth>256</TileWidth>
                <TileHeight>256</TileHeight>
                <MatrixWidth>262144</MatrixWidth>
                <MatrixHeight>131072</MatrixHeight>
            </TileMatrix>
            <TileMatrix>
                <ows:Identifier>19</ows:Identifier>
                <ScaleDenominator>1066.36479192489287015632</ScaleDenominator>
                <TopLeftCorner>90.000000 -180.000000</TopLeftCorner>
                <TileWidth>256</TileWidth>
                <TileHeight>256</TileHeight>
                <MatrixWidth>524288</MatrixWidth>
                <MatrixHeight>262144</MatrixHeight>
            </TileMatrix>
        </TileMatrixSet>
        <TileMatrixSet>
            <ows:Identifier>forarcmap</ows:Identifier>
            <ows:SupportedCRS>urn:ogc:def:crs:EPSG::4326</ows:SupportedCRS>
            <WellKnownScaleSet>urn:ogc:def:wkss:OGC:1.0:GoogleCRS84Quad</WellKnownScaleSet>
            <TileMatrix>
                <ows:Identifier>2</ows:Identifier>
                <ScaleDenominator>1.3977056600717944E8</ScaleDenominator>
                <TopLeftCorner>90 -180</TopLeftCorner>
                <BottomRightCorner>-90 180</BottomRightCorner>
                <TileWidth>256</TileWidth>
                <TileHeight>256</TileHeight>
                <MatrixHeight>2</MatrixHeight>
                <MatrixWidth>4</MatrixWidth>
            </TileMatrix>
            <TileMatrix>
                <ows:Identifier>3</ows:Identifier>
                <ScaleDenominator>6.988528300358972E7</ScaleDenominator>
                <TopLeftCorner>90 -180</TopLeftCorner>
                <BottomRightCorner>-90 180</BottomRightCorner>
                <TileWidth>256</TileWidth>
                <TileHeight>256</TileHeight>
                <MatrixWidth>8</MatrixWidth>
                <MatrixHeight>4</MatrixHeight>
            </TileMatrix>
            <TileMatrix>
                <ows:Identifier>4</ows:Identifier>
                <ScaleDenominator>3.494264150179486E7</ScaleDenominator>
                <TopLeftCorner>90 -180</TopLeftCorner>
                <BottomRightCorner>-90 180</BottomRightCorner>
                <TileWidth>256</TileWidth>
                <TileHeight>256</TileHeight>
                <MatrixWidth>16</MatrixWidth>
                <MatrixHeight>8</MatrixHeight>
            </TileMatrix>
            <TileMatrix>
                <ows:Identifier>5</ows:Identifier>
                <ScaleDenominator>1.747132075089743E7</ScaleDenominator>
                <TopLeftCorner>90 -180</TopLeftCorner>
                <BottomRightCorner>-90 180</BottomRightCorner>
                <TileWidth>256</TileWidth>
                <TileHeight>256</TileHeight>
                <MatrixWidth>32</MatrixWidth>
                <MatrixHeight>16</MatrixHeight>
            </TileMatrix>
            <TileMatrix>
                <ows:Identifier>6</ows:Identifier>
                <ScaleDenominator>8735660.375448715</ScaleDenominator>
                <TopLeftCorner>90 -180</TopLeftCorner>
                <BottomRightCorner>-90 180</BottomRightCorner>
                <TileWidth>256</TileWidth>
                <TileHeight>256</TileHeight>
                <MatrixWidth>64</MatrixWidth>
                <MatrixHeight>32</MatrixHeight>
            </TileMatrix>
            <TileMatrix>
                <ows:Identifier>7</ows:Identifier>
                <ScaleDenominator>4367830.1877243575</ScaleDenominator>
                <TopLeftCorner>90 -180</TopLeftCorner>
                <BottomRightCorner>-90 180</BottomRightCorner>
                <TileWidth>256</TileWidth>
                <TileHeight>256</TileHeight>
                <MatrixWidth>128</MatrixWidth>
                <MatrixHeight>64</MatrixHeight>
            </TileMatrix>
            <TileMatrix>
                <ows:Identifier>8</ows:Identifier>
                <ScaleDenominator>2183915.0938621787</ScaleDenominator>
                <TopLeftCorner>90 -180</TopLeftCorner>
                <BottomRightCorner>-90 180</BottomRightCorner>
                <TileWidth>256</TileWidth>
                <TileHeight>256</TileHeight>
                <MatrixWidth>256</MatrixWidth>
                <MatrixHeight>128</MatrixHeight>
            </TileMatrix>
            <TileMatrix>
                <ows:Identifier>9</ows:Identifier>
                <ScaleDenominator>1091957.5469310894</ScaleDenominator>
                <TopLeftCorner>90 -180</TopLeftCorner>
                <BottomRightCorner>-90 180</BottomRightCorner>
                <TileWidth>256</TileWidth>
                <TileHeight>256</TileHeight>
                <MatrixWidth>512</MatrixWidth>
                <MatrixHeight>256</MatrixHeight>
            </TileMatrix>
            <TileMatrix>
                <ows:Identifier>10</ows:Identifier>
                <ScaleDenominator>545978.7734655447</ScaleDenominator>
                <TopLeftCorner>90 -180</TopLeftCorner>
                <BottomRightCorner>-90 180</BottomRightCorner>
                <TileWidth>256</TileWidth>
                <TileHeight>256</TileHeight>
                <MatrixWidth>1024</MatrixWidth>
                <MatrixHeight>512</MatrixHeight>
            </TileMatrix>
            <TileMatrix>
                <ows:Identifier>11</ows:Identifier>
                <ScaleDenominator>272989.38673277234</ScaleDenominator>
                <TopLeftCorner>90 -180</TopLeftCorner>
                <BottomRightCorner>-90 180</BottomRightCorner>
                <TileWidth>256</TileWidth>
                <TileHeight>256</TileHeight>
                <MatrixWidth>2048</MatrixWidth>
                <MatrixHeight>1024</MatrixHeight>
            </TileMatrix>
            <TileMatrix>
                <ows:Identifier>12</ows:Identifier>
                <ScaleDenominator>136494.69336638617</ScaleDenominator>
                <TopLeftCorner>90 -180</TopLeftCorner>
                <BottomRightCorner>-90 180</BottomRightCorner>
                <TileWidth>256</TileWidth>
                <TileHeight>256</TileHeight>
                <MatrixWidth>4096</MatrixWidth>
                <MatrixHeight>2048</MatrixHeight>
            </TileMatrix>
            <TileMatrix>
                <ows:Identifier>13</ows:Identifier>
                <ScaleDenominator>68247.34668319309</ScaleDenominator>
                <TopLeftCorner>90 -180</TopLeftCorner>
                <BottomRightCorner>-90 180</BottomRightCorner>
                <TileWidth>256</TileWidth>
                <TileHeight>256</TileHeight>
                <MatrixWidth>8192</MatrixWidth>
                <MatrixHeight>4096</MatrixHeight>
            </TileMatrix>
            <TileMatrix>
                <ows:Identifier>14</ows:Identifier>
                <ScaleDenominator>34123.67334159654</ScaleDenominator>
                <TopLeftCorner>90 -180</TopLeftCorner>
                <BottomRightCorner>-90 180</BottomRightCorner>
                <TileWidth>256</TileWidth>
                <TileHeight>256</TileHeight>
                <MatrixWidth>16384</MatrixWidth>
                <MatrixHeight>8192</MatrixHeight>
            </TileMatrix>
            <TileMatrix>
                <ows:Identifier>15</ows:Identifier>
                <ScaleDenominator>17061.83667079827</ScaleDenominator>
                <TopLeftCorner>90 -180</TopLeftCorner>
                <BottomRightCorner>-90 180</BottomRightCorner>
                <TileWidth>256</TileWidth>
                <TileHeight>256</TileHeight>
                <MatrixWidth>32768</MatrixWidth>
                <MatrixHeight>16384</MatrixHeight>
            </TileMatrix>
            <TileMatrix>
                <ows:Identifier>16</ows:Identifier>
                <ScaleDenominator>8530.918335399136</ScaleDenominator>
                <TopLeftCorner>90 -180</TopLeftCorner>
                <BottomRightCorner>-90 180</BottomRightCorner>
                <TileWidth>256</TileWidth>
                <TileHeight>256</TileHeight>
                <MatrixWidth>65536</MatrixWidth>
                <MatrixHeight>32768</MatrixHeight>
            </TileMatrix>
            <TileMatrix>
                <ows:Identifier>17</ows:Identifier>
                <ScaleDenominator>4265.459167699568</ScaleDenominator>
                <TopLeftCorner>90 -180</TopLeftCorner>
                <BottomRightCorner>-90 180</BottomRightCorner>
                <TileWidth>256</TileWidth>
                <TileHeight>256</TileHeight>
                <MatrixWidth>131072</MatrixWidth>
                <MatrixHeight>65536</MatrixHeight>
            </TileMatrix>
            <TileMatrix>
                <ows:Identifier>18</ows:Identifier>
                <ScaleDenominator>2132.729583849784</ScaleDenominator>
                <TopLeftCorner>90 -180</TopLeftCorner>
                <BottomRightCorner>-90 180</BottomRightCorner>
                <TileWidth>256</TileWidth>
                <TileHeight>256</TileHeight>
                <MatrixWidth>262144</MatrixWidth>
                <MatrixHeight>131072</MatrixHeight>
            </TileMatrix>
            <TileMatrix>
                <ows:Identifier>19</ows:Identifier>
                <ScaleDenominator>1066.364791924892</ScaleDenominator>
                <TopLeftCorner>90 -180</TopLeftCorner>
                <BottomRightCorner>-90 180</BottomRightCorner>
                <TileWidth>256</TileWidth>
                <TileHeight>256</TileHeight>
                <MatrixWidth>524288</MatrixWidth>
                <MatrixHeight>262144</MatrixHeight>
            </TileMatrix>
        </TileMatrixSet>
        
        <TileMatrixSet>
            <ows:Identifier>supermap</ows:Identifier>
            <ows:SupportedCRS>urn:ogc:def:crs:EPSG::4326</ows:SupportedCRS>
            <WellKnownScaleSet>ChinaPublicServices</WellKnownScaleSet>
            <TileMatrix>
                <ows:Identifier>1</ows:Identifier>
                <ScaleDenominator>1.47914677725E8</ScaleDenominator>
                <!-- <Resolution>0.3515625</Resolution> -->
                <TopLeftCorner>90.0 -180.0</TopLeftCorner>
                <TileWidth>256</TileWidth>
                <TileHeight>256</TileHeight>
                <MatrixWidth>4</MatrixWidth>
                <MatrixHeight>2</MatrixHeight>
            </TileMatrix>
            <TileMatrix>
                <ows:Identifier>2</ows:Identifier>
                <ScaleDenominator>7.39573388625E7</ScaleDenominator>
                <!-- <Resolution>0.17578125</Resolution> -->
                <TopLeftCorner>90.0 -180.0</TopLeftCorner>
                <TileWidth>256</TileWidth>
                <TileHeight>256</TileHeight>
                <MatrixWidth>8</MatrixWidth>
                <MatrixHeight>4</MatrixHeight>
            </TileMatrix>
            <TileMatrix>
                <ows:Identifier>3</ows:Identifier>
                <ScaleDenominator>3.697866943125E7</ScaleDenominator>
                <!-- <Resolution>0.087890625</Resolution> -->
                <TopLeftCorner>90.0 -180.0</TopLeftCorner>
                <TileWidth>256</TileWidth>
                <TileHeight>256</TileHeight>
                <MatrixWidth>16</MatrixWidth>
                <MatrixHeight>8</MatrixHeight>
            </TileMatrix>
            <TileMatrix>
                <ows:Identifier>4</ows:Identifier>
                <ScaleDenominator>1.8489334715625E7</ScaleDenominator>
                <!-- <Resolution>0.0439453125</Resolution> -->
                <TopLeftCorner>90.0 -180.0</TopLeftCorner>
                <TileWidth>256</TileWidth>
                <TileHeight>256</TileHeight>
                <MatrixWidth>32</MatrixWidth>
                <MatrixHeight>16</MatrixHeight>
            </TileMatrix>
            <TileMatrix>
                <ows:Identifier>5</ows:Identifier>
                <ScaleDenominator>9244667.3578125</ScaleDenominator>
                <!-- <Resolution>0.02197265625</Resolution> -->
                <TopLeftCorner>90.0 -180.0</TopLeftCorner>
                <TileWidth>256</TileWidth>
                <TileHeight>256</TileHeight>
                <MatrixWidth>64</MatrixWidth>
                <MatrixHeight>32</MatrixHeight>
            </TileMatrix>
            <TileMatrix>
                <ows:Identifier>6</ows:Identifier>
                <ScaleDenominator>4622333.67890625</ScaleDenominator>
                <!-- <Resolution>0.010986328125</Resolution> -->
                <TopLeftCorner>90.0 -180.0</TopLeftCorner>
                <TileWidth>256</TileWidth>
                <TileHeight>256</TileHeight>
                <MatrixWidth>128</MatrixWidth>
                <MatrixHeight>64</MatrixHeight>
            </TileMatrix>
            <TileMatrix>
                <ows:Identifier>7</ows:Identifier>
                <ScaleDenominator>2311166.839453125</ScaleDenominator>
                <!-- <Resolution>0.0054931640625</Resolution> -->
                <TopLeftCorner>90.0 -180.0</TopLeftCorner>
                <TileWidth>256</TileWidth>
                <TileHeight>256</TileHeight>
                <MatrixWidth>256</MatrixWidth>
                <MatrixHeight>128</MatrixHeight>
            </TileMatrix>
            <TileMatrix>
                <ows:Identifier>8</ows:Identifier>
                <ScaleDenominator>1155583.4197265625</ScaleDenominator>
                <!-- <Resolution>0.00274658203125</Resolution> -->
                <TopLeftCorner>90.0 -180.0</TopLeftCorner>
                <TileWidth>256</TileWidth>
                <TileHeight>256</TileHeight>
                <MatrixWidth>512</MatrixWidth>
                <MatrixHeight>256</MatrixHeight>
            </TileMatrix>
            <TileMatrix>
                <ows:Identifier>9</ows:Identifier>
                <ScaleDenominator>577791.7098632812</ScaleDenominator>
                <!-- <Resolution>0.001373291015625</Resolution> -->
                <TopLeftCorner>90.0 -180.0</TopLeftCorner>
                <TileWidth>256</TileWidth>
                <TileHeight>256</TileHeight>
                <MatrixWidth>1024</MatrixWidth>
                <MatrixHeight>512</MatrixHeight>
            </TileMatrix>
            <TileMatrix>
                <ows:Identifier>10</ows:Identifier>
                <ScaleDenominator>288895.8549316406</ScaleDenominator>
                <!-- <Resolution>6.866455078125E-4</Resolution> -->
                <TopLeftCorner>90.0 -180.0</TopLeftCorner>
                <TileWidth>256</TileWidth>
                <TileHeight>256</TileHeight>
                <MatrixWidth>2048</MatrixWidth>
                <MatrixHeight>1024</MatrixHeight>
            </TileMatrix>
            <TileMatrix>
                <ows:Identifier>11</ows:Identifier>
                <ScaleDenominator>144447.9274658203</ScaleDenominator>
                <!-- <Resolution>3.4332275390625E-4</Resolution> -->
                <TopLeftCorner>90.0 -180.0</TopLeftCorner>
                <TileWidth>256</TileWidth>
                <TileHeight>256</TileHeight>
                <MatrixWidth>4096</MatrixWidth>
                <MatrixHeight>2048</MatrixHeight>
            </TileMatrix>
            <TileMatrix>
                <ows:Identifier>12</ows:Identifier>
                <ScaleDenominator>72223.96373291015</ScaleDenominator>
                <!-- <Resolution>1.71661376953125E-4</Resolution> -->
                <TopLeftCorner>90.0 -180.0</TopLeftCorner>
                <TileWidth>256</TileWidth>
                <TileHeight>256</TileHeight>
                <MatrixWidth>8192</MatrixWidth>
                <MatrixHeight>4096</MatrixHeight>
            </TileMatrix>
            <TileMatrix>
                <ows:Identifier>13</ows:Identifier>
                <ScaleDenominator>36111.98186645508</ScaleDenominator>
                <!-- <Resolution>8.58306884765625E-5</Resolution> -->
                <TopLeftCorner>90.0 -180.0</TopLeftCorner>
                <TileWidth>256</TileWidth>
                <TileHeight>256</TileHeight>
                <MatrixWidth>16384</MatrixWidth>
                <MatrixHeight>8192</MatrixHeight>
            </TileMatrix>
            <TileMatrix>
                <ows:Identifier>14</ows:Identifier>
                <ScaleDenominator>18055.99093322754</ScaleDenominator>
                <!-- <Resolution>4.291534423828125E-5</Resolution> -->
                <TopLeftCorner>90.0 -180.0</TopLeftCorner>
                <TileWidth>256</TileWidth>
                <TileHeight>256</TileHeight>
                <MatrixWidth>32768</MatrixWidth>
                <MatrixHeight>16384</MatrixHeight>
            </TileMatrix>
            <TileMatrix>
                <ows:Identifier>15</ows:Identifier>
                <ScaleDenominator>9027.99546661377</ScaleDenominator>
                <!-- <Resolution>2.1457672119140625E-5</Resolution> -->
                <TopLeftCorner>90.0 -180.0</TopLeftCorner>
                <TileWidth>256</TileWidth>
                <TileHeight>256</TileHeight>
                <MatrixWidth>65536</MatrixWidth>
                <MatrixHeight>32768</MatrixHeight>
            </TileMatrix>
            <TileMatrix>
                <ows:Identifier>16</ows:Identifier>
                <ScaleDenominator>4513.997733306885</ScaleDenominator>
                <!-- <Resolution>1.0728836059570312E-5</Resolution> -->
                <TopLeftCorner>90.0 -180.0</TopLeftCorner>
                <TileWidth>256</TileWidth>
                <TileHeight>256</TileHeight>
                <MatrixWidth>131072</MatrixWidth>
                <MatrixHeight>65536</MatrixHeight>
            </TileMatrix>
            <TileMatrix>
                <ows:Identifier>17</ows:Identifier>
                <ScaleDenominator>2256.9988666534423</ScaleDenominator>
                <!-- <Resolution>5.364418029785156E-6</Resolution> -->
                <TopLeftCorner>90.0 -180.0</TopLeftCorner>
                <TileWidth>256</TileWidth>
                <TileHeight>256</TileHeight>
                <MatrixWidth>262144</MatrixWidth>
                <MatrixHeight>131072</MatrixHeight>
            </TileMatrix>
            <TileMatrix>
                <ows:Identifier>18</ows:Identifier>
                <ScaleDenominator>1128.4994333267211</ScaleDenominator>
                <!-- <Resolution>2.682209014892578E-6</Resolution> -->
                <TopLeftCorner>90.0 -180.0</TopLeftCorner>
                <TileWidth>256</TileWidth>
                <TileHeight>256</TileHeight>
                <MatrixWidth>524288</MatrixWidth>
                <MatrixHeight>262144</MatrixHeight>
            </TileMatrix>
            <TileMatrix>
                <ows:Identifier>19</ows:Identifier>
                <ScaleDenominator>564.2497166633606</ScaleDenominator>
                <!-- <Resolution>1.341104507446289E-6</Resolution> -->
                <TopLeftCorner>90.0 -180.0</TopLeftCorner>
                <TileWidth>256</TileWidth>
                <TileHeight>256</TileHeight>
                <MatrixWidth>1048576</MatrixWidth>
                <MatrixHeight>524288</MatrixHeight>
            </TileMatrix>
        </TileMatrixSet>
    </Contents>
</Capabilities>