Tutorial

Introduction

This tutorial shows how to use the quantized mesh tile module. This format is designed to work exclusively with the TMS (Tile Map Service) tiling scheme and is optimized to display TIN (Triangulated irregular network) data on the web.

The only available client able to read and display this format is Cesium.

This module has been developed based on the specifications of the format described here.

Therefore, if you’ve planned on creating your own terrain server, please make sure you follow all the instructions provided in the specifications of the format. You may also need to define a layer.json metadata file at the root of your terrain server which seems to be a derivative of Mapbox tilejson-spec. Make sure you get it right. ;)

Create a terrain tile

The encoding module can determine the extent of a tile based on the geometries it receives as arguments. Nevertheless, this can only work if the tile has at least 1 triangle on all of its 4 edges. As a result, it is advised to always provide the bounds of the tile.

So first determine the extent of the tile.

>>> from quantized_mesh_tile.global_geodetic import GlobalGeodetic
>>> geodetic = GlobalGeodetic(True)
>>> [z, x, y] = [9, 533, 383]
>>> [west, south, east, north] = bounds = geodetic.TileBounds(x, y, z)

Now that we have the extent, let’s assume you generated a mesh using your favorite meshing engine and ended up with the following geometries.

>>> geometries = [
        'POLYGON Z ((7.3828125 44.6484375 303.3, ' +
                    '7.3828125 45.0 320.2, ' +
                    '7.5585937 44.82421875 310.2, ' +
                    '7.3828125 44.6484375 303.3))',
        'POLYGON Z ((7.3828125 44.6484375 303.3, ' +
                    '7.734375 44.6484375 350.3, ' +
                    '7.5585937 44.82421875 310.2, ' +
                    '7.3828125 44.6484375 303.3))',
        'POLYGON Z ((7.734375 44.6484375 350.3, ' +
                    '7.734375 45.0 330.3, ' +
                    '7.5585937 44.82421875 310.2, ' +
                    '7.734375 44.6484375 350.3))',
        'POLYGON Z ((7.734375 45.0 330.3, ' +
                    '7.5585937 44.82421875 310.2, ' +
                    '7.3828125 45.0 320.2, ' +
                    '7.734375 45.0 330.3))'
    ]

For a full list of input formats for the geometries, please refer to quantized_mesh_tile.terrain.TerrainTile.

>>> from quantized_mesh_tile import encode
>>> tile = encode(geometries, bounds=bounds)
>>> print len(tile.getTrianglesCoordinates())
>>> tile.toFile('%s/%s/%s.terrain' % (z, x, y))

This operation will write a local file representing the terrain tile. If you don’t want to create a physical file but only need its content, you can use:

>>> tile = encode(geometries, bounds=bounds)
>>> content = tile.toBytesIO(gzipped=True)

This operation will create a gzipped compressed string buffer wrapped in a io.BytesIO instance.

If you want to enable lighting effect (experimental):

>>> tile = encode(geometries, bounds=bounds, hasLighting=True)
>>> content = tile.toBytesIO(gzipped=True)

To define a water-mask you can use:

>>> # Water only
>>> watermask = [255]
>>> tile = encode(geometries, bounds=bounds, watermask=watermask)

If you have non-triangular geometries (typically when clipping in an existing mesh), you can also use the option autocorrectGeometries to collapse them into triangles. This option should be used with care to fix punctual meshing mistakes.

>>> geometries = [
        'POLYGON Z ((7.3828125 44.6484375 303.3, ' +
                    '7.3828125 45.0 320.2, ' +
                    '7.5585937 44.82421875 310.2, ' +
                    '7.3828125 44.6484375 303.3))',
        'POLYGON Z ((7.3828125 44.6484375 303.3, ' +
                    '7.734375 44.6484375 350.3, ' +
                    '7.5585937 44.82421875 310.2, ' +
                    '7.3828125 44.6484375 303.3))',
        'POLYGON Z ((7.734375 44.6484375 350.3, ' +
                    '7.734375 45.0 330.3, ' +
                    '7.5585937 44.82421875 310.2, ' +
                    '7.734375 44.6484375 350.3))',
        'POLYGON Z ((7.734375 45.0 330.3, ' +
                    '7.5585937 44.82421875 310.2, ' +
                    '7.3828125 45.0 320.2, ' +
                    '7.55859375 45.0 325.2, ' +
                    '7.734375 45.0 330.3))'
    ]
>>> tile = encode(geometries, bounds=bounds, autocorrectGeometries=True)
>>> print len(tile.getTrianglesCoordinates())

Read a local terrain tile

As the coordinates within a terrain tile are quantized, its values can be only be correctly decoded if we know the exact extent of the tile.

>>> from quantized_mesh_tile.global_geodetic import GlobalGeodetic
>>> geodetic = GlobalGeodetic(True)
>>> [z, x, y] = [9, 533, 383]
>>> [west, south, east, north] = bounds = geodetic.TileBounds(x, y, z)
>>> path = '%s/%s/%s.terrain' % (z, x, y)
>>> tile = decode(path, bounds)
>>> print tile.getTrianglesCoordinates()

Or let’s assume we have a gizpped compressed tile with water-mask extension:

>>> tile = decode(path, bounds, gzipped=True, hasWatermask=True)

Read a remote terrain tile

Using the requests module, here is an example on how to read a remote terrain tile.

The you won’t need to decompress the gzipped tile has this is performed automatically in the requests module.

>>> from io import BytesIO
>>> import requests
>>> from quantized_mesh_tile.terrain import TerrainTile
>>> from quantized_mesh_tile.global_geodetic import GlobalGeodetic
>>> [z, x, y] = [14, 24297, 10735]
>>> geodetic = GlobalGeodetic(True)
>>> [west, south, east, north] = bounds = geodetic.TileBounds(x, y, z)
>>> url = 'http://assets.agi.com/stk-terrain/world/%s/%s/%s.terrain?v=1.16389.0' % (z, x, y)
>>> response = requests.get(url)
>>> content = BytesIO(response.content)
>>> ter = TerrainTile(west=west, south=south, east=east, north=north)
>>> ter.fromBytesIO(content)
>>> print ter.getVerticesCoordinates()