diff --git a/src/ifcwrap/IfcGeomWrapper.i b/src/ifcwrap/IfcGeomWrapper.i index e9bcd72985..4f18ee14c7 100644 --- a/src/ifcwrap/IfcGeomWrapper.i +++ b/src/ifcwrap/IfcGeomWrapper.i @@ -117,6 +117,7 @@ std::pair vector_to_buffer(const T& t) { // @this is really annoying, but apparently inheritance // is lost in swig in the shared_ptr type hiearchy using namespace ifcopenshell::geometry::taxonomy; + if (!$1) $1 = try_upcast($input, SWIGTYPE_p_std__shared_ptrT_ifcopenshell__geometry__taxonomy__boolean_result_t); if (!$1) $1 = try_upcast($input, SWIGTYPE_p_std__shared_ptrT_ifcopenshell__geometry__taxonomy__bspline_curve_t); if (!$1) $1 = try_upcast($input, SWIGTYPE_p_std__shared_ptrT_ifcopenshell__geometry__taxonomy__bspline_surface_t); if (!$1) $1 = try_upcast($input, SWIGTYPE_p_std__shared_ptrT_ifcopenshell__geometry__taxonomy__circle_t); @@ -154,6 +155,41 @@ std::string taxonomy_item_repr(ifcopenshell::geometry::taxonomy::item::ptr i) { } %} +%{ + + +namespace { + // Helper function to create a Python tuple from an Eigen matrix/vector + template + PyObject* eigen_to_python_tuple(const Eigen::MatrixBase& mat) { + constexpr auto rows = T::RowsAtCompileTime; + constexpr auto cols = T::ColsAtCompileTime; + + if constexpr (rows == 1 || cols == 1) { + // Eigen::Vector (1D array) + PyObject* tuple = PyTuple_New(rows * cols); + for (int i = 0; i < mat.size(); ++i) { + PyTuple_SetItem(tuple, i, PyFloat_FromDouble(mat(i))); + } + return tuple; + } else { + // Eigen::Matrix (2D array) + PyObject* tuple = PyTuple_New(rows); + for (int i = 0; i < rows; ++i) { + PyObject* row = PyTuple_New(cols); + for (int j = 0; j < cols; ++j) { + PyTuple_SetItem(row, j, PyFloat_FromDouble(mat(i, j))); + } + PyTuple_SetItem(tuple, i, row); + } + return tuple; + } + } +} + +%} + +%shared_ptr(ifcopenshell::geometry::taxonomy::boolean_result); %shared_ptr(ifcopenshell::geometry::taxonomy::item); %shared_ptr(ifcopenshell::geometry::taxonomy::implicit_item); %shared_ptr(ifcopenshell::geometry::taxonomy::piecewise_function); @@ -223,46 +259,85 @@ std::string taxonomy_item_repr(ifcopenshell::geometry::taxonomy::item::ptr i) { } } -%extend ifcopenshell::geometry::taxonomy::point3 { - PyObject* coords_() const { - auto result = PyTuple_New(3); - for (int i = 0; i < 3; ++i) { - PyTuple_SET_ITEM(result, i, PyFloat_FromDouble($self->ccomponents().data()[i])); - } - return result; + +%define assign_component_acccess(item_name) + +%extend ifcopenshell::geometry::taxonomy::item_name { + PyObject* components_() const { + return eigen_to_python_tuple(self->ccomponents()); } %pythoncode %{ - coords = property(coords_) + components = property(components_) %} -} +}; -%extend ifcopenshell::geometry::taxonomy::direction3 { - // @todo refactor in macro - PyObject* coords_() const { - auto result = PyTuple_New(3); - for (int i = 0; i < 3; ++i) { - PyTuple_SET_ITEM(result, i, PyFloat_FromDouble($self->ccomponents().data()[i])); - } - return result; - } +%enddef - %pythoncode %{ - coords = property(coords_) - %} -} +assign_component_acccess(point3); +assign_component_acccess(direction3); +assign_component_acccess(matrix4); +assign_component_acccess(colour); +%define assign_children_access(item_name, children_type) -%extend ifcopenshell::geometry::taxonomy::loop { - const std::vector& children_() const { +%extend ifcopenshell::geometry::taxonomy::item_name { + // swig does not accept auto here as the return type + const std::vector& children_() const { return $self->children; } + const ifcopenshell::geometry::taxonomy::children_type::ptr& __getitem__(int index) const { + if (index < 0 || index >= $self->children.size()) { + throw std::runtime_error("Index " + std::to_string(index) + " is out of bounds for an array of length " + std::to_string($self->children.size())); + } + return $self->children[index]; + } + %pythoncode %{ children = property(children_) + def __iter__(self): + return iter(self.children) %} -} +}; +%enddef + +assign_children_access(collection, geom_item); +assign_children_access(loop, edge); +assign_children_access(face, loop); +assign_children_access(shell, face); +assign_children_access(solid, shell); +assign_children_access(loft, face); +assign_children_access(boolean_result, geom_item); + +%define assign_matrix_access(item_name) + +%extend ifcopenshell::geometry::taxonomy::item_name { + // swig does not accept auto here as the return type + const ifcopenshell::geometry::taxonomy::matrix4::ptr& matrix_() const { + return $self->matrix; + } + + %pythoncode %{ + matrix = property(matrix_) + %} +}; + +%enddef + +assign_matrix_access(line); +assign_matrix_access(circle); +assign_matrix_access(ellipse); +assign_matrix_access(collection); +assign_matrix_access(solid); +assign_matrix_access(face); +assign_matrix_access(plane); +assign_matrix_access(cylinder); +assign_matrix_access(sphere); +assign_matrix_access(torus); +assign_matrix_access(extrusion); +assign_matrix_access(revolve); %extend ifcopenshell::geometry::Settings { void set_(const std::string& name, bool val) { @@ -1131,6 +1206,7 @@ ifcopenshell::geometry::taxonomy::item::ptr try_upcast(PyObject* obj0, swig_type %enddef +assign_repr(ifcopenshell::geometry::taxonomy::boolean_result) assign_repr(ifcopenshell::geometry::taxonomy::bspline_curve) assign_repr(ifcopenshell::geometry::taxonomy::bspline_surface) assign_repr(ifcopenshell::geometry::taxonomy::circle) @@ -1159,4 +1235,5 @@ assign_repr(ifcopenshell::geometry::taxonomy::torus) assign_repr(ifcopenshell::geometry::taxonomy::style) assign_repr(ifcopenshell::geometry::taxonomy::sweep_along_curve) + #endif diff --git a/src/ifcwrap/utils/type_conversion.i b/src/ifcwrap/utils/type_conversion.i index 5ef2ceb124..5c90179b4d 100644 --- a/src/ifcwrap/utils/type_conversion.i +++ b/src/ifcwrap/utils/type_conversion.i @@ -247,7 +247,8 @@ PyObject* item_to_pyobject(const ifcopenshell::geometry::taxonomy::item::ptr& i) auto kind = i->kind(); // @todo this is not automatically generated :( // we can probably use the dispatch mechanism for this we already have in the kernel - if (kind == BSPLINE_CURVE) { return SWIG_NewPointerObj(SWIG_as_voidptr(new std::shared_ptr(std::static_pointer_cast(i))), SWIGTYPE_p_std__shared_ptrT_ifcopenshell__geometry__taxonomy__bspline_curve_t, 0 | SWIG_POINTER_OWN); } + if (kind == BOOLEAN_RESULT) { return SWIG_NewPointerObj(SWIG_as_voidptr(new std::shared_ptr(std::static_pointer_cast(i))), SWIGTYPE_p_std__shared_ptrT_ifcopenshell__geometry__taxonomy__boolean_result_t, 0 | SWIG_POINTER_OWN); } + else if (kind == BSPLINE_CURVE) { return SWIG_NewPointerObj(SWIG_as_voidptr(new std::shared_ptr(std::static_pointer_cast(i))), SWIGTYPE_p_std__shared_ptrT_ifcopenshell__geometry__taxonomy__bspline_curve_t, 0 | SWIG_POINTER_OWN); } else if (kind == BSPLINE_SURFACE) { return SWIG_NewPointerObj(SWIG_as_voidptr(new std::shared_ptr(std::static_pointer_cast(i))), SWIGTYPE_p_std__shared_ptrT_ifcopenshell__geometry__taxonomy__bspline_surface_t, 0 | SWIG_POINTER_OWN); } else if (kind == CIRCLE) { return SWIG_NewPointerObj(SWIG_as_voidptr(new std::shared_ptr(std::static_pointer_cast(i))), SWIGTYPE_p_std__shared_ptrT_ifcopenshell__geometry__taxonomy__circle_t, 0 | SWIG_POINTER_OWN); } else if (kind == COLLECTION) { return SWIG_NewPointerObj(SWIG_as_voidptr(new std::shared_ptr(std::static_pointer_cast(i))), SWIGTYPE_p_std__shared_ptrT_ifcopenshell__geometry__taxonomy__collection_t, 0 | SWIG_POINTER_OWN); } diff --git a/src/ifcwrap/utils/typemaps_out.i b/src/ifcwrap/utils/typemaps_out.i index ea5648030e..2984e5f059 100644 --- a/src/ifcwrap/utils/typemaps_out.i +++ b/src/ifcwrap/utils/typemaps_out.i @@ -112,8 +112,14 @@ CREATE_VECTOR_TYPEMAP_OUT(IfcGeom::ConversionResultShape *) } }; +%typemap(out) const item_name::ptr& { + $result = item_to_pyobject(*$1); +}; + %enddef +vector_of_item(ifcopenshell::geometry::taxonomy::item) +vector_of_item(ifcopenshell::geometry::taxonomy::boolean_result) vector_of_item(ifcopenshell::geometry::taxonomy::bspline_curve) vector_of_item(ifcopenshell::geometry::taxonomy::bspline_surface) vector_of_item(ifcopenshell::geometry::taxonomy::circle) @@ -141,3 +147,4 @@ vector_of_item(ifcopenshell::geometry::taxonomy::sphere) vector_of_item(ifcopenshell::geometry::taxonomy::torus) vector_of_item(ifcopenshell::geometry::taxonomy::style) vector_of_item(ifcopenshell::geometry::taxonomy::sweep_along_curve) +vector_of_item(ifcopenshell::geometry::taxonomy::geom_item)