API usage
Generic Tile
The py3dtiles module provides some classes to fit into the specification:
TileContent with a header TileContentHeader and a body TileContentBody
TileContentHeader represents the metadata of the tile (magic value, version, …)
TileContentBody contains varying semantic and geometric data depending on the the tile’s type
Moreover, a utility class TileContentReader is available to read a tile file as well as a simple command line tool to retrieve basic information about a tile: py3dtiles_info. We also provide a utility to generate a tileset from a list of 3D models in WKB format or stored in a postGIS table.
Point Cloud
Points Tile Format: https://github.com/AnalyticalGraphicsInc/3d-tiles/tree/master/specification/TileFormats/PointCloud
In the current implementation, the Pnts class only contains a FeatureTable (FeatureTableHeader and a FeatureTableBody, which contains features of type Feature).
How to read a .pnts file
>>> from py3dtiles.tileset.content import Pnts
>>> from py3dtiles.tileset.utils import TileContentReader
>>>
>>> filename = 'tests/pointCloudRGB.pnts'
>>>
>>> # read the file
>>> tile_content = TileContentReader.read_file(filename)
>>>
>>> # tile_content is an instance of the TileContent class
>>> tile_content
<py3dtiles.tile_content.TileContent>
>>>
>>> # extract information about the tile_content header
>>> th = tile_content.header
>>> th
<py3dtiles.tile_content.TileContentHeader>
>>> th.magic_value
'pnts'
>>> th.tile_byte_length
15176
>>>
>>> # extract the feature table
>>> ft = tile_content.body.feature_table
>>> ft
<py3dtiles.feature_table.FeatureTable
>>>
>>> # display feature table header
>>> ft.header.to_json()
{'RTC_CENTER': [1215012.8828876738, -4736313.051199594, 4081605.22126042],
'RGB': {'byteOffset': 12000}, 'POINTS_LENGTH': 1000, 'POSITION': {'byteOffset': 0}}
>>>
>>> # extract positions and colors of the first point
>>> f = ft.feature(0)
>>> f
<py3dtiles.feature_table.Feature>
>>> f.positions
{'Y': 4.4896851, 'X': 2.19396, 'Z': -0.17107764}
>>> f.colors
{'Green': 243, 'Red': 44, 'Blue': 209}
How to write a .pnts file
To write a Point Cloud file, you have to build a numpy array with the corresponding data type.
>>> import numpy as np
>>>
>>> from py3dtiles.tileset.content import Pnts
>>> from py3dtiles.tileset.feature_table import Feature
>>>
>>> # create the numpy dtype for positions with 32-bit floating point numbers
>>> dt = np.dtype([('X', '<f4'), ('Y', '<f4'), ('Z', '<f4')])
>>>
>>> # create a position array
>>> position = np.array([(4.489, 2.19, -0.17)], dtype=dt)
>>>
>>> # create a new feature from a uint8 numpy array
>>> f = Feature.from_array(dt, position.view('uint8'))
>>> f
<py3dtiles.feature_table.Feature>
>>> f.positions
{'Y': 2.19, 'X': 4.489, 'Z': -0.17}
>>>
>>> # create a tile directly from our feature. None is for "no colors".
>>> t = Pnts.from_features(dt, None, [f])
>>>
>>> # the tile is complete
>>> t.body.feature_table.header.to_json()
{'POINTS_LENGTH': 1, 'POSITION': {'byteOffset': 0}}
>>>
>>> # to save our tile as a .pnts file
>>> t.save_as("mypoints.pnts")
Batched 3D Model
Batched 3D Model Tile Format: https://github.com/AnalyticalGraphicsInc/3d-tiles/tree/master/TileFormats/Batched3DModel
How to read a .b3dm file
>>> from py3dtiles.tileset.content import B3dm
>>> from py3dtiles.tileset.utils import TileContentReader
>>>
>>> filename = 'tests/dragon_low.b3dm'
>>>
>>> # read the file
>>> tile_content = TileContentReader.read_file(filename)
>>>
>>> # tile_content is an instance of the TileContent class
>>> tile_content
<py3dtiles.tile_content.TileContent>
>>>
>>> # extract information about the tile header
>>> th = tile_content.header
>>> th
<py3dtiles.b3dm.B3dmHeader>
>>> th.magic_value
'b3dm'
>>> th.tile_byte_length
47246
>>>
>>> # extract the glTF
>>> gltf = tile_content.body.glTF
>>> gltf
<py3dtiles.gltf.GlTF>
>>>
>>> # display gltf header's asset field
>>> gltf.header['asset']
{'premultipliedAlpha': True, 'profile': {'version': '1.0', 'api': 'WebGL'}, 'version': '1.0', 'generator': 'OBJ2GLTF'}
How to write a .b3dm file
To write a Batched 3D Model file, you have to import the geometry from a wkb file containing polyhedralsurfaces or multipolygons.
>>> import numpy as np
>>>
>>> from py3dtiles.tilers.b3dm.wkb_utils import TriangleSoup
>>> from py3dtiles.tileset.content import B3dm, GlTF
>>>
>>> # load a wkb file
>>> wkb = open('tests/building.wkb', 'rb').read()
>>>
>>> # define the geometry's bouding box
>>> box = [[-8.75, -7.36, -2.05], [8.80, 7.30, 2.05]]
>>>
>>> # define the geometry's world transformation
>>> transform = np.array([
... [1, 0, 0, 1842015.125],
... [0, 1, 0, 5177109.25],
... [0, 0, 1, 247.87364196777344],
... [0, 0, 0, 1]], dtype=float)
>>> transform = transform.flatten('F')
>>>
>>> # use the TriangleSoup helper class to transform the wkb into arrays
>>> # of points and normals
>>> ts = TriangleSoup.from_wkb_multipolygon(wkb)
>>> positions = ts.getPositionArray()
>>> normals = ts.getNormalArray()
>>> # generate the glTF part from the binary arrays.
>>> # notice that from_binary_arrays accepts array of geometries
>>> # for batching purposes.
>>> geometry = { 'position': positions, 'normal': normals, 'bbox': box }
>>> gltf = GlTF.from_binary_arrays([geometry], transform)
>>>
>>> # create a b3dm tile_content directly from the glTF.
>>> t = B3dm.from_glTF(gltf)
>>>
>>> # to save our tile as a .b3dm file
>>> t.save_as("mymodel.b3dm")