mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-22 04:21:00 +00:00
geom: expose a reusable kernel object to Python (prototype for #9417)
ifcopenshell.geom.create_shape constructs a geometry kernel, converter and mapping on every call and discards them afterwards. For hybrid kernels the construction alone rescans the plugin directory per component, which #9417 addresses on the C++ side by caching the resolved component ids. This prototypes the alternative aothms suggested in the #9417 review: reuse the constructed kernel itself from Python. The wrapper gains a geometry_kernel class holding the converter (and through it the kernel, mapping and conversion caches) built once per (geometry_library, file, settings) triple, with create_shape(instance[, representation]) delegating to the same helper the free create_shape uses, now split so both paths share one body. Python gains ifcopenshell.geom.kernel(settings, file, geometry_library) mirroring the iterator constructor signature. The binding is fixed at construction: settings are copied the way converter already copies them, and a guard rejects instances from a different file because the mapping is file-bound. On PGSuper_Import_Model.ifc (322 products, single-threaded, arm64 Linux), hybrid-cgal-simple-opencascade drops from 71.97 ms/call with per-call create_shape to 23.35 ms/call through the reused kernel, matching the iterator (22.74 ms/call) without needing the #9417 cache; plain opencascade is unaffected (23.30 vs 22.28 ms/call).
This commit is contained in:
committed by
Thomas Krijnen
parent
e713fdb17e
commit
66bcddc277
@@ -990,10 +990,7 @@ struct shape_rtti : public boost::static_visitor<PyObject*>
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
static std::variant<ifcopenshell::geom::element*, ifcopenshell::geom::representation*, ifcopenshell::geom::transformation*> helper_fn_create_shape(ifcopenshell::logger& logger, const std::string& geometry_library, ifcopenshell::geom::settings& settings, const express::base& instance, const express::base& representation = express::base()) {
|
||||
ifcopenshell::file* file = instance.file();
|
||||
|
||||
ifcopenshell::geom::converter kernel(ifcopenshell::geom::kernels::construct(file, geometry_library, settings, logger), file, settings, logger);
|
||||
static std::variant<ifcopenshell::geom::element*, ifcopenshell::geom::representation*, ifcopenshell::geom::transformation*> helper_fn_create_shape_with_converter(ifcopenshell::geom::converter& kernel, ifcopenshell::geom::settings& settings, const express::base& instance, const express::base& representation) {
|
||||
if (instance.declaration().is("IfcProduct")) {
|
||||
if (representation && !representation.declaration().is("IfcRepresentation")) {
|
||||
throw ifcopenshell::exception("Supplied representation not of type IfcRepresentation");
|
||||
@@ -1069,6 +1066,12 @@ struct shape_rtti : public boost::static_visitor<PyObject*>
|
||||
}
|
||||
return std::variant<ifcopenshell::geom::element*, ifcopenshell::geom::representation*, ifcopenshell::geom::transformation*>();
|
||||
}
|
||||
|
||||
static std::variant<ifcopenshell::geom::element*, ifcopenshell::geom::representation*, ifcopenshell::geom::transformation*> helper_fn_create_shape(ifcopenshell::logger& logger, const std::string& geometry_library, ifcopenshell::geom::settings& settings, const express::base& instance, const express::base& representation = express::base()) {
|
||||
ifcopenshell::file* file = instance.file();
|
||||
ifcopenshell::geom::converter kernel(ifcopenshell::geom::kernels::construct(file, geometry_library, settings, logger), file, settings, logger);
|
||||
return helper_fn_create_shape_with_converter(kernel, settings, instance, representation);
|
||||
}
|
||||
%}
|
||||
|
||||
%typemap(out) ifcopenshell::geom::taxonomy::item::ptr {
|
||||
@@ -1116,6 +1119,37 @@ ifcopenshell::geom::taxonomy::item::ptr try_upcast(PyObject* obj0, swig_type_inf
|
||||
}
|
||||
%}
|
||||
|
||||
%inline %{
|
||||
// Reusable geometry kernel handle bound to a (geometry_library, file,
|
||||
// settings) triple. Constructing it resolves the kernel once and reuses
|
||||
// the converter, mapping and caches for every create_shape call.
|
||||
class geometry_kernel {
|
||||
public:
|
||||
geometry_kernel(const std::string& geometry_library, ifcopenshell::file* file, ifcopenshell::geom::settings& settings, ifcopenshell::logger* logger = nullptr)
|
||||
: file_(file)
|
||||
, settings_(settings)
|
||||
, converter_(ifcopenshell::geom::kernels::construct(file, geometry_library, settings_, ifcopenshell::logger_or_root(logger)), file, settings_, ifcopenshell::logger_or_root(logger))
|
||||
{}
|
||||
|
||||
std::variant<ifcopenshell::geom::element*, ifcopenshell::geom::representation*, ifcopenshell::geom::transformation*> create_shape(const express::base& instance, const express::base& representation) {
|
||||
if (instance.file() != file_) {
|
||||
throw ifcopenshell::exception("Instance does not belong to the file this kernel was constructed for");
|
||||
}
|
||||
return helper_fn_create_shape_with_converter(converter_, settings_, instance, representation);
|
||||
}
|
||||
|
||||
// Manual definition of overload without representation argument
|
||||
std::variant<ifcopenshell::geom::element*, ifcopenshell::geom::representation*, ifcopenshell::geom::transformation*> create_shape(const express::base& instance) {
|
||||
return create_shape(instance, express::base());
|
||||
}
|
||||
|
||||
private:
|
||||
ifcopenshell::file* file_;
|
||||
ifcopenshell::geom::settings settings_;
|
||||
ifcopenshell::geom::converter converter_;
|
||||
};
|
||||
%}
|
||||
|
||||
// @todo bring back serialization OCCT -> IFC by means of opencascade_geometry_ifc_writer_registry
|
||||
|
||||
%template(OpaqueCoordinate_3) ifcopenshell::geom::opaque_coordinate<3>;
|
||||
|
||||
Reference in New Issue
Block a user