mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-11 10:06:47 +00:00
Rework SWIG python binding not to rely on polymorhpic functions. Use hand-written typemaps that map vectors to tuples and iterables to vectors. Add support for multidimensional aggregates in Python.
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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<const char*, int> 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<int>& v) {
|
||||
void IfcParse::IfcLateBoundEntity::setArgumentAsAggregateOfInt(unsigned int i, const std::vector<int>& 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<double>& v) {
|
||||
void IfcParse::IfcLateBoundEntity::setArgumentAsAggregateOfDouble(unsigned int i, const std::vector<double>& 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<std::string>& v) {
|
||||
void IfcParse::IfcLateBoundEntity::setArgumentAsAggregateOfString(unsigned int i, const std::vector<std::string>& 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<std::string>::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<IfcUtil::ArgumentType,Argument*> IfcParse::IfcLateBoundEntity::get_argument(unsigned i) {
|
||||
return std::pair<IfcUtil::ArgumentType,Argument*>(getArgumentType(i),getArgument(i));
|
||||
void IfcParse::IfcLateBoundEntity::setArgumentAsAggregateOfAggregateOfInt(unsigned int i, const std::vector< std::vector<int> >& 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<IfcUtil::ArgumentType,Argument*> 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<double> >& 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);
|
||||
|
||||
@@ -60,22 +60,23 @@ namespace IfcParse {
|
||||
std::vector<std::string> getAttributeNames() const;
|
||||
std::vector<std::string> 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<int>& v);
|
||||
void setArgument(unsigned int i, const std::vector<double>& v);
|
||||
void setArgument(unsigned int i, const std::vector<std::string>& 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<int>& v);
|
||||
void setArgumentAsAggregateOfDouble(unsigned int i, const std::vector<double>& v);
|
||||
void setArgumentAsAggregateOfString(unsigned int i, const std::vector<std::string>& v);
|
||||
void setArgumentAsAggregateOfEntityInstance(unsigned int i, IfcEntityList::ptr v);
|
||||
|
||||
void setArgumentAsAggregateOfAggregateOfInt(unsigned int i, const std::vector< std::vector<int> >& v);
|
||||
void setArgumentAsAggregateOfAggregateOfDouble(unsigned int i, const std::vector< std::vector<double> >& v);
|
||||
void setArgumentAsAggregateOfAggregateOfEntityInstance(unsigned int i, IfcEntityListList::ptr v);
|
||||
|
||||
std::string toString();
|
||||
|
||||
// TODO: Write as SWIG extension methods?
|
||||
std::pair<IfcUtil::ArgumentType,Argument*> get_argument(unsigned i);
|
||||
std::pair<IfcUtil::ArgumentType,Argument*> get_argument(const std::string& a);
|
||||
|
||||
bool is_valid();
|
||||
};
|
||||
|
||||
@@ -137,3 +137,10 @@ static const char* const argument_type_string[] = {
|
||||
const char* IfcUtil::ArgumentTypeToString(ArgumentType argument_type) {
|
||||
return argument_type_string[static_cast<int>(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;
|
||||
}
|
||||
@@ -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 <class T>
|
||||
|
||||
+12
-130
@@ -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<IfcParse::IfcLateBoundEntity*>(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<IfcUtil::ArgumentType, Argument*> {
|
||||
// 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<int> 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<double> 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<std::string> 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<IfcUtil::ArgumentType,Argument*> get_argument(unsigned i) {
|
||||
return std::pair<IfcUtil::ArgumentType,Argument*>($self->getArgumentType(i), $self->getArgument(i));
|
||||
}
|
||||
|
||||
std::pair<IfcUtil::ArgumentType,Argument*> get_argument(const std::string& a) {
|
||||
unsigned i = IfcSchema::Type::GetAttributeIndex($self->type(), a);
|
||||
return std::pair<IfcUtil::ArgumentType,Argument*>($self->getArgumentType(i), $self->getArgument(i));
|
||||
}
|
||||
}
|
||||
|
||||
%extend IfcParse::IfcSpfHeader {
|
||||
|
||||
+10
-2
@@ -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
|
||||
|
||||
@@ -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 <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
// Conversion functions and checks to convert Python objects into STL vectors
|
||||
%{
|
||||
template <typename T> void* get_python_type();
|
||||
template <> void* get_python_type<double>() { return &PyFloat_Type; }
|
||||
#if PY_VERSION_HEX >= 0x03000000
|
||||
template <> void* get_python_type<int>() { return &PyLong_Type; }
|
||||
template <> void* get_python_type<std::string>() { return &PyUnicode_Type; }
|
||||
#else
|
||||
template <> void* get_python_type<int>() { return &PyInt_Type; }
|
||||
template <> void* get_python_type<std::string>() { 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 <typename T>
|
||||
T cast_pyobject(PyObject* element);
|
||||
|
||||
template <>
|
||||
int cast_pyobject(PyObject* element) {
|
||||
return static_cast<int>(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<IfcParse::IfcLateBoundEntity*>(0);
|
||||
return reinterpret_cast<IfcParse::IfcLateBoundEntity*>(arg);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::vector<T> python_sequence_as_vector(PyObject* aggregate) {
|
||||
std::vector<T> 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<T>(element);
|
||||
result_vector.push_back(t);
|
||||
}
|
||||
return result_vector;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::vector< std::vector<T> > python_sequence_as_vector_of_vector(PyObject* aggregate) {
|
||||
std::vector< std::vector<T> > 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> t = python_sequence_as_vector<T>(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 <typename T>
|
||||
PyObject* pythonize_vector(const std::vector<T>& 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 <typename T>
|
||||
PyObject* pythonize_vector2(const std::vector< std::vector<T> >& 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;
|
||||
}
|
||||
%}
|
||||
@@ -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 <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
%define CREATE_VECTOR_TYPEMAP_IN(template_type, express_name, python_name)
|
||||
|
||||
%typemap(in) std::vector<template_type> {
|
||||
if (!check_aggregate_of_type($input, get_python_type<template_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<template_type>($input);
|
||||
}
|
||||
|
||||
%typemap(arginit) const std::vector<template_type>& {
|
||||
$1 = new std::vector<template_type>();
|
||||
}
|
||||
%typemap(in) const std::vector<template_type>& {
|
||||
if (!check_aggregate_of_type($input, get_python_type<template_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<template_type>($input);
|
||||
}
|
||||
%typemap(freearg) const std::vector<template_type>& {
|
||||
delete $1;
|
||||
}
|
||||
|
||||
%typemap(in) std::vector< std::vector<template_type> > {
|
||||
if (!check_aggregate_of_aggregate_of_type($input, get_python_type<template_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<template_type>($input);
|
||||
}
|
||||
|
||||
%typemap(arginit) const std::vector< std::vector<template_type> >& {
|
||||
$1 = new std::vector< std::vector<template_type> >();
|
||||
}
|
||||
%typemap(in) const std::vector< std::vector<template_type> >& {
|
||||
if (!check_aggregate_of_aggregate_of_type($input, get_python_type<template_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<template_type>($input);
|
||||
}
|
||||
%typemap(freearg) const std::vector< std::vector<template_type> >& {
|
||||
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<IfcParse::IfcLateBoundEntity*>(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<IfcUtil::IfcBaseClass*> 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<IfcParse::IfcLateBoundEntity*>(element_element);
|
||||
if (inst) {
|
||||
vector.push_back(cast_pyobject<IfcParse::IfcLateBoundEntity*>(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");
|
||||
}
|
||||
}
|
||||
@@ -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<IfcUtil::ArgumentType, Argument*> {
|
||||
// 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<int>) arg);
|
||||
break;
|
||||
case IfcUtil::Argument_AGGREGATE_OF_DOUBLE:
|
||||
$result = pythonize_vector((std::vector<double>) arg);
|
||||
break;
|
||||
case IfcUtil::Argument_AGGREGATE_OF_STRING:
|
||||
$result = pythonize_vector((std::vector<std::string>) 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<int> >) arg);
|
||||
break;
|
||||
case IfcUtil::Argument_AGGREGATE_OF_AGGREGATE_OF_DOUBLE:
|
||||
$result = pythonize_vector2((std::vector< std::vector<double> >) 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<template_type> {
|
||||
$result = pythonize_vector<template_type>($1);
|
||||
}
|
||||
%typemap(out) const std::vector<template_type>& {
|
||||
$result = pythonize_vector<template_type>($1);
|
||||
}
|
||||
%enddef
|
||||
|
||||
CREATE_VECTOR_TYPEMAP_OUT(int)
|
||||
CREATE_VECTOR_TYPEMAP_OUT(double)
|
||||
CREATE_VECTOR_TYPEMAP_OUT(std::string)
|
||||
Reference in New Issue
Block a user