Skip to content

Instantly share code, notes, and snippets.

@maxcollombin
Last active February 26, 2024 07:19
Show Gist options
  • Save maxcollombin/817ff444e5d2ca11da04ab00774a8315 to your computer and use it in GitHub Desktop.
Save maxcollombin/817ff444e5d2ca11da04ab00774a8315 to your computer and use it in GitHub Desktop.
This script generates a JSON and XML representation of a an OGC 2D tile matrix set definition for use with geographical data services.
"""
Swiss Tile Matrix Set Generation Script
This script generates a JSON and XML representation of a an OGC 2D tile matrix set definition
for use with geographical data services.
Author: [Maxime Collombin]
Date: [14/08/2023]
"""
# -*- coding: utf-8 -*-
import json
import pandas as pd
import xml.etree.ElementTree as ET
from lxml import etree
from xml.dom import minidom
cell_sizes = [4000, 2000, 1000, 500, 250, 100, 50, 20, 10, 5, 2.5, 1, 0.5, 0.25, 0.1, 0.05]
# cell_sizes = [4000, 3750, 3500, 3250, 3000, 2750, 2500, 2250, 2000, 1750, 1500, 1250, 1000, 750, 650, 500, 250, 100, 50, 20, 10, 5, 2.5, 2, 1.5, 1, 0.5, 0.25, 0.1, 0.05]
tile_width = 256
tile_height = 256
bbox = [2419995.7488073637, 1030006.663199476, 2900009.727428728, 1350004.292478851]
point_of_origin = [bbox[0], bbox[3]]
scale_denominator = [cell_size / (0.28 * 10**-3) for cell_size in cell_sizes]
matrix_width = [max(1, int(round((bbox[2] - bbox[0]) / (cell_size * tile_width), 0))) for cell_size in cell_sizes]
matrix_height = [max(1, int(round((bbox[3] - bbox[1]) / (cell_size * tile_height), 0))) for cell_size in cell_sizes]
tms_data = {
'ScaleDenominator': scale_denominator,
'CellSize': cell_sizes,
'MatrixWidth': matrix_width,
'MatrixHeight': matrix_height
}
tms = pd.DataFrame(tms_data)
tms['tmsc:Identifier'] = tms.index
tms['CornerOfOrigin'] = 'topLeft'
tms['PointOfOrigin'] = str(point_of_origin)
tms['PointOfOrigin'] = tms['PointOfOrigin'].str.replace('[','').str.replace(']','').str.split(',').apply(lambda x: [float(i) for i in x])
tms['TileWidth'] = tile_width
tms['TileHeight'] = tile_height
tms.loc[0, ['MatrixWidth', 'MatrixHeight']] = 1
tms_xml = tms.copy()
tms_json = tms_xml.copy()
column_name_mapping = {
'tmsc:Identifier': 'id',
'ScaleDenominator': 'scaleDenominator',
'CellSize': 'cellSize',
'CornerOfOrigin': 'cornerOfOrigin',
'PointOfOrigin': 'pointOfOrigin',
'TileWidth': 'tileWidth',
'TileHeight': 'tileHeight',
'MatrixWidth': 'matrixWidth',
'MatrixHeight': 'matrixHeight'
}
tms_json.rename(columns=column_name_mapping, inplace=True)
header_xml = {
'tmsc:Title': 'Switzerland 2D tile matrix set definition',
'tmsc:Identifier': 'SwissLV95CellSizes',
'uri': 'http://www.opengis.net/def/tilematrixset/OGC/1.0/SwissLV95CellSizes',
'tmsc:CRS': 'http://www.opengis.net/def/crs/EPSG/0/2056',
'OrderedAxes': ['E', 'N'],
'tileMatrices': tms_xml.to_dict('records')
}
header_json = {
'title': 'Switzerland 2D tile matrix set definition',
'id': 'SwissLV95CellSizes',
'uri': 'http://www.opengis.net/def/tilematrixset/OGC/1.0/SwissLV95CellSizes',
'crs': 'http://www.opengis.net/def/crs/EPSG/0/2056',
'orderedAxes': ['E', 'N'],
'tileMatrices': tms_json.to_dict('records')
}
with open('SwissLV95CellSizes.json', 'w') as outfile:
json.dump(header_json, outfile, indent=4, sort_keys=False)
root = ET.Element('TileMatrixSet')
root.set('id', 'SwissLV95CellSizes')
root.set('xmlns', 'http://www.opengis.net/tms/2.0')
root.set('xmlns:tmsc', 'http://www.opengis.net/tms/2.0/common')
root.set('xmlns:xsi', 'http://www.w3.org/2001/XMLSchema-instance')
root.set('xsi:schemaLocation', 'http://www.opengis.net/tms/2.0 https://schemas.opengis.net/tms/2.0/xml/tilematrixset.xsd')
for key, value in header_xml.items():
if key == 'tileMatrices':
for item in value:
tile_matrix_element = ET.SubElement(root, 'TileMatrix')
for sub_key, sub_value in item.items():
sub_key_element = ET.SubElement(tile_matrix_element, sub_key)
if sub_key == 'PointOfOrigin':
sub_key_element.text = ' '.join(map(str, sub_value)) # Convert list to string with space separator
else:
sub_key_element.text = str(sub_value)
elif key == 'tmsc:CRS':
crs_element = ET.SubElement(root, key)
uri_element = ET.SubElement(crs_element, 'tmsc:URI')
uri_element.text = str(value)
else:
key_element = ET.SubElement(root, key)
key_element.text = str(value)
xml_string = ET.tostring(root, encoding='utf-8')
pretty_xml_string = minidom.parseString(xml_string).toprettyxml(indent=' ')
with open('SwissLV95CellSizes.xml', 'w') as xml_outfile:
xml_outfile.write(pretty_xml_string)
@maxcollombin
Copy link
Author

2do:

Adapt the script to have convenient naming in both json and xml files.
The CRS in the xml root should also be:

  <tmsc:CRS>
    <tmsc:URI>http://www.opengis.net/def/crs/EPSG/0/2056</tmsc:URI>
 </tmsc:CRS>

and not

<tmsc:CRS>http://www.opengis.net/def/crs/EPSG/0/2056</tmsc:CRS>

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment