Changelog#
All notable changes to this project will be documented in this file.
v11.0.0 (2025-07-25)#
BREAKING CHANGES#
the parameter
force_universal_mergerofmerger.merge_from_fileshas been removed. The merger automatically select the best strategy now.Any other method than
mergeandmerge_from_filesfrommergerare now private.
Feat#
merger: rework it completely. It should now be more relevant and simpler at the same time
tileset: record which tool and which version generated a tileset
tiler: allow the use of custom tilers and exposes
Convertergltf_utils: support setting extra properties in gltf
bounding_volume_box: add BoundingVolumeBox.from_mins_maxs class method
bounding_volume: add some utility method
Fix#
node: fix some sonarcloud issues
merger: make some method private
tileset: don’t crash when trying to load tiles without content
tiler: make sure each tiler has its own working directory
matrix_manipulation: don’t return garbage when making rotation matrix between 2 parallel vectors
point_tiler: bypass transformation when crs_out and crs_in are the same
convert.py: when using several tilers, make sure we merge the resulting tilesets
convert.py: skip some actions for a tiler when it has not been used
Tiler: rename Tiler.initialization to Tiler.initialize
give tilers a way to tell convert which files they support
merger: supports tilesets when root_tile doesn’t have content
tile: init bounding_volume_box when needed
bounding_volume_box: stop imposing the printoptions in py3dtiles
bounding_volume_box: relax a bit the types for construction/operations
use non buggy pyzmq version
Refactor#
pyproject.toml: put the version in a more standard way
node: rename to_tileset to to_tile, as it returns a Tile
base_tiler: rename a parameter
tiler: change the name to str instead of b-string
tiler: rename return_type param to message_type of process_message
tiler_worker: untie it from zmq, make it easier to implement
make it simpler to implement a tiler by removing useless code
bounding_volume_box: remove redundant validity tests
bounding_volume: remove dependency to Tile
v10.0.0 (2025-05-06)#
BREAKING CHANGES#
Generic way to deal with extra fields for point conversion#
We now deal with extra fields in a generic way, so that users can include the fields they want, not only classification and intensity. Additionally, we don’t include intensity and classification by default any more.
Here’s how to migrate:
- convert(file, outfolder=folder)
+ convert(file, outfolder=folder, extra_fields=["intensity", "classification"])
For cli invocations, please use multiple --extra-fields arguments.
Api change for B3dm creation#
The api to create b3dm from primitives has changed:
B3dm.from_primitiveshas been replaced byB3dm.from_meshes. It takes a list ofGltfMeshGltfPrimitivehas been separated betweenGltfMeshandGltfPrimitiveto be more flexible, while keeping the ease of use that has motivated their creationin turn, the API of
gltf_utilshas also changed to adapt these modifications
Other breaking changes#
TileContent.to_hex_strhas been removed
Feat#
support several materials by geometry for b3dm and gltf
add support for python 3.13
las_reader: warn if the files seems to use half of the RGB range
support files with uppercase file extensions
support arbitrary fields when converting pointclouds
support converting files with and without color together
support for numpy 2.0
Fix#
wkb_utils: change implicit overflow into an explicit overflow
pyproject.toml: remove useless cython dependencies
windows: use longdouble instead of float128, not supported on windows
points_grid: compile _insert (and _insert_extra_fields) again
reader: make sure we generate fake colors in uint8
reader: remove last occurrences of the unused fraction parameter
Documentation#
We now have a new landing page in the website and a new theme :-)
v9.0.0 (2024-10-18)#
BREAKING CHANGES#
The support for python3.8 is dropped.
Feat#
convert.py: add the possibility to use pyproj’s always_xy parameter from py3dtiles. This is useful if your CRS defines its axis as northing - easting (in this order), but your data uses easting - northing ordering.
Added flag for disabling usage of processpool. Useful in some cloud contexts.
support python3.12
Fix#
dependencies: bump laspy to >= 2.5 to avoid https://github.com/laspy/laspy/pull/273
v8.0.2 (2024-08-01)#
Changes for this release are only about our CI pipeline.
We fixed the bug with the tag name for the docker image: it was v8-0-1 in the previous release instead of v8.0.1.
v8.0.1 (2024-07-24)#
fix#
revert commit 395f294ed2cd38125ed132fdc13289e2870aa6d0 that breaks the process launching on windows
v8.0.0 (2024-07-16)#
BREAKING CHANGE#
The
fractionparameter ofconvert(and the--fractioncli flag) has been removed, because we didn’t actually use it in the codeThe . folder by default is now /data on docker image, please update your mounts accordingly.
We replaced the home-made gltf support by pygltflib. It should be compatible with the previous usage for the most part, except for direct usage of
gltf.py(replace it with direct usage of pygltflib) andB3dm.from_numpy_arrays, which has been replaced byB3dm.from_primitives. We believe this will be vastly easier to use. Under the hood, it generates gltf primitives inside the tile.the
allsection in setup.py has been removed becausepyproject.tomldoesn’t support creating them from all the other sections, please usepip install -e .[postgres,las,ply]instead.TileContent.print_info(), B3dm.print_info() and Pnts.print_info() have been removed and replaced by str methods. By assuming
b3dm_tileis a B3dm tile, one may access to string representations with print(b3dm_tile) or str(b3dm_tile).Tileset.root_urimust now be set after the constructionBoundingVolume: the functionsis_box,is_regionandis_spherefrom this class are removed, useisinstance(BoundingVolumeBox)(or the relevant subclass) instead.
Feat#
the docker image is now also pushed on dockerhub
the home-made gltf support is replaced by pygltflib. a
gltf_utilsmodule has been introduced to provide a higher-level API to pygltflibb3dm: support batchids with pygltflib
b3dm: min/max attributes in gltf accessors
b3dm: support materials & uvs with pygltflib
b3dm: from_gltf also takes a feature table
pnts: display info about batchtable when printing
support intensity in pointcloud conversion, only in uint8 at the moment. Intensity of las files are converted from uint16 to uint8 at the moment.
tile.py: add method to transform coords according to this tile transformation property
convert.py: accept an existing out folders if empty
bounding_volume_box: add classmethod .from_points and .from_list and document a bit
We now have a logo!
tileset: add mechanism to support extensions
base_tiler: create an abstract tiler. This abstract class aims at making the creation of a custom tiler easier.
Fix#
tile.py: write content URI as posix
typing: quantized positions in pnts are uint16, not uint8
export: fix optional import of psycopg2
tile.py: make sure we reshape and flatten in column order
py3dtiles/tileset/content/b3dm.py: sync the tile info after array initialization
buildings.b3dm fixture is outdated
BatchTable: ignore extensions in from_array
point_tiler: set refine mode in the correct place
Tile: don’t raise error if file missing
docker: move the workdir to /data in images
convert.py:
don’t crash on trying to remove non-existent path
fix transmission of worker error messages to main thread
fix(b3dm.py): make node_matrix serializable
Refactor#
convert.py: use our Tile and Tileset classes instead of dicts
tileset.py: remove root_uri from constructor parameters
bounding_volume_box: make sure transform accept only 4x4 matrices
make export.py independant from home-made gltf
print_info is replaced by str properties for each tile_content
convert.py:
remove unused parameter
simplify Process declaration
move tiler point specific code outside of convert.py by using the abstract tiler
move pytest fixtures into tests/conftest.py
Miscellaneous#
for nix users, a shell.nix has been added to the project.
v7.0.0 (2023-12-12)#
Community change: Big news!#
We welcome Lorenzo Marnat (Liris) as a new maintainer! The Liris has contributed a lot to py3dtiles through their fork and the client application py3dtilers and Lorenzo is currently helping getting these improvements merged. This is a very important step forward developing our community and we’re very glad to have him in the team.
As a result, we have made it so that py3dtiles is less tied to Oslandia and more to its own community. We hope to make contributions and implications even easier and open to other entities:
the repository has moved to its own organization: https://gitlab.com/py3dtiles/py3dtiles and the main branch is now
maininstead ofmaster. The existing issues and merge requests has been kept and the branch they point to has been updated. Please update your git remotes, especially because there is no redirection at the git level: we needed to recreate the py3dtiles on oslandia namespace to setup a redirection from the old pages.The main domain is now
https://py3dtiles.org. A redirection has been made, but we still advise everybody to update their bookmarksWe have a
GOVERNANCE.mddocumentation that describes how the community will operate from now on.and we now have a chat room on matrix.org!
BREAKING CHANGE#
FeatureTable*has been renamed toPntsFeatureTable*py3dtiles now requires numpy >= 1.24 to allow python 3.11 support (note: 3.12 support must wait for the next numba release)
Big change in the way we deal with dependencies. With more and more file format supports added, the dependency tree is becoming bigger and bigger. To avoid cluttering client environments with dependencies for formats they don’t need, we are now using the extras_require section for some formats. Here is the list of file formats and the command to use to get the corresponding dependencies:
postgresql support:
pip install py3dtiles[postgres]las/laz support:
pip install py3dtiles[las](note: laz support is still conditioned by the presence of laszip or laz-rs, see installation documentation)ply support:
pip install py3dtiles[ply]
The .[all] sections allows to get all these dependencies. The docker image contains everything.
Csv and xyz support depends on the standard library, therefore they are always included.
Feat#
add support for python 3.11
add featureTable and B3dmFeatureTable classes
upgrade numpy
support for csv files and classification data in the xyz_reader
Fix#
mypy: make type declarations compatible with python3.8
convert.py: ensure the main process waits for all child to finish
align b3dm_feature_table to 8 bytes
Pnts from_file method to ensure TileContent is PNTS
PNTS ft body to_array returns one array
distance.py: remove a numba warning
docker: create it on bullseye to have liblaszip8
Refactor#
convert.py: change self.idle_clients type to set
reorder imports according to our isort config
rename PNTS FeatureTable classes
v6.0.0 (2023-04-04)#
BREAKING CHANGE#
py3dtiles mergenow takes tileset path instead of a folder path.The class
BaseExtensionbecomes an abstract class. Please use one of the subclassesTileContentReaderclass has been removed and its static methods are now plain functions intile_content_reader.py.The
read_filefunction has been renamed toread_binary_tile_contentinstance created with FeatureTableHeader.from_semantic method.the
queueargument is removed from readerrunmethod signatures (these functions do not send messages anymore)The method
syncof thePntsBodyandB3dmBodyhas been moved toTileContentclass. The parameterbodyhas been removed.The
Pnts.from_featuremethod signature has completely changed. Numpy data type isn’t used anymore but aFeatureTableHeaderThe attributes:
B3dm.from_glTFhas been renamed toB3dm.from_gltfB3dmBody.from_glTFhas been renamed toB3dmBody.from_gltfB3dmBody.glTFhas been renamed toB3dmBody.gltf
Few import changes:
Change
from py3dtiles.tileset.tile_content_reader import read_filetofrom py3dtiles.tileset.content import read_fileChange
import py3dtiles.tileset.batch_tabletoimport py3dtiles.tileset.content.batch_tableChange
import py3dtiles.tileset.content.feature_tableinimport py3dtiles.tileset.content.feature_tableThe import of
TileContenthas been changed, now it is :from py3dtiles.tileset.content import TileContent, TileContentBody, TileContentHeader
The type
ThreeDDictBasehas been renamed toRootPropertyDictTypeThe class
Extendablehas been renamed toRootPropertyand :its method
add_extensionhas been deleted, add directly to the attributeextensionsits method
has_extensionshas been deleted, check directly the content of the attributeextensionsits method
get_extensionhas been deleted, retrieve directly the extension with its name in the dict attributeextensionsits method
get_extensionshas been deleted, get directly the attributeextensions
The class
Tilehas been modified:The
get_contentmethod has been renamed toget_or_fetch_content. If thecontentis already loaded or thecontent_uriis absolute,root_urimust be None.The
set_contentmethod has been removed, set directly the attributetile_contentThe
set_content_uriand Tileget_content_urimethods have been removed, set and get directly thecontent_uriattribute.The method
get_childrenhas been renamed toget_all_childrenThe method
get_direct_childrenhas been deleted, use directly the attributechildrento get them. Note: It is highly recommended to still use the method Tile.add_children (and not children.append)The method
has_childrenhas been removed, check directly if the attributechildrenis empty.
The class
TileSethas been modified:The
from_dictrequires a new parameter:root_uri, that is the folder where the tileset is.The method
add_asset_extras()has been deleted, use directly the attributeextra(dict)The classes for tile content have been modified:
The class
TileContentis now an abstract class, useB3dmorPntsclass insteadTo create a
PntsorB3dminstance, you must indicate the header and the body instance in the constructorThe
TileContentTypeclass has been removedThe type attribute of the class
TileContentBodyhas been removedThe class
Featurehas been removedThe
FeatureTableHeader.from_dtypemethod has been replaced byfrom_semanticThe
positions_dtype,colors_dtypeandnormal_dtypeattributes of the classFeatureTableHeaderhas been removed. To get the data type, useSEMANTIC_TYPE_MAP[semantic]with semantic eitherfeature_table_header.positions,feature_table_header.colorsorfeature_table_header.normalThe
FeatureTableBody.positions_arrattribute has been renamed topositionThe
FeatureTableBody.colors_arrattribute has been renamed tocolorsThe
FeatureTableBody.positions_itemsizehas been removedThe
FeatureTableBody.colors_itemsizehas been removedThe
FeatureTableBody.from_featuresmethod has been removed, useFeatureTable.from_featuresinsteadThe
FeatureTableBody.positionsandFeatureTableBody.colorsmethods have been removed, useFeatureTable.get_feature_color_atandFeatureTable.get_feature_position_atinsteadThe
FeatureTable.featuremethod has been renamed toget_feature_atand return tuple instead of Feature instanceThe signature of
FeatureTable.from_featureshas completely changed. Numpy data type isn’t anymore use, but aFeatureTableHeaderinstance created withFeatureTableHeader.from_semantic()method
Feat#
Windows is fully supported
a docker image is now built on each release
Classification data can now be exported in the tileset
Add an universal merger
Load tileset from dictionary with lazy tile content loading
Add methods to remove tilesets and tiles on disk
Add the support of extras and extensions properties for Asset, BoundingVolume, Tile and TileSet
Import and export extensionsUsed and extensionsRequired (TileSet)
tileset.py: Sync root uri of tiles when the tileset is written as json
tileset.py: Add methods
from_fileandget_tile_contentstile.py: The transformation attribute can be set in
__init__()bounding_volume.py: Add new methods as abstractmethod
new Py3dtiles exceptions have been created:
TilerException
ThreeDTileSpecError
PntsSpecError
B3dmSpecError
TilesetSpecError
BoundingVolumeMissingException
Use transformation when sync bounding volume
feature_table.py: Improve the support of pnts feature table
batch_table.py: Allow mix of json and binary data
Create a dedicated type for the export of the feature table header
Add the Batch Table Hierarchy extension
Add get_points method to PntsBody
Add the from_points method in Pnts class
Publish number_of_points_in_tileset on the API
Typing work largely completed
Fix#
api.rst: Correct the examples in the api doc
Change gltf padding to fix b3dm body alignment
las_reader: Correct color_scale calculation
convert.py: Allow
convertto work with thespawnmultiprocess methodReverse the recursivity to prune from leafs to root instead of root to leafs
allow multiple user to convert simultaneously on the same machine
fix a warning about a 0 division that can occur when aabb have a 0-size dimension.
Refactor#
Remove useless llvm dependency
Retrieve crs with laspy instead of pdal and remove the pdal dependency
Rename
read_filefunction toread_binary_tile_contentMove
print_b3dm_infoandprint_pnts_infoin thetile_contentclassesuse tile.content_uri in write_to_directory method
merger.py: use tileset module instead of using custom tools
bounding_volume_box.py: improve the readability of some methods
use fix size numpy data type (
np.uint8instead ofnp.ubytes)explicit re-export module with a better API import style
move all node_process functions in a class to clean/simplify code
move the main node processing loop to
convert.pyfor centralizing message sendingyield node process and send message in the main node processing function
Remove useless try..except blocks
halt_at_depthdefined starting from node name lengthRemove
node_catalogparameter ofinsertand _splitmethods since it is useless.yield node process and send message with yielded values [WIP]
Reader
runmethods now yields tuples of coordinate, color and classification arrays and the message is sent by the Worker objectpnts_writer.py:
runmethod now yields the total amount of nodes and the message is sent by the Worker objecttransform
TileContentclass to abstract class and add typing infotileset/utils.py: The static methods in
TileContentReaderbecome functions in a dedicatedtile_content_reader.pymoduleLowercase all
glTFoccurrencesnode.py: Rename
reminderoccurrences toremainder
v5.0.0 (2023-02-02)#
BREAKING CHANGE#
py3dtiles no longer support python 3.7 (it reaches EOL in june)
The function convert_to_ecef has been removed
Many imports have been changed, please update them accordingly:
from py3dtiles import B3dmbecomesfrom py3dtiles.tileset.content import B3dmfrom py3dtiles import GlTFbecomesfrom py3dtiles.tileset.content import GlTFfrom py3dtiles import Pntsbecomesfrom py3dtiles.tileset.content import Pntsfrom py3dtiles import BatchTablebecomesfrom py3dtiles.tileset.batch_table import BatchTablefrom py3dtiles import BoundingVolumeBoxbecomesfrom py3dtiles.tileset.bounding_volume_box import BoundingVolumeBoxfrom py3dtiles import Extendablebecomesfrom py3dtiles.tileset.extendable import Extendablefrom py3dtiles import Extensionbecomesfrom py3dtiles.tileset.extension import BaseExtensionfrom py3dtiles import Tilebecomesfrom py3dtiles.tileset.tile import Tilefrom py3dtiles import TileContentbecomesfrom py3dtiles.tileset.tile_content import TileContentfrom py3dtiles import TileSetbecomesfrom py3dtiles.tileset.tileset import TileSetfrom py3dtiles import TileContentReaderbecomesfrom py3dtiles.tileset.utils import TileContentReaderfrom py3dtiles import TriangleSoupbecomesfrom py3dtiles.tilers.b3dm.wkb_utils import TriangleSoupfrom py3dtiles import Featurebecomesfrom py3dtiles.tileset.feature_table import Feature
The BoundingVolume class become an abstract class
The way of getting / setting
transformhas changed:The methods
set_transformandget_transformof the classTilehas been removed, and the attributetransformof the classTilehas been renamed from_transformtotransform.Please use the attribute directly.in the same vein, the method
set_transformof the classTilesethas been removedThe method set_from_array from the class BoundingVolumeBox has been removed, use set_from_list instead (with an ArrayLike)
some parameters types have been set to always be a flat numpy array of
np.float64:Tile.transformThe parameter
offsetof the methodBoundingVolumeBox.translateThe parameter
transformof the methodBoundingVolumeBox.transformThe parameter
box_listof the methodBoundingVolumeBox.set_from_listThe parameter
mins_maxsof the methodBoundingVolumeBox.get_box_array_from_mins_maxsThe parameter
pointsof the methodBoundingVolumeBox.get_box_array_from_point
Features#
convert.py: add parameter to ignore CRS mixin in input files
add the import and export of batch table from pnts (only json)
reader/ply_reader.py: support .ply files
typing.py: create the tileset json structure with typing annotations
Fixes#
add and update typing annotations to fix all mypy issues
check magic value as bytes not str
exclude B028 flake8 rule
node.py: delete tile children when the tile root is moved in a sub tileset
Refactor#
remove all asserts in source code
select only used fonctions from transformation file and update the code
LICENSE: remove Mapbox third party license
remove copied earcut code and use mapbox library
change file hierarchy
v4.0.0 (2023-01-09)#
BREAKING CHANGE#
The parameter
srs_inandsrs_outofpy3dtiles.convert.converthave been renamed tocrs_inandcrs_out. Furthermore, their type is no longer int or str butpyproj.CRS. No change has been made to the command-linepy3dtiles convert, but you can use proj4 string in addition to epsg code. To migrate old code, instead of:
from py3dtiles.convert import convert
# ...
convert('without_srs.las', outfolder=tmp_dir, crs_out='4978')
you can do:
from pyproj import CRS
from py3dtiles.convert import convert
# ...
convert('without_srs.las', outfolder=tmp_dir, crs_out=CRS.from_epsg(4978))
SrsInMissingException has been moved from
py3dtiles/utils.pytopy3dtiles/exceptions.py.
Feat#
The main feature of this release is that you can now mix las/laz/xyz files in one invocation of the convert function.
Fix#
shared_node_store.py: fix node removing in cache if already deleted
change srs_in to srs_out to fix refactoring error
avoid duplicate points when the mode is replace
Refactor#
convert: rename the ‘infos’ variable and function to ‘file_info’
convert: use CRS almost everywhere instead of string representing epsg code
exceptions: move all custom exceptions at the same place
convert: use a dictionary to find the correct reader
fix issues find by pre-commit
Chores#
add pre-commit hooks
v3.0.0#
BREAKING#
Some renaming has been done to better follow the 3dtiles specification:
TileHeader->TileContentHeaderTileBody->TileContentBodyThe API of merger.py::merge wasn’t really convenient to use and has now changed. Now the signature is:
def merge(folder: Union[str, Path], overwrite: bool = False, verbose: int = 0) -> None
the argument verbose of the cli interface has changed. To increase the verbosity, the number of -v is counted (-vv will be a verbose of 2).
Boolean options has been changed from
--foo=1to simple flags:--foo. Affected options are--overwriteand--graph.--rgb=nohas been replaced by a--no-rgboption to deactivate it. The default is still to keep color information
Features#
support laz if laszip is installed
windows support (NOTE: testers needed)
Some classes to represent 3Dtiles concepts have been added:
BoundingVolumeBox
TileSet
Tile
uExtension
Fix#
The geometric error of two merged tilesets is now the biggest of the two tileset geometric error divided by the ratio of kept points. We believe this use of GeometricError fits more the spirit of the specification.
node: avoid empty children array in tileset.json
setup.py: fix missing dependency pytest
node: avoid to add empty children array
disable padding if already 8-byte aligned instead of adding 8 new empty bytes
featureTable: add a 8-byte boundary for FeatureTableBody
featureTable: change the boundary from 4 to 8
replace sys.exit(1) in convert by raising an exception
v2.0.0#
This releases completely reworks py3dtiles command line and add new features.
The command line now uses subcommands syntax, in order to expose a single entry point and support multiple commands. The existing commands ‘export_tileset’ and ‘py3dtiles_info’ became ‘py3dtiles export’ and ‘py3dtiles info’.
Changes#
relicensed as Apache 2.0.
minimal python supported is now 3.8
dependencies versions has been updated:
laspy should be at least 2.0
numpy at least 1.20.0
Tile has been renamed to TileContent
Features#
New features were added, the main one being: py3dtiles can be used to convert pointcloud las files to a 3dtiles tileset.
This is the purpose of the ‘py3dtiles convert’ command. It supports multicore processor for faster processing, leveraging pyzmq, and the memory management has been carefully implemented to support virtually unlimited points count.
Other features:
read points from xyz files
Documentation are now published at https://oslandia.gitlab.io/py3dtiles
Fixes#
53580ba Jeremy Gaillard fix: use y-up orientation for glTF objects in export script
65d6f67 Jeremy Gaillard fix: proper bounding box size in export script
3603b00 Augustin Trancart fix: reliably select triangulation projection plane and orientation
fd2105a jailln Fix gltf min and max value