hub/venv/lib/python3.7/site-packages/trimesh/exchange/export.py

217 lines
6.1 KiB
Python
Raw Normal View History

import os
import json
import numpy as np
from ..constants import log
from .. import util
from .. import resolvers
from .urdf import export_urdf # NOQA
from .gltf import export_glb, export_gltf
from .obj import export_obj
from .off import _off_exporters
from .stl import export_stl, export_stl_ascii
from .ply import _ply_exporters
from .dae import _collada_exporters
from .xyz import _xyz_exporters
def export_mesh(mesh, file_obj, file_type=None, resolver=None, **kwargs):
"""
Export a Trimesh object to a file- like object, or to a filename
Parameters
-----------
file_obj : str, file-like
Where should mesh be exported to
file_type : str or None
Represents file type (eg: 'stl')
resolver : None or trimesh.resolvers.Resolver
Resolver to write referenced assets to
Returns
----------
exported : bytes or str
Result of exporter
"""
# if we opened a file object in this function
# we will want to close it when we're done
was_opened = False
if util.is_pathlib(file_obj):
# handle `pathlib` objects by converting to string
file_obj = str(file_obj.absolute())
if util.is_string(file_obj):
if file_type is None:
# get file type from file name
file_type = (str(file_obj).split('.')[-1]).lower()
if file_type in _mesh_exporters:
was_opened = True
# get full path of file before opening
file_path = os.path.abspath(os.path.expanduser(file_obj))
file_obj = open(file_path, 'wb')
if resolver is None:
# create a resolver which can write files to the path
resolver = resolvers.FilePathResolver(file_path)
# make sure file type is lower case
file_type = str(file_type).lower()
if not (file_type in _mesh_exporters):
raise ValueError('%s exporter not available!', file_type)
if isinstance(mesh, (list, tuple, set, np.ndarray)):
faces = 0
for m in mesh:
faces += len(m.faces)
log.debug('Exporting %d meshes with a total of %d faces as %s',
len(mesh), faces, file_type.upper())
elif hasattr(mesh, 'faces'):
# if the mesh has faces log the number
log.debug('Exporting %d faces as %s', len(mesh.faces),
file_type.upper())
# OBJ files save assets everywhere
if file_type == 'obj':
kwargs['resolver'] = resolver
export = _mesh_exporters[file_type](mesh, **kwargs)
if hasattr(file_obj, 'write'):
result = util.write_encoded(file_obj, export)
else:
result = export
if was_opened:
file_obj.close()
return result
def export_dict64(mesh):
"""
Export a mesh as a dictionary, with data encoded
to base64.
"""
return export_dict(mesh, encoding='base64')
def export_dict(mesh, encoding=None):
"""
Export a mesh to a dict
Parameters
------------
mesh : trimesh.Trimesh
Mesh to be exported
encoding : str or None
Such as 'base64'
Returns
-------------
export : dict
Data stored in dict
"""
def encode(item, dtype=None):
if encoding is None:
return item.tolist()
else:
if dtype is None:
dtype = item.dtype
return util.array_to_encoded(item, dtype=dtype, encoding=encoding)
# metadata keys we explicitly want to preserve
# sometimes there are giant datastructures we don't
# care about in metadata which causes exports to be
# extremely slow, so skip all but known good keys
meta_keys = ['units', 'file_name', 'file_path']
metadata = {k: v for k, v in mesh.metadata.items() if k in meta_keys}
export = {
'metadata': metadata,
'faces': encode(mesh.faces),
'face_normals': encode(mesh.face_normals),
'vertices': encode(mesh.vertices)
}
if mesh.visual.kind == 'face':
export['face_colors'] = encode(mesh.visual.face_colors)
elif mesh.visual.kind == 'vertex':
export['vertex_colors'] = encode(mesh.visual.vertex_colors)
return export
def scene_to_dict(scene, use_base64=False):
"""
Export a Scene object as a dict.
Parameters
-------------
scene : trimesh.Scene
Scene object to be exported
Returns
-------------
as_dict : dict
Scene as a dict
"""
# save some basic data about the scene
export = {'graph': scene.graph.to_edgelist(),
'geometry': {},
'scene_cache': {'bounds': scene.bounds.tolist(),
'extents': scene.extents.tolist(),
'centroid': scene.centroid.tolist(),
'scale': scene.scale}}
# encode arrays with base64 or not
if use_base64:
file_type = 'dict64'
else:
file_type = 'dict'
# if the mesh has an export method use it
# otherwise put the mesh itself into the export object
for geometry_name, geometry in scene.geometry.items():
if hasattr(geometry, 'export'):
# export the data
exported = {'data': geometry.export(file_type=file_type),
'file_type': file_type}
export['geometry'][geometry_name] = exported
else:
# case where mesh object doesn't have exporter
# might be that someone replaced the mesh with a URL
export['geometry'][geometry_name] = geometry
return export
def export_json(mesh):
blob = export_dict(mesh, encoding='base64')
export = json.dumps(blob)
return export
def export_msgpack(mesh):
import msgpack
blob = export_dict(mesh, encoding='binary')
export = msgpack.dumps(blob)
return export
_mesh_exporters = {
'stl': export_stl,
'dict': export_dict,
'json': export_json,
'glb': export_glb,
'obj': export_obj,
'gltf': export_gltf,
'dict64': export_dict64,
'msgpack': export_msgpack,
'stl_ascii': export_stl_ascii
}
_mesh_exporters.update(_ply_exporters)
_mesh_exporters.update(_off_exporters)
_mesh_exporters.update(_collada_exporters)
_mesh_exporters.update(_xyz_exporters)