mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-19 22:50:21 +00:00
Wire up serializer plug-ins in python
This commit is contained in:
@@ -20,6 +20,7 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from collections.abc import Generator, Iterable
|
from collections.abc import Generator, Iterable
|
||||||
|
from os import PathLike, fspath
|
||||||
from typing import TYPE_CHECKING, Any, Literal, Optional, TypeVar, Union, cast, overload
|
from typing import TYPE_CHECKING, Any, Literal, Optional, TypeVar, Union, cast, overload
|
||||||
|
|
||||||
from .. import ifcopenshell_wrapper, open
|
from .. import ifcopenshell_wrapper, open
|
||||||
@@ -630,69 +631,84 @@ def make_shape_function(fn):
|
|||||||
# tesselate = make_shape_function(ifcopenshell_wrapper.tesselate)
|
# tesselate = make_shape_function(ifcopenshell_wrapper.tesselate)
|
||||||
|
|
||||||
|
|
||||||
def transform_string(v: Union[str, serializers.buffer]) -> serializers.buffer:
|
class _serializer_factory:
|
||||||
if isinstance(v, str):
|
def __init__(self, name: str, extension: str):
|
||||||
return ifcopenshell_wrapper.buffer(v)
|
self.name = name
|
||||||
return v
|
self.extension = extension
|
||||||
|
self.__name__ = name
|
||||||
|
|
||||||
|
def __call__(self, out_filename: Union[str, PathLike[str]], *args: Any) -> ifcopenshell_wrapper.GeometrySerializer:
|
||||||
|
if self.name == "obj" and len(args) == 3:
|
||||||
|
output_filename = args[0]
|
||||||
|
output_temp_filename = out_filename
|
||||||
|
geometry_settings, serializer_settings = args[1], args[2]
|
||||||
|
elif len(args) == 2:
|
||||||
|
output_filename = out_filename
|
||||||
|
output_temp_filename = out_filename
|
||||||
|
geometry_settings, serializer_settings = args
|
||||||
|
else:
|
||||||
|
obj_signature = " or (out_filename, mtl_filename, geometry_settings, serializer_settings)"
|
||||||
|
raise TypeError(
|
||||||
|
f"serializers.{self.name}() expects (out_filename, geometry_settings, serializer_settings)"
|
||||||
|
+ (obj_signature if self.name == "obj" else "")
|
||||||
|
)
|
||||||
|
|
||||||
|
output_filename = self._path(output_filename)
|
||||||
|
output_temp_filename = self._path(output_temp_filename)
|
||||||
|
|
||||||
|
return ifcopenshell_wrapper.create_geometry_serializer(
|
||||||
|
self.extension, output_filename, output_temp_filename, geometry_settings, serializer_settings
|
||||||
|
)
|
||||||
|
|
||||||
|
def _path(self, value: Union[str, PathLike[str]]) -> str:
|
||||||
|
try:
|
||||||
|
path = fspath(value)
|
||||||
|
except TypeError:
|
||||||
|
raise TypeError(f"serializers.{self.name}() requires a filesystem path") from None
|
||||||
|
if not isinstance(path, str):
|
||||||
|
raise TypeError(f"serializers.{self.name}() requires a text filesystem path")
|
||||||
|
return path
|
||||||
|
|
||||||
|
|
||||||
class serializers:
|
class _serializers_meta(type):
|
||||||
# Python does not have automatic casts. The C++ serializers accept a stream_or_filename
|
_extensions = {
|
||||||
# which in C++ can be automatically constructed from a filename string. In Python we
|
"obj": "obj",
|
||||||
# have to implement this cast/construction explicitly by transform_string.
|
"svg": "svg",
|
||||||
@staticmethod
|
"ttl": "ttl",
|
||||||
def obj(
|
"gltf": "glb",
|
||||||
out_filename: Union[str, serializers.buffer],
|
"glb": "glb",
|
||||||
mtl_filename: Union[str, serializers.buffer],
|
"hdf": "h5",
|
||||||
geometry_settings: settings,
|
"hdf5": "h5",
|
||||||
settings: serializer_settings,
|
"h5": "h5",
|
||||||
) -> ifcopenshell_wrapper.WaveFrontOBJSerializer:
|
"collada": "dae",
|
||||||
out_filename = transform_string(out_filename)
|
"dae": "dae",
|
||||||
mtl_filename = transform_string(mtl_filename)
|
"stp": "stp",
|
||||||
return ifcopenshell_wrapper.WaveFrontOBJSerializer(out_filename, mtl_filename, geometry_settings, settings)
|
"step": "stp",
|
||||||
|
"igs": "igs",
|
||||||
|
"iges": "igs",
|
||||||
|
"usd": "usd",
|
||||||
|
"usda": "usd",
|
||||||
|
"usdc": "usd",
|
||||||
|
}
|
||||||
|
|
||||||
@staticmethod
|
def __getattr__(cls, name: str) -> _serializer_factory:
|
||||||
def svg(
|
extension = cls._extensions.get(name)
|
||||||
out_filename: Union[str, serializers.buffer], geometry_settings: settings, settings: serializer_settings
|
if extension is None:
|
||||||
) -> ifcopenshell_wrapper.SvgSerializer:
|
raise AttributeError(f"type object 'serializers' has no attribute '{name}'")
|
||||||
out_filename = transform_string(out_filename)
|
factory = _serializer_factory(name, extension)
|
||||||
return ifcopenshell_wrapper.SvgSerializer(out_filename, geometry_settings, settings)
|
setattr(cls, name, factory)
|
||||||
|
return factory
|
||||||
|
|
||||||
# Hdf- Xml- and glTF- serializers don't support writing to a buffer, only to filename
|
def __dir__(cls) -> list[str]:
|
||||||
# so no wrap_buffer_creation() for these serializers
|
return sorted(set(super().__dir__()) | set(cls._extensions))
|
||||||
# xml = ifcopenshell_wrapper.XmlSerializer
|
|
||||||
|
|
||||||
|
class serializers(metaclass=_serializers_meta):
|
||||||
buffer = ifcopenshell_wrapper.buffer
|
buffer = ifcopenshell_wrapper.buffer
|
||||||
# gltf, hdf5, collada and json availability depend on IfcOpenShell configuration settings
|
|
||||||
try:
|
|
||||||
gltf = ifcopenshell_wrapper.GltfSerializer
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
try:
|
|
||||||
hdf5 = ifcopenshell_wrapper.HdfSerializer
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
try:
|
|
||||||
collada = ifcopenshell_wrapper.ColladaSerializer
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
try:
|
|
||||||
json = ifcopenshell_wrapper.JsonSerializer
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
# ttl is always available since it doesn't depend on any C++ libraries,
|
|
||||||
# just people might be using an outdated binary
|
|
||||||
if hasattr(ifcopenshell_wrapper, "TtlWktSerializer"):
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def ttl(
|
|
||||||
out_filename: Union[str, serializers.buffer], geometry_settings: settings, settings: serializer_settings
|
|
||||||
) -> ifcopenshell_wrapper.SvgSerializer:
|
|
||||||
out_filename = transform_string(out_filename)
|
|
||||||
return ifcopenshell_wrapper.TtlWktSerializer(out_filename, geometry_settings, settings)
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def guess_from_extension(cls, filepath: str):
|
def guess_from_extension(cls, filepath: str):
|
||||||
ext = filepath.split(".")[-1]
|
ext = filepath.rsplit(".", 1)[-1].lower()
|
||||||
mapping = {
|
mapping = {
|
||||||
"glb": "gltf",
|
"glb": "gltf",
|
||||||
"hdf": "hdf5",
|
"hdf": "hdf5",
|
||||||
@@ -701,8 +717,14 @@ class serializers:
|
|||||||
"obj": "obj",
|
"obj": "obj",
|
||||||
"svg": "svg",
|
"svg": "svg",
|
||||||
"ttl": "ttl",
|
"ttl": "ttl",
|
||||||
"xml": "xml",
|
|
||||||
"dae": "collada",
|
"dae": "collada",
|
||||||
|
"stp": "stp",
|
||||||
|
"step": "step",
|
||||||
|
"igs": "igs",
|
||||||
|
"iges": "iges",
|
||||||
|
"usd": "usd",
|
||||||
|
"usda": "usda",
|
||||||
|
"usdc": "usdc",
|
||||||
}
|
}
|
||||||
serializer_name = mapping.get(ext)
|
serializer_name = mapping.get(ext)
|
||||||
if not serializer_name:
|
if not serializer_name:
|
||||||
|
|||||||
@@ -1710,6 +1710,13 @@ def construct_iterator_with_include_exclude_id(geometry_library, settings, file,
|
|||||||
def convert_loop_to_function_item(loop): ...
|
def convert_loop_to_function_item(loop): ...
|
||||||
def create_box(*args): ...
|
def create_box(*args): ...
|
||||||
def create_epeck(*args): ...
|
def create_epeck(*args): ...
|
||||||
|
def create_geometry_serializer(
|
||||||
|
extension: str,
|
||||||
|
output_filename: str,
|
||||||
|
output_temp_filename: str,
|
||||||
|
geometry_settings: Settings,
|
||||||
|
serializer_settings: SerializerSettings,
|
||||||
|
) -> GeometrySerializer: ...
|
||||||
def create_shape(*args): ...
|
def create_shape(*args): ...
|
||||||
def flatten(deep): ...
|
def flatten(deep): ...
|
||||||
def get_feature(x): ...
|
def get_feature(x): ...
|
||||||
|
|||||||
@@ -634,17 +634,34 @@ struct ShapeRTTI : public boost::static_visitor<PyObject*>
|
|||||||
$result = std::visit(ShapeRTTI(), (std::variant<IfcGeom::Element*, IfcGeom::Representation::Representation*, IfcGeom::Transformation*>) $1);
|
$result = std::visit(ShapeRTTI(), (std::variant<IfcGeom::Element*, IfcGeom::Representation::Representation*, IfcGeom::Transformation*>) $1);
|
||||||
}
|
}
|
||||||
|
|
||||||
%newobject construct_iterator;
|
%newobject construct_iterator;
|
||||||
%newobject construct_iterator_with_include_exclude;
|
%newobject construct_iterator_with_include_exclude;
|
||||||
%newobject construct_iterator_with_include_exclude_globalid;
|
%newobject construct_iterator_with_include_exclude_globalid;
|
||||||
%newobject construct_iterator_with_include_exclude_id;
|
%newobject construct_iterator_with_include_exclude_id;
|
||||||
|
%newobject create_geometry_serializer;
|
||||||
// I couldn't get the vector<string> typemap to be applied when %extending Iterator constructor.
|
|
||||||
// anyway it does not matter as SWIG generates C code without actual constructors
|
// I couldn't get the vector<string> typemap to be applied when %extending Iterator constructor.
|
||||||
%inline %{
|
// anyway it does not matter as SWIG generates C code without actual constructors
|
||||||
IfcGeom::Iterator* construct_iterator(const std::string& geometry_library, ifcopenshell::geometry::Settings settings, ifcopenshell::file* file, int num_threads) {
|
%inline %{
|
||||||
return new IfcGeom::Iterator(ifcopenshell::geometry::kernels::construct(file, geometry_library, settings), settings, file, num_threads);
|
GeometrySerializer* create_geometry_serializer(
|
||||||
}
|
const std::string& extension,
|
||||||
|
const std::string& output_filename,
|
||||||
|
const std::string& output_temp_filename,
|
||||||
|
ifcopenshell::geometry::Settings& geometry_settings,
|
||||||
|
const ifcopenshell::geometry::SerializerSettings& serializer_settings
|
||||||
|
) {
|
||||||
|
return new PythonPluginGeometrySerializer(
|
||||||
|
extension,
|
||||||
|
output_filename,
|
||||||
|
output_temp_filename,
|
||||||
|
geometry_settings,
|
||||||
|
serializer_settings
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
IfcGeom::Iterator* construct_iterator(const std::string& geometry_library, ifcopenshell::geometry::Settings settings, ifcopenshell::file* file, int num_threads) {
|
||||||
|
return new IfcGeom::Iterator(ifcopenshell::geometry::kernels::construct(file, geometry_library, settings), settings, file, num_threads);
|
||||||
|
}
|
||||||
|
|
||||||
IfcGeom::Iterator* construct_iterator_with_include_exclude(const std::string& geometry_library, ifcopenshell::geometry::Settings settings, ifcopenshell::file* file, std::vector<std::string> elems, bool include, int num_threads) {
|
IfcGeom::Iterator* construct_iterator_with_include_exclude(const std::string& geometry_library, ifcopenshell::geometry::Settings settings, ifcopenshell::file* file, std::vector<std::string> elems, bool include, int num_threads) {
|
||||||
std::set<std::string> elems_set(elems.begin(), elems.end());
|
std::set<std::string> elems_set(elems.begin(), elems.end());
|
||||||
|
|||||||
Reference in New Issue
Block a user