121 lines
3.8 KiB
Python
121 lines
3.8 KiB
Python
import os
|
|
import json
|
|
from io import StringIO
|
|
|
|
import logging
|
|
log = logging.getLogger(__name__)
|
|
|
|
import cadquery
|
|
|
|
from . import Exporter, register_exporter
|
|
from .. import Component, Part, Assembly
|
|
|
|
|
|
@register_exporter('json', Part)
|
|
class ThreejsJSONExporter(Exporter):
|
|
"""
|
|
Export the :class:`Part <cqparts.Part>` to a *three.js JSON v3* file format.
|
|
|
|
=============== ======================
|
|
**Name** ``json``
|
|
**Exports** :class:`Part <cqparts.Part>`
|
|
**Spec** `three.js JSON model format v3 specification <https://github.com/mrdoob/three.js/wiki/JSON-Model-format-3>`_
|
|
=============== ======================
|
|
|
|
For information on how to load in a webpage, look to your WebGL framework
|
|
of choice:
|
|
|
|
* ThreeJS: https://threejs.org/docs/#api/loaders/ObjectLoader
|
|
* A-Frame: https://aframe.io/docs/0.7.0/core/asset-management-system.html#lt-a-asset-item-gt
|
|
|
|
"""
|
|
|
|
def __call__(self, filename="out.json", world=False):
|
|
"""
|
|
Write to file.
|
|
|
|
:param filename: file to write
|
|
:type filename: :class:`str`
|
|
:param world: if True, use world coordinates, otherwise use local
|
|
:type world: :class:`bool`
|
|
"""
|
|
log.debug("exporting: %r", self.obj)
|
|
log.debug(" to: %s", filename)
|
|
with open(filename, 'w') as fh:
|
|
fh.write(self.get_str(world=world))
|
|
|
|
def get_str(self, *args, **kwargs):
|
|
"""
|
|
Get file string.
|
|
|
|
(same arguments as :meth:`get_export_gltf_dict`)
|
|
|
|
:return: JSON string
|
|
:rtype: :class:`str`
|
|
"""
|
|
data = self.get_dict(*args, **kwargs)
|
|
return json.dumps(data)
|
|
|
|
def get_dict(self, world=False):
|
|
"""
|
|
Get the part's geometry as a :class:`dict`
|
|
|
|
:param world: if True, use world coordinates, otherwise use local
|
|
:type world: :class:`bool`
|
|
:return: JSON model format
|
|
:rtype: :class:`dict`
|
|
"""
|
|
data = {}
|
|
with StringIO() as stream:
|
|
obj = self.obj.world_obj if world else self.obj.local_obj
|
|
cadquery.exporters.exportShape(obj, 'TJS', stream)
|
|
stream.seek(0)
|
|
data = json.load(stream)
|
|
|
|
# Change diffuse colour to that in render properties
|
|
data['materials'][0]['colorDiffuse'] = [
|
|
val / 255. for val in self.obj._render.rgb
|
|
]
|
|
data['materials'][0]['transparency'] = self.obj._render.alpha
|
|
|
|
return data
|
|
|
|
|
|
@register_exporter('json', Assembly)
|
|
class ThreejsJSONAssemblyExporter(Exporter):
|
|
"""
|
|
Export an :class:`Assembly` into **multiple** ``json`` files.
|
|
|
|
=============== ======================
|
|
**Name** ``json``
|
|
**Exports** :class:`Assembly`
|
|
**Spec** `three.js JSON model format v3 specification <https://github.com/mrdoob/three.js/wiki/JSON-Model-format-3>`_
|
|
=============== ======================
|
|
|
|
.. warning::
|
|
|
|
The *three.js JSON v3* format does not support multiple models (or, at
|
|
least, not as far as I can tell).
|
|
|
|
So this exporter will create multiple files, one per part.
|
|
|
|
If you're after a more modern WebGL supported export, consider using
|
|
:class:`GLTFExporter <cqparts.codec.GLTFExporter>` instead.
|
|
|
|
"""
|
|
|
|
def __call__(self, filename='out.json', world=False):
|
|
self._write_file(self.obj, filename, world=world)
|
|
|
|
@classmethod
|
|
def _write_file(cls, obj, filename, world=False):
|
|
# recursive method to iterate through children
|
|
if isinstance(obj, Assembly):
|
|
# Object has no geometry, iter through components
|
|
obj.solve()
|
|
for (name, child) in obj.components.items():
|
|
s = os.path.splitext(filename)
|
|
cls._write_file(child, "%s.%s%s" % (s[0], name, s[1]), world=True)
|
|
else:
|
|
ThreejsJSONExporter(obj)(filename, world=world)
|