diff --git a/src/ifcopenshell-python/ifcopenshell/__init__.py b/src/ifcopenshell-python/ifcopenshell/__init__.py index 40918b2771..4912860fb3 100644 --- a/src/ifcopenshell-python/ifcopenshell/__init__.py +++ b/src/ifcopenshell-python/ifcopenshell/__init__.py @@ -51,22 +51,15 @@ class entity_instance(object): return entity_instance.wrap_value(self.wrapped_data.get_inverse(name)) else: raise AttributeError("entity instance of type '%s' has no attribute '%s'"%(self.wrapped_data.is_a(), name)) @staticmethod - def map_value(v): - if isinstance(v, entity_instance): return v.wrapped_data - elif isinstance(v, (tuple, list)) and len(v): - classes = list(map(type, v)) - if float in classes: return ifcopenshell_wrapper.double_vector(v) - elif int in classes: return ifcopenshell_wrapper.int_vector(v) - elif str in classes: return ifcopenshell_wrapper.string_vector(v) - elif entity_instance in classes: return list(map(lambda e: e.wrapped_data, v)) - return v - @staticmethod def wrap_value(v): wrap = lambda e: entity_instance(e) if isinstance(v, ifcopenshell_wrapper.entity_instance): return wrap(v) elif isinstance(v, (tuple, list)) and len(v): - classes = list(map(type, v)) - if ifcopenshell_wrapper.entity_instance in classes: return list(map(wrap, v)) + classes = set(map(type, v)) + if {ifcopenshell_wrapper.entity_instance} == classes: return list(map(wrap, v)) + elif {list} == classes: + classes = set(map(type, v[0])) + if {ifcopenshell_wrapper.entity_instance} == classes: return [list(map(wrap, x)) for x in v] return v def attribute_type(self, attr): attr_idx = attr if isinstance(attr, int) else self.wrapped_data.get_argument_index(attr) @@ -78,7 +71,10 @@ class entity_instance(object): def __getitem__(self, key): return entity_instance.wrap_value(self.wrapped_data.get_argument(key)) def __setitem__(self, idx, value): - self.wrapped_data.set_argument(idx, entity_instance.map_value(value)) + attr_type = self.attribute_type(idx).title().replace(' ', '') + attr_type = attr_type.replace('Binary', 'String') + attr_type = attr_type.replace('Enumeration', 'String') + getattr(self.wrapped_data, "setArgumentAs%s" % attr_type)(idx, value) def __len__(self): return len(self.wrapped_data) def __repr__(self): return repr(self.wrapped_data) def is_a(self, *args): return self.wrapped_data.is_a(*args) diff --git a/src/ifcparse/IfcLateBoundEntity.cpp b/src/ifcparse/IfcLateBoundEntity.cpp index df3183275a..af13f6d9fd 100644 --- a/src/ifcparse/IfcLateBoundEntity.cpp +++ b/src/ifcparse/IfcLateBoundEntity.cpp @@ -110,13 +110,13 @@ void IfcParse::IfcLateBoundEntity::invalid_argument(unsigned int i, const std::s const std::string arg_name = IfcSchema::Type::GetAttributeName(_type,i); throw IfcException(t + " is not a valid type for '" + arg_name + "'"); } -void IfcParse::IfcLateBoundEntity::setArgument(unsigned int i) { +void IfcParse::IfcLateBoundEntity::setArgumentAsNull(unsigned int i) { bool is_optional = IfcSchema::Type::GetAttributeOptional(_type, i); if (is_optional) { writable_entity()->setArgument(i); } else invalid_argument(i,"NULL"); } -void IfcParse::IfcLateBoundEntity::setArgument(unsigned int i, int v) { +void IfcParse::IfcLateBoundEntity::setArgumentAsInt(unsigned int i, int v) { IfcUtil::ArgumentType arg_type = IfcSchema::Type::GetAttributeType(_type,i); if (arg_type == Argument_INT) { writable_entity()->setArgument(i,v); @@ -124,19 +124,19 @@ void IfcParse::IfcLateBoundEntity::setArgument(unsigned int i, int v) { writable_entity()->setArgument(i, v == 1); } else invalid_argument(i,"INTEGER"); } -void IfcParse::IfcLateBoundEntity::setArgument(unsigned int i, bool v) { +void IfcParse::IfcLateBoundEntity::setArgumentAsBool(unsigned int i, bool v) { IfcUtil::ArgumentType arg_type = IfcSchema::Type::GetAttributeType(_type,i); if (arg_type == Argument_BOOL) { writable_entity()->setArgument(i,v); } else invalid_argument(i,"BOOLEAN"); } -void IfcParse::IfcLateBoundEntity::setArgument(unsigned int i, double v) { +void IfcParse::IfcLateBoundEntity::setArgumentAsDouble(unsigned int i, double v) { IfcUtil::ArgumentType arg_type = IfcSchema::Type::GetAttributeType(_type,i); if (arg_type == Argument_DOUBLE) { writable_entity()->setArgument(i,v); } else invalid_argument(i,"REAL"); } -void IfcParse::IfcLateBoundEntity::setArgument(unsigned int i, const std::string& a) { +void IfcParse::IfcLateBoundEntity::setArgumentAsString(unsigned int i, const std::string& a) { IfcUtil::ArgumentType arg_type = IfcSchema::Type::GetAttributeType(_type,i); if (arg_type == Argument_STRING) { writable_entity()->setArgument(i,a); @@ -144,23 +144,27 @@ void IfcParse::IfcLateBoundEntity::setArgument(unsigned int i, const std::string std::pair enum_data = IfcSchema::Type::GetEnumerationIndex(IfcSchema::Type::GetAttributeEntity(_type, i), a); writable_entity()->setArgument(i, enum_data.second, enum_data.first); } else if (arg_type == Argument_BINARY) { - boost::dynamic_bitset<> bits(a); - writable_entity()->setArgument(i, bits); + if (valid_binary_string(a)) { + boost::dynamic_bitset<> bits(a); + writable_entity()->setArgument(i, bits); + } else { + throw IfcException("String not a valid binary representation"); + } } else invalid_argument(i,"STRING"); } -void IfcParse::IfcLateBoundEntity::setArgument(unsigned int i, const std::vector& v) { +void IfcParse::IfcLateBoundEntity::setArgumentAsAggregateOfInt(unsigned int i, const std::vector& v) { IfcUtil::ArgumentType arg_type = IfcSchema::Type::GetAttributeType(_type,i); if (arg_type == Argument_AGGREGATE_OF_INT) { writable_entity()->setArgument(i,v); } else invalid_argument(i,"AGGREGATE OF INT"); } -void IfcParse::IfcLateBoundEntity::setArgument(unsigned int i, const std::vector& v) { +void IfcParse::IfcLateBoundEntity::setArgumentAsAggregateOfDouble(unsigned int i, const std::vector& v) { IfcUtil::ArgumentType arg_type = IfcSchema::Type::GetAttributeType(_type,i); if (arg_type == Argument_AGGREGATE_OF_DOUBLE) { writable_entity()->setArgument(i,v); } else invalid_argument(i,"AGGREGATE OF DOUBLE"); } -void IfcParse::IfcLateBoundEntity::setArgument(unsigned int i, const std::vector& v) { +void IfcParse::IfcLateBoundEntity::setArgumentAsAggregateOfString(unsigned int i, const std::vector& v) { IfcUtil::ArgumentType arg_type = IfcSchema::Type::GetAttributeType(_type,i); if (arg_type == Argument_AGGREGATE_OF_STRING) { writable_entity()->setArgument(i,v); @@ -168,28 +172,44 @@ void IfcParse::IfcLateBoundEntity::setArgument(unsigned int i, const std::vector std::vector< boost::dynamic_bitset<> > bits; bits.reserve(v.size()); for (std::vector::const_iterator it = v.begin(); it != v.end(); ++it) { - bits.push_back(boost::dynamic_bitset<>(*it)); + if (valid_binary_string(*it)) { + bits.push_back(boost::dynamic_bitset<>(*it)); + } else { + throw IfcException("String not a valid binary representation"); + } } writable_entity()->setArgument(i, bits); } else invalid_argument(i,"AGGREGATE OF STRING"); } -void IfcParse::IfcLateBoundEntity::setArgument(unsigned int i, IfcParse::IfcLateBoundEntity* v) { +void IfcParse::IfcLateBoundEntity::setArgumentAsEntityInstance(unsigned int i, IfcParse::IfcLateBoundEntity* v) { IfcUtil::ArgumentType arg_type = IfcSchema::Type::GetAttributeType(_type,i); if (arg_type == Argument_ENTITY_INSTANCE) { writable_entity()->setArgument(i,v); } else invalid_argument(i,"ENTITY INSTANCE"); } -void IfcParse::IfcLateBoundEntity::setArgument(unsigned int i, IfcEntityList::ptr v) { +void IfcParse::IfcLateBoundEntity::setArgumentAsAggregateOfEntityInstance(unsigned int i, IfcEntityList::ptr v) { IfcUtil::ArgumentType arg_type = IfcSchema::Type::GetAttributeType(_type,i); if (arg_type == Argument_AGGREGATE_OF_ENTITY_INSTANCE) { writable_entity()->setArgument(i,v); } else invalid_argument(i,"AGGREGATE OF ENTITY INSTANCE"); } -std::pair IfcParse::IfcLateBoundEntity::get_argument(unsigned i) { - return std::pair(getArgumentType(i),getArgument(i)); +void IfcParse::IfcLateBoundEntity::setArgumentAsAggregateOfAggregateOfInt(unsigned int i, const std::vector< std::vector >& v) { + IfcUtil::ArgumentType arg_type = IfcSchema::Type::GetAttributeType(_type,i); + if (arg_type == Argument_AGGREGATE_OF_AGGREGATE_OF_INT) { + writable_entity()->setArgument(i,v); + } else invalid_argument(i,"AGGREGATE OF AGGREGATE OF INT"); } -std::pair IfcParse::IfcLateBoundEntity::get_argument(const std::string& a) { - return get_argument(IfcSchema::Type::GetAttributeIndex(_type,a)); +void IfcParse::IfcLateBoundEntity::setArgumentAsAggregateOfAggregateOfDouble(unsigned int i, const std::vector< std::vector >& v) { + IfcUtil::ArgumentType arg_type = IfcSchema::Type::GetAttributeType(_type,i); + if (arg_type == Argument_AGGREGATE_OF_AGGREGATE_OF_DOUBLE) { + writable_entity()->setArgument(i,v); + } else invalid_argument(i,"AGGREGATE OF AGGREGATE OF DOUBLE"); +} +void IfcParse::IfcLateBoundEntity::setArgumentAsAggregateOfAggregateOfEntityInstance(unsigned int i, IfcEntityListList::ptr v) { + IfcUtil::ArgumentType arg_type = IfcSchema::Type::GetAttributeType(_type,i); + if (arg_type == Argument_AGGREGATE_OF_AGGREGATE_OF_ENTITY_INSTANCE) { + writable_entity()->setArgument(i,v); + } else invalid_argument(i,"AGGREGATE OF AGGREGATE OF ENTITY INSTANCE"); } unsigned IfcParse::IfcLateBoundEntity::getArgumentIndex(const std::string& a) const { return IfcSchema::Type::GetAttributeIndex(_type,a); diff --git a/src/ifcparse/IfcLateBoundEntity.h b/src/ifcparse/IfcLateBoundEntity.h index 8642cd63fc..65a91d0f77 100644 --- a/src/ifcparse/IfcLateBoundEntity.h +++ b/src/ifcparse/IfcLateBoundEntity.h @@ -60,22 +60,23 @@ namespace IfcParse { std::vector getAttributeNames() const; std::vector getInverseAttributeNames() const; - void setArgument(unsigned int i); - void setArgument(unsigned int i, int v); - void setArgument(unsigned int i, bool v); - void setArgument(unsigned int i, double v); - void setArgument(unsigned int i, const std::string& v); - void setArgument(unsigned int i, const std::vector& v); - void setArgument(unsigned int i, const std::vector& v); - void setArgument(unsigned int i, const std::vector& v); - void setArgument(unsigned int i, IfcLateBoundEntity* v); - void setArgument(unsigned int i, IfcEntityList::ptr v); + void setArgumentAsNull(unsigned int i); + void setArgumentAsInt(unsigned int i, int v); + void setArgumentAsBool(unsigned int i, bool v); + void setArgumentAsDouble(unsigned int i, double v); + void setArgumentAsString(unsigned int i, const std::string& v); + void setArgumentAsEntityInstance(unsigned int i, IfcLateBoundEntity* v); + + void setArgumentAsAggregateOfInt(unsigned int i, const std::vector& v); + void setArgumentAsAggregateOfDouble(unsigned int i, const std::vector& v); + void setArgumentAsAggregateOfString(unsigned int i, const std::vector& v); + void setArgumentAsAggregateOfEntityInstance(unsigned int i, IfcEntityList::ptr v); + + void setArgumentAsAggregateOfAggregateOfInt(unsigned int i, const std::vector< std::vector >& v); + void setArgumentAsAggregateOfAggregateOfDouble(unsigned int i, const std::vector< std::vector >& v); + void setArgumentAsAggregateOfAggregateOfEntityInstance(unsigned int i, IfcEntityListList::ptr v); std::string toString(); - - // TODO: Write as SWIG extension methods? - std::pair get_argument(unsigned i); - std::pair get_argument(const std::string& a); bool is_valid(); }; diff --git a/src/ifcparse/IfcUtil.cpp b/src/ifcparse/IfcUtil.cpp index d9f3e4ef81..0f4bc13734 100644 --- a/src/ifcparse/IfcUtil.cpp +++ b/src/ifcparse/IfcUtil.cpp @@ -137,3 +137,10 @@ static const char* const argument_type_string[] = { const char* IfcUtil::ArgumentTypeToString(ArgumentType argument_type) { return argument_type_string[static_cast(argument_type)]; } + +bool IfcUtil::valid_binary_string(const std::string& s) { + for (std::string::const_iterator it = s.begin(); it != s.end(); ++it) { + if (*it != '0' && *it != '1') return false; + } + return true; +} \ No newline at end of file diff --git a/src/ifcparse/IfcUtil.h b/src/ifcparse/IfcUtil.h index a6edc1531e..e57f5da279 100644 --- a/src/ifcparse/IfcUtil.h +++ b/src/ifcparse/IfcUtil.h @@ -102,6 +102,8 @@ namespace IfcUtil { const char* getArgumentName(unsigned int i) const; IfcSchema::Type::Enum getArgumentEntity(unsigned int i) const { return IfcSchema::Type::UNDEFINED; } }; + + bool valid_binary_string(const std::string& s); } template diff --git a/src/ifcwrap/IfcParseWrapper.i b/src/ifcwrap/IfcParseWrapper.i index 3219e99093..12582c4c1e 100644 --- a/src/ifcwrap/IfcParseWrapper.i +++ b/src/ifcwrap/IfcParseWrapper.i @@ -62,139 +62,15 @@ namespace IfcUtil { %rename("get_argument_optionality") getArgumentOptionality; %rename("get_attribute_names") getAttributeNames; %rename("get_inverse_attribute_names") getInverseAttributeNames; -%rename("_set_argument") setArgument; %rename("__repr__") toString; %rename("entity_instance") IfcLateBoundEntity; %rename("file") IfcFile; -%typemap(typecheck,precedence=SWIG_TYPECHECK_INTEGER) IfcEntityList::ptr { - $1 = (PySequence_Check($input) && !PyUnicode_Check($input) && !PyString_Check($input)) ? 1 : 0; -} +%include "utils/type_conversion.i" -%typemap(in) IfcEntityList::ptr { - if (PySequence_Check($input)) { - $1 = IfcEntityList::ptr(new IfcEntityList()); - for(Py_ssize_t i = 0; i < PySequence_Size($input); ++i) { - PyObject* obj = PySequence_GetItem($input, i); - if (obj) { - void *arg = 0; - int res = SWIG_ConvertPtr(obj, &arg, SWIGTYPE_p_IfcParse__IfcLateBoundEntity, 0); - if (!SWIG_IsOK(res)) { - SWIG_exception_fail(SWIG_ArgError(res), "Sequence element not of type IfcParse::IfcLateBoundEntity*"); - } else { - $1->push(reinterpret_cast(arg)); - } - } - } - } else { - SWIG_exception(SWIG_RuntimeError,"Unknown argument type"); - } -} +%include "utils/typemaps_in.i" -%typemap(out) IfcEntityList::ptr { - const unsigned size = $1 ? $1->size() : 0; - $result = PyList_New(size); - for (unsigned i = 0; i < size; ++i) { - PyObject *o = SWIG_NewPointerObj(SWIG_as_voidptr((*$1)[i]), SWIGTYPE_p_IfcParse__IfcLateBoundEntity, 0); - PyList_SetItem($result,i,o); - } -} - -%typemap(out) IfcUtil::ArgumentType { - $result = SWIG_Python_str_FromChar(IfcUtil::ArgumentTypeToString($1)); -} - -%typemap(out) std::pair { - // The SWIG %exception directive does not take care - // of our typemap. So the argument conversion block - // is wrapped in a try-catch block manually. - try { - const Argument& arg = *($1.second); - const IfcUtil::ArgumentType type = $1.first; - if (arg.isNull() || type == IfcUtil::Argument_DERIVED) { - Py_INCREF(Py_None); - $result = Py_None; - } else { - switch(type) { - case IfcUtil::Argument_INT: - $result = PyInt_FromLong((int)arg); - break; - case IfcUtil::Argument_BOOL: - $result = PyBool_FromLong((bool)arg); - break; - case IfcUtil::Argument_DOUBLE: - $result = PyFloat_FromDouble(arg); - break; - case IfcUtil::Argument_ENUMERATION: - case IfcUtil::Argument_STRING: { - const std::string s = arg; - $result = PyString_FromString(s.c_str()); - break; } - case IfcUtil::Argument_BINARY: { - const boost::dynamic_bitset<> b = arg; - std::string bitstring; - boost::to_string(b, bitstring); - $result = PyString_FromString(bitstring.c_str()); - break; } - case IfcUtil::Argument_AGGREGATE_OF_INT: { - const std::vector v = arg; - const unsigned size = v.size(); - $result = PyList_New(size); - for (unsigned int i = 0; i < size; ++i) { - PyList_SetItem($result,i,PyInt_FromLong(v[i])); - } - break; } - case IfcUtil::Argument_AGGREGATE_OF_DOUBLE: { - const std::vector v = arg; - const unsigned size = v.size(); - $result = PyList_New(size); - for (unsigned int i = 0; i < size; ++i) { - PyList_SetItem($result,i,PyFloat_FromDouble(v[i])); - } - break; } - case IfcUtil::Argument_AGGREGATE_OF_STRING: { - const std::vector v = arg; - const unsigned size = v.size(); - $result = PyList_New(size); - for (unsigned int i = 0; i < size; ++i) { - PyList_SetItem($result,i,PyString_FromString(v[i].c_str())); - } - break; } - case IfcUtil::Argument_ENTITY_INSTANCE: { - IfcUtil::IfcBaseClass* e = arg; - $result = SWIG_NewPointerObj(SWIG_as_voidptr(e), SWIGTYPE_p_IfcParse__IfcLateBoundEntity, 0); - break; } - case IfcUtil::Argument_AGGREGATE_OF_ENTITY_INSTANCE: { - IfcEntityList::ptr es = arg; - const unsigned size = es->size(); - $result = PyList_New(size); - for (unsigned i = 0; i < size; ++i) { - PyObject *o = SWIG_NewPointerObj(SWIG_as_voidptr((*es)[i]), SWIGTYPE_p_IfcParse__IfcLateBoundEntity, 0); - PyList_SetItem($result,i,o); - } - break; } - case IfcUtil::Argument_AGGREGATE_OF_BINARY: { - const std::vector< boost::dynamic_bitset<> > bs = arg; - const unsigned size = bs.size(); - $result = PyList_New(size); - for (unsigned int i = 0; i < size; ++i) { - std::string bitstring; - boost::to_string(bs[i], bitstring); - PyList_SetItem($result,i,PyString_FromString(bitstring.c_str())); - } - break; } - case IfcUtil::Argument_UNKNOWN: - default: - SWIG_exception(SWIG_RuntimeError,"Unknown argument type"); - break; - } - } - } catch(IfcParse::IfcException& e) { - SWIG_exception(SWIG_RuntimeError, e.what()); - } catch(...) { - SWIG_exception(SWIG_RuntimeError, "An unknown error occurred"); - } -} +%include "utils/typemaps_out.i" %extend IfcParse::IfcFile { IfcParse::IfcLateBoundEntity* by_id(unsigned id) { @@ -245,9 +121,15 @@ namespace IfcUtil { } } } - %pythoncode %{ - set_argument = lambda self,x,y: self._set_argument(x) if y is None else self._set_argument(x,y) - %} + + std::pair get_argument(unsigned i) { + return std::pair($self->getArgumentType(i), $self->getArgument(i)); + } + + std::pair get_argument(const std::string& a) { + unsigned i = IfcSchema::Type::GetAttributeIndex($self->type(), a); + return std::pair($self->getArgumentType(i), $self->getArgument(i)); + } } %extend IfcParse::IfcSpfHeader { diff --git a/src/ifcwrap/IfcPython.i b/src/ifcwrap/IfcPython.i index dce1433441..602110d255 100644 --- a/src/ifcwrap/IfcPython.i +++ b/src/ifcwrap/IfcPython.i @@ -24,9 +24,11 @@ %exception { try { $action - } catch(IfcParse::IfcException& e) { + } catch(const IfcParse::IfcAttributeOutOfRangeException& e) { + SWIG_exception(SWIG_IndexError, e.what()); + } catch(const IfcParse::IfcException& e) { SWIG_exception(SWIG_RuntimeError, e.what()); - } catch(std::runtime_error& e) { + } catch(const std::runtime_error& e) { SWIG_exception(SWIG_RuntimeError, e.what()); } catch(...) { SWIG_exception(SWIG_RuntimeError, "An unknown error occurred"); @@ -39,6 +41,12 @@ #include "../ifcparse/IfcFile.h" #include "../ifcparse/IfcLateBoundEntity.h" + + #ifdef USE_IFC4 + #include "../ifcparse/Ifc4-latebound.h" + #else + #include "../ifcparse/Ifc2x3-latebound.h" + #endif %} // The following typemaps are an alternative for the read-only std::vector diff --git a/src/ifcwrap/utils/type_conversion.i b/src/ifcwrap/utils/type_conversion.i new file mode 100644 index 0000000000..0bc47d5b9d --- /dev/null +++ b/src/ifcwrap/utils/type_conversion.i @@ -0,0 +1,159 @@ +/******************************************************************************** + * * + * This file is part of IfcOpenShell. * + * * + * IfcOpenShell is free software: you can redistribute it and/or modify * + * it under the terms of the Lesser GNU General Public License as published by * + * the Free Software Foundation, either version 3.0 of the License, or * + * (at your option) any later version. * + * * + * IfcOpenShell is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * Lesser GNU General Public License for more details. * + * * + * You should have received a copy of the Lesser GNU General Public License * + * along with this program. If not, see . * + * * + ********************************************************************************/ + +// Conversion functions and checks to convert Python objects into STL vectors +%{ + template void* get_python_type(); + template <> void* get_python_type() { return &PyFloat_Type; } + #if PY_VERSION_HEX >= 0x03000000 + template <> void* get_python_type() { return &PyLong_Type; } + template <> void* get_python_type() { return &PyUnicode_Type; } + #else + template <> void* get_python_type() { return &PyInt_Type; } + template <> void* get_python_type() { return &PyString_Type; } + #endif + + bool check_aggregate_of_type(PyObject* aggregate, void* type_obj) { + if (!PySequence_Check(aggregate)) return false; + for(Py_ssize_t i = 0; i < PySequence_Size(aggregate); ++i) { + PyObject* element = PySequence_GetItem(aggregate, i); + // This is equivalent to the PyFloat_CheckExact macro. This means + // that direct instances of int, float, str, etc. need to be used. + if (element->ob_type != type_obj) return false; + } + return true; + } + + bool check_aggregate_of_aggregate_of_type(PyObject* aggregate, void* type_obj) { + if (!PySequence_Check(aggregate)) return false; + for(Py_ssize_t i = 0; i < PySequence_Size(aggregate); ++i) { + PyObject* element = PySequence_GetItem(aggregate, i); + if (!check_aggregate_of_type(element, type_obj)) { + return false; + } + } + return true; + } + + template + T cast_pyobject(PyObject* element); + + template <> + int cast_pyobject(PyObject* element) { + return static_cast(PyInt_AsLong(element)); + } + + template <> + double cast_pyobject(PyObject* element) { + return PyFloat_AsDouble(element); + } + + template <> + std::string cast_pyobject(PyObject* element) { + char* str_data = SWIG_Python_str_AsChar(element); + std::string str = str_data; + SWIG_Python_str_DelForPy3(str_data); + return str; + } + + template <> + IfcParse::IfcLateBoundEntity* cast_pyobject(PyObject* element) { + void *arg = 0; + int res = SWIG_ConvertPtr(element, &arg, SWIGTYPE_p_IfcParse__IfcLateBoundEntity, 0); + if (!res) return static_cast(0); + return reinterpret_cast(arg); + } + + template + std::vector python_sequence_as_vector(PyObject* aggregate) { + std::vector result_vector; + result_vector.reserve(PySequence_Size(aggregate)); + for(Py_ssize_t i = 0; i < PySequence_Size(aggregate); ++i) { + PyObject* element = PySequence_GetItem(aggregate, i); + T t = cast_pyobject(element); + result_vector.push_back(t); + } + return result_vector; + } + + template + std::vector< std::vector > python_sequence_as_vector_of_vector(PyObject* aggregate) { + std::vector< std::vector > result_vector; + result_vector.reserve(PySequence_Size(aggregate)); + for(Py_ssize_t i = 0; i < PySequence_Size(aggregate); ++i) { + PyObject* element = PySequence_GetItem(aggregate, i); + std::vector t = python_sequence_as_vector(element); + result_vector.push_back(t); + } + return result_vector; + } +%} + +// Conversion functions to convert STL vectors into Python objects +%{ + PyObject* pythonize(const int& t) { return PyInt_FromLong(t); } + PyObject* pythonize(const bool& t) { return PyBool_FromLong(t); } + PyObject* pythonize(const double& t) { return PyFloat_FromDouble(t); } + PyObject* pythonize(const std::string& t) { return PyString_FromString(t.c_str()); } + PyObject* pythonize(const IfcUtil::IfcBaseClass* t) { return SWIG_NewPointerObj(SWIG_as_voidptr(t), SWIGTYPE_p_IfcParse__IfcLateBoundEntity, 0); } + + PyObject* pythonize(const boost::dynamic_bitset<>& t) { + std::string bitstring; + boost::to_string(t, bitstring); + return pythonize(bitstring); + } + + PyObject* pythonize(const IfcEntityList::ptr& t) { + unsigned int i = 0; + PyObject* pyobj = PyTuple_New(t->size()); + for (IfcEntityList::it it = t->begin(); it != t->end(); ++it, ++i) { + PyTuple_SetItem(pyobj, i, pythonize(*it)); + } + return pyobj; + } + + template + PyObject* pythonize_vector(const std::vector& v) { + const unsigned size = v.size(); + PyObject* pyobj = PyTuple_New(size); + for (unsigned int i = 0; i < size; ++i) { + PyTuple_SetItem(pyobj, i, pythonize(v[i])); + } + return pyobj; + } + + template + PyObject* pythonize_vector2(const std::vector< std::vector >& v) { + const unsigned size = v.size(); + PyObject* pyobj = PyTuple_New(size); + for (unsigned int i = 0; i < size; ++i) { + PyTuple_SetItem(pyobj, i, pythonize_vector(v[i])); + } + return pyobj; + } + + PyObject* pythonize(const IfcEntityListList::ptr& t) { + unsigned int i = 0; + PyObject* pyobj = PyTuple_New(t->size()); + for (IfcEntityListList::outer_it it = t->begin(); it != t->end(); ++it, ++i) { + PyTuple_SetItem(pyobj, i, pythonize_vector(*it)); + } + return pyobj; + } +%} diff --git a/src/ifcwrap/utils/typemaps_in.i b/src/ifcwrap/utils/typemaps_in.i new file mode 100644 index 0000000000..b486b80d6a --- /dev/null +++ b/src/ifcwrap/utils/typemaps_in.i @@ -0,0 +1,111 @@ +/******************************************************************************** + * * + * This file is part of IfcOpenShell. * + * * + * IfcOpenShell is free software: you can redistribute it and/or modify * + * it under the terms of the Lesser GNU General Public License as published by * + * the Free Software Foundation, either version 3.0 of the License, or * + * (at your option) any later version. * + * * + * IfcOpenShell is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * Lesser GNU General Public License for more details. * + * * + * You should have received a copy of the Lesser GNU General Public License * + * along with this program. If not, see . * + * * + ********************************************************************************/ + +%define CREATE_VECTOR_TYPEMAP_IN(template_type, express_name, python_name) + + %typemap(in) std::vector { + if (!check_aggregate_of_type($input, get_python_type())) { + SWIG_exception(SWIG_TypeError, "Attribute of type AGGREGATE OF " #express_name " needs a python sequence of " #python_name "s"); + } + $1 = python_sequence_as_vector($input); + } + + %typemap(arginit) const std::vector& { + $1 = new std::vector(); + } + %typemap(in) const std::vector& { + if (!check_aggregate_of_type($input, get_python_type())) { + SWIG_exception(SWIG_TypeError, "Attribute of type AGGREGATE OF " #express_name " needs a python sequence of " #python_name "s"); + } + *$1 = python_sequence_as_vector($input); + } + %typemap(freearg) const std::vector& { + delete $1; + } + + %typemap(in) std::vector< std::vector > { + if (!check_aggregate_of_aggregate_of_type($input, get_python_type())) { + SWIG_exception(SWIG_TypeError, "Attribute of type AGGREGATE OF AGGREGATE OF " #express_name " needs a python sequence of sequence of " #python_name "s"); + } + $1 = python_sequence_as_vector_of_vector($input); + } + + %typemap(arginit) const std::vector< std::vector >& { + $1 = new std::vector< std::vector >(); + } + %typemap(in) const std::vector< std::vector >& { + if (!check_aggregate_of_aggregate_of_type($input, get_python_type())) { + SWIG_exception(SWIG_TypeError, "Attribute of type AGGREGATE OF AGGREGATE OF " #express_name " needs a python sequence of sequence of " #python_name "s"); + } + *$1 = python_sequence_as_vector_of_vector($input); + } + %typemap(freearg) const std::vector< std::vector >& { + delete $1; + } + +%enddef + +CREATE_VECTOR_TYPEMAP_IN(int, INTEGER, int) +CREATE_VECTOR_TYPEMAP_IN(double, REAL, float) +CREATE_VECTOR_TYPEMAP_IN(std::string, STRING, str) + +%typemap(in) IfcEntityList::ptr { + if (PySequence_Check($input)) { + $1 = IfcEntityList::ptr(new IfcEntityList()); + for(Py_ssize_t i = 0; i < PySequence_Size($input); ++i) { + PyObject* element = PySequence_GetItem($input, i); + IfcParse::IfcLateBoundEntity* inst = cast_pyobject(element); + if (inst) { + $1->push(inst); + } else { + SWIG_exception(SWIG_TypeError, "Attribute of type AGGREGATE OF ENTITY INSTANCE needs a python sequence of entity instances"); + } + } + } else { + SWIG_exception(SWIG_TypeError, "Attribute of type AGGREGATE OF ENTITY INSTANCE needs a python sequence of entity instances"); + } +} + +%typemap(in) IfcEntityListList::ptr { + if (PySequence_Check($input)) { + $1 = IfcEntityListList::ptr(new IfcEntityListList()); + for(Py_ssize_t i = 0; i < PySequence_Size($input); ++i) { + PyObject* element = PySequence_GetItem($input, i); + if (PySequence_Check(element)) { + std::vector vector; + vector.reserve(PySequence_Size(element)); + for(Py_ssize_t j = 0; j < PySequence_Size(element); ++j) { + PyObject* element_element = PySequence_GetItem(element, j); + IfcParse::IfcLateBoundEntity* inst = cast_pyobject(element_element); + if (inst) { + vector.push_back(cast_pyobject(element_element)); + } else { + SWIG_exception(SWIG_TypeError, "Attribute of type AGGREGATE OF AGGREGATE OF ENTITY INSTANCE needs a python sequence of sequence of entity instances"); + } + } + $1->push(vector); + } else { + SWIG_exception(SWIG_TypeError, "Attribute of type AGGREGATE OF AGGREGATE OF ENTITY INSTANCE needs a python sequence of sequence of entity instances"); + break; + } + } + } else { + SWIG_exception(SWIG_TypeError, "Attribute of type AGGREGATE OF AGGREGATE OF ENTITY INSTANCE needs a python sequence of sequence of entity instances"); + } +} \ No newline at end of file diff --git a/src/ifcwrap/utils/typemaps_out.i b/src/ifcwrap/utils/typemaps_out.i new file mode 100644 index 0000000000..57edb1c93b --- /dev/null +++ b/src/ifcwrap/utils/typemaps_out.i @@ -0,0 +1,92 @@ +%typemap(out) IfcEntityList::ptr { + const unsigned size = $1 ? $1->size() : 0; + $result = PyTuple_New(size); + for (unsigned i = 0; i < size; ++i) { + PyTuple_SetItem($result, i, pythonize((*$1)[i])); + } +} + +%typemap(out) IfcUtil::ArgumentType { + $result = SWIG_Python_str_FromChar(IfcUtil::ArgumentTypeToString($1)); +} + +%typemap(out) std::pair { + // The SWIG %exception directive does not take care + // of our typemap. So the attribute conversion block + // is wrapped in a try-catch block manually. + try { + const Argument& arg = *($1.second); + const IfcUtil::ArgumentType type = $1.first; + if (arg.isNull() || type == IfcUtil::Argument_DERIVED) { + Py_INCREF(Py_None); + $result = Py_None; + } else { + switch(type) { + case IfcUtil::Argument_INT: + $result = pythonize((int) arg); + break; + case IfcUtil::Argument_BOOL: + $result = pythonize((bool) arg); + break; + case IfcUtil::Argument_DOUBLE: + $result = pythonize((double) arg); + break; + case IfcUtil::Argument_ENUMERATION: + case IfcUtil::Argument_STRING: + $result = pythonize((std::string) arg); + break; + case IfcUtil::Argument_BINARY: + $result = pythonize((boost::dynamic_bitset<>) arg); + break; + case IfcUtil::Argument_AGGREGATE_OF_INT: + $result = pythonize_vector((std::vector) arg); + break; + case IfcUtil::Argument_AGGREGATE_OF_DOUBLE: + $result = pythonize_vector((std::vector) arg); + break; + case IfcUtil::Argument_AGGREGATE_OF_STRING: + $result = pythonize_vector((std::vector) arg); + break; + case IfcUtil::Argument_ENTITY_INSTANCE: + $result = pythonize((IfcUtil::IfcBaseClass*) arg); + break; + case IfcUtil::Argument_AGGREGATE_OF_ENTITY_INSTANCE: + $result = pythonize((IfcEntityList::ptr) arg); + break; + case IfcUtil::Argument_AGGREGATE_OF_BINARY: + $result = pythonize_vector((std::vector< boost::dynamic_bitset<> >) arg); + break; + case IfcUtil::Argument_AGGREGATE_OF_AGGREGATE_OF_INT: + $result = pythonize_vector2((std::vector< std::vector >) arg); + break; + case IfcUtil::Argument_AGGREGATE_OF_AGGREGATE_OF_DOUBLE: + $result = pythonize_vector2((std::vector< std::vector >) arg); + break; + case IfcUtil::Argument_AGGREGATE_OF_AGGREGATE_OF_ENTITY_INSTANCE: + $result = pythonize((IfcEntityListList::ptr) arg); + break; + case IfcUtil::Argument_UNKNOWN: + default: + SWIG_exception(SWIG_RuntimeError,"Unknown attribute type"); + break; + } + } + } catch(IfcParse::IfcException& e) { + SWIG_exception(SWIG_RuntimeError, e.what()); + } catch(...) { + SWIG_exception(SWIG_RuntimeError, "An unknown error occurred"); + } +} + +%define CREATE_VECTOR_TYPEMAP_OUT(template_type) + %typemap(out) std::vector { + $result = pythonize_vector($1); + } + %typemap(out) const std::vector& { + $result = pythonize_vector($1); + } +%enddef + +CREATE_VECTOR_TYPEMAP_OUT(int) +CREATE_VECTOR_TYPEMAP_OUT(double) +CREATE_VECTOR_TYPEMAP_OUT(std::string)