/******************************************************************************** * * * 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 . * * * ********************************************************************************/ // A class declaration to silence SWIG warning about base classes being // undefined, the constructor is private so that SWIG does not wrap them class IfcEntityInstanceData { private: IfcEntityInstanceData(); }; %ignore IfcParse::IfcFile::register_inverse; %ignore IfcParse::IfcFile::unregister_inverse; %ignore IfcParse::IfcFile::schema; %ignore IfcParse::IfcFile::begin; %ignore IfcParse::IfcFile::end; %ignore parse_context; %ignore operator<<; %ignore IfcParse::FileDescription::FileDescription; %ignore IfcParse::FileName::FileName; %ignore IfcParse::FileSchema::FileSchema; %ignore IfcParse::IfcFile::tokens; %ignore IfcParse::IfcSpfHeader::IfcSpfHeader(IfcSpfLexer*); %ignore IfcParse::IfcSpfHeader::lexer; %ignore IfcParse::IfcSpfHeader::stream; %ignore IfcParse::HeaderEntity::is; %ignore IfcParse::IfcFile::type_iterator; %ignore IfcUtil::IfcBaseClass::is; %rename("by_id") instance_by_id; %rename("by_type") instances_by_type; %rename("by_type_excl_subtypes") instances_by_type_excl_subtypes; %rename("entity_instance") IfcBaseClass; %rename("file") IfcFile; %rename("add") addEntity; %rename("remove") removeEntity; class attribute_value_derived {}; %{ class attribute_value_derived {}; %} %extend attribute_value_derived { %pythoncode %{ def __bool__(self): return False def __repr__(self): return '*' %} } %inline %{ static bool feature_use_attribute_value_derived = false; void set_feature(const std::string& x, PyObject* v) { if (PyBool_Check(v) && x == "use_attribute_value_derived") { feature_use_attribute_value_derived = v == Py_True; } else { throw std::runtime_error("Invalid feature specification"); } } PyObject* get_feature(const std::string& x) { if (x == "use_attribute_value_derived") { return PyBool_FromLong(feature_use_attribute_value_derived); } else { throw std::runtime_error("Invalid feature specification"); } } %} %{ static const std::string& helper_fn_declaration_get_name(const IfcParse::declaration* decl) { return decl->name(); } static IfcUtil::ArgumentType helper_fn_attribute_type(const IfcUtil::IfcBaseClass* inst, unsigned i) { const IfcParse::parameter_type* pt = 0; if (inst->declaration().as_entity()) { pt = inst->declaration().as_entity()->attribute_by_index(i)->type_of_attribute(); if (inst->declaration().as_entity()->derived()[i]) { return IfcUtil::Argument_DERIVED; } } else if (inst->declaration().as_type_declaration() && i == 0) { pt = inst->declaration().as_type_declaration()->declared_type(); } else if (inst->declaration().as_enumeration_type() && i == 0) { // Enumeration is always from string in Python return IfcUtil::Argument_STRING; } if (pt == 0) { return IfcUtil::Argument_UNKNOWN; } else { return IfcUtil::from_parameter_type(pt); } } %} %extend IfcParse::IfcFile { // Use to correlate to entity_instance.file_pointer, so that we // can trace file ownership of instances on the python side. size_t file_pointer() const { return reinterpret_cast($self); } IfcUtil::IfcBaseClass* by_guid(const std::string& guid) { return $self->instance_by_guid(guid); } aggregate_of_instance::ptr get_inverse(IfcUtil::IfcBaseClass* e) { return $self->getInverse(e->as()->id(), 0, -1); } std::vector get_inverse_indices(IfcUtil::IfcBaseClass* e) { return $self->get_inverse_indices(e->as()->id()); } int get_total_inverses(IfcUtil::IfcBaseClass* e) { return $self->getTotalInverses(e->as()->id()); } void write(const std::string& fn) { std::ofstream f(IfcUtil::path::from_utf8(fn).c_str()); f << (*$self); } std::string to_string() { std::stringstream s; s << (*$self); return s.str(); } std::vector entity_names() const { std::vector keys; keys.reserve(std::distance($self->begin(), $self->end())); for (IfcParse::IfcFile::entity_by_id_t::const_iterator it = $self->begin(); it != $self->end(); ++ it) { keys.push_back(it->first); } return keys; } std::vector types() const { const size_t n = std::distance($self->types_begin(), $self->types_end()); std::vector ts; ts.reserve(n); std::transform($self->types_begin(), $self->types_end(), std::back_inserter(ts), helper_fn_declaration_get_name); return ts; } /* std::vector types_with_super() const { const size_t n = std::distance($self->types_incl_super_begin(), $self->types_incl_super_end()); std::vector ts; ts.reserve(n); std::transform($self->types_incl_super_begin(), $self->types_incl_super_end(), std::back_inserter(ts), helper_fn_declaration_get_name); return ts; } */ std::string schema_name() const { if ($self->schema() == 0) return ""; return $self->schema()->name(); } %pythoncode %{ # Hide the getters with read-only property implementations header = property(header) schema = property(schema_name) %} } %extend IfcUtil::IfcBaseClass { int get_attribute_category(const std::string& name) const { if (!$self->declaration().as_entity()) { return name == "wrappedValue"; } { const std::vector attrs = $self->declaration().as_entity()->all_attributes(); std::vector::const_iterator it = attrs.begin(); for (; it != attrs.end(); ++it) { if ((*it)->name() == name) { return 1; } } } { const std::vector attrs = $self->declaration().as_entity()->all_inverse_attributes(); std::vector::const_iterator it = attrs.begin(); for (; it != attrs.end(); ++it) { if ((*it)->name() == name) { return 2; } } } return 0; } // id() is defined on IfcBaseEntity and not on IfcBaseClass, in order // to expose it to the Python wrapper it is simply duplicated here. // Same applies to the two methods reimplemented below. int id() const { return $self->as() != nullptr ? $self->as()->id() : 0; } int __len__() const { if ($self->declaration().as_entity()) { return $self->declaration().as_entity()->attribute_count(); } else { return 1; } } std::vector get_attribute_names() const { if (!$self->declaration().as_entity()) { return std::vector(1, "wrappedValue"); } const std::vector attrs = $self->declaration().as_entity()->all_attributes(); std::vector attr_names; attr_names.reserve(attrs.size()); std::vector::const_iterator it = attrs.begin(); for (; it != attrs.end(); ++it) { attr_names.push_back((*it)->name()); } return attr_names; } std::vector get_inverse_attribute_names() const { if (!$self->declaration().as_entity()) { return std::vector(0); } const std::vector attrs = $self->declaration().as_entity()->all_inverse_attributes(); std::vector attr_names; attr_names.reserve(attrs.size()); std::vector::const_iterator it = attrs.begin(); for (; it != attrs.end(); ++it) { attr_names.push_back((*it)->name()); } return attr_names; } bool is_a(const std::string& s) { return self->declaration().is(s); } std::string is_a(bool with_schema=false) const { auto t = self->declaration().name(); if (with_schema) { t = self->declaration().schema()->name() + "." + t; } return t; } AttributeValue get_argument(unsigned i) { return $self->data().get_attribute_value(i); } AttributeValue get_argument(const std::string& a) { auto i = $self->declaration().as_entity()->attribute_index(a); if (i == -1) { throw std::runtime_error("Attribute '" + a + "' not found on entity named " + $self->declaration().name()); } return $self->data().get_attribute_value((unsigned)i); } bool __eq__(IfcUtil::IfcBaseClass* other) const { return $self->identity() == other->identity(); } std::string __repr__() const { std::ostringstream oss; $self->toString(oss); return oss.str(); } std::string to_string(bool valid_spf) const { std::ostringstream oss; $self->toString(oss, valid_spf); return oss.str(); } // Just something to have a somewhat sensible value to hash size_t file_pointer() const { return reinterpret_cast($self->file_); } unsigned get_argument_index(const std::string& a) const { if ($self->declaration().as_entity()) { return $self->declaration().as_entity()->attribute_index(a); } else if (a == "wrappedValue") { return 0; } else { throw IfcParse::IfcException(a + " not found on " + $self->declaration().name()); } } aggregate_of_instance::ptr get_inverse(const std::string& a) { if ($self->declaration().as_entity()) { return ((IfcUtil::IfcBaseEntity*)$self)->get_inverse(a); } else { throw IfcParse::IfcException(a + " not found on " + $self->declaration().name()); } } const char* const get_argument_type(unsigned int i) const { return IfcUtil::ArgumentTypeToString(helper_fn_attribute_type($self, i)); } const std::string& get_argument_name(unsigned int i) const { if ($self->declaration().as_entity()) { return $self->declaration().as_entity()->attribute_by_index(i)->name(); } else if (i == 0) { static std::string WRAPPED = "wrappedValue"; return WRAPPED; } else { throw IfcParse::IfcException(boost::lexical_cast(i) + " out of bounds on " + $self->declaration().name()); } } void setArgumentAsNull(unsigned int i) { bool is_optional = $self->declaration().as_entity()->attribute_by_index(i)->optional(); if (is_optional) { self->set_attribute_value(i, Blank{}); } else { throw IfcParse::IfcException("Attribute not set"); } } void setArgumentAsInt(unsigned int i, int v) { IfcUtil::ArgumentType arg_type = helper_fn_attribute_type($self, i); if (arg_type == IfcUtil::Argument_INT) { self->set_attribute_value(i, v); } else if ( (arg_type == IfcUtil::Argument_BOOL) && ( (v == 0) || (v == 1) ) ) { self->set_attribute_value(i, v); } else { throw IfcParse::IfcException("Attribute not set"); } } void setArgumentAsBool(unsigned int i, bool v) { IfcUtil::ArgumentType arg_type = helper_fn_attribute_type($self, i); if (arg_type == IfcUtil::Argument_BOOL) { self->set_attribute_value(i, v); } else { throw IfcParse::IfcException("Attribute not set"); } } void setArgumentAsLogical(unsigned int i, boost::logic::tribool v) { IfcUtil::ArgumentType arg_type = helper_fn_attribute_type($self, i); if (arg_type == IfcUtil::Argument_LOGICAL) { self->set_attribute_value(i, v); } else { throw IfcParse::IfcException("Attribute not set"); } } void setArgumentAsDouble(unsigned int i, double v) { IfcUtil::ArgumentType arg_type = helper_fn_attribute_type($self, i); if (arg_type == IfcUtil::Argument_DOUBLE) { self->set_attribute_value(i, v); } else { throw IfcParse::IfcException("Attribute not set"); } } void setArgumentAsString(unsigned int i, const std::string& a) { IfcUtil::ArgumentType arg_type = helper_fn_attribute_type($self, i); if (arg_type == IfcUtil::Argument_STRING) { self->set_attribute_value(i, a); } else if (arg_type == IfcUtil::Argument_ENUMERATION) { const IfcParse::enumeration_type* enum_type = $self->declaration().schema()->declaration_by_name($self->declaration().type())->as_entity()-> attribute_by_index(i)->type_of_attribute()->as_named_type()->declared_type()->as_enumeration_type(); self->set_attribute_value(i, EnumerationReference(enum_type, enum_type->lookup_enum_offset(a))); } else if (arg_type == IfcUtil::Argument_BINARY) { if (IfcUtil::valid_binary_string(a)) { boost::dynamic_bitset<> bits(a); self->set_attribute_value(i, bits); } else { throw IfcParse::IfcException("String not a valid binary representation"); } } else { throw IfcParse::IfcException("Attribute not set"); } } void setArgumentAsAggregateOfInt(unsigned int i, const std::vector& v) { IfcUtil::ArgumentType arg_type = helper_fn_attribute_type($self, i); if (arg_type == IfcUtil::Argument_AGGREGATE_OF_INT) { self->set_attribute_value(i, v); } else { throw IfcParse::IfcException("Attribute not set"); } } void setArgumentAsAggregateOfDouble(unsigned int i, const std::vector& v) { IfcUtil::ArgumentType arg_type = helper_fn_attribute_type($self, i); if (arg_type == IfcUtil::Argument_AGGREGATE_OF_DOUBLE) { self->set_attribute_value(i, v); } else { throw IfcParse::IfcException("Attribute not set"); } } void setArgumentAsAggregateOfString(unsigned int i, const std::vector& v) { IfcUtil::ArgumentType arg_type = helper_fn_attribute_type($self, i); if (arg_type == IfcUtil::Argument_AGGREGATE_OF_STRING) { self->set_attribute_value(i, v); } else if (arg_type == IfcUtil::Argument_AGGREGATE_OF_BINARY) { std::vector< boost::dynamic_bitset<> > bits; bits.reserve(v.size()); for (std::vector::const_iterator it = v.begin(); it != v.end(); ++it) { if (IfcUtil::valid_binary_string(*it)) { bits.push_back(boost::dynamic_bitset<>(*it)); } else { throw IfcParse::IfcException("String not a valid binary representation"); } } self->set_attribute_value(i, bits); } else { throw IfcParse::IfcException("Attribute not set"); } } void setArgumentAsEntityInstance(unsigned int i, IfcUtil::IfcBaseClass* v) { IfcUtil::ArgumentType arg_type = helper_fn_attribute_type($self, i); if (arg_type == IfcUtil::Argument_ENTITY_INSTANCE) { self->set_attribute_value(i, v); } else { throw IfcParse::IfcException("Attribute not set"); } } void setArgumentAsAggregateOfEntityInstance(unsigned int i, aggregate_of_instance::ptr v) { IfcUtil::ArgumentType arg_type = helper_fn_attribute_type($self, i); if (arg_type == IfcUtil::Argument_AGGREGATE_OF_ENTITY_INSTANCE) { self->set_attribute_value(i, v); } else { throw IfcParse::IfcException("Attribute not set"); } } void setArgumentAsAggregateOfAggregateOfInt(unsigned int i, const std::vector< std::vector >& v) { IfcUtil::ArgumentType arg_type = helper_fn_attribute_type($self, i); if (arg_type == IfcUtil::Argument_AGGREGATE_OF_AGGREGATE_OF_INT) { self->set_attribute_value(i, v); } else { throw IfcParse::IfcException("Attribute not set"); } } void setArgumentAsAggregateOfAggregateOfDouble(unsigned int i, const std::vector< std::vector >& v) { IfcUtil::ArgumentType arg_type = helper_fn_attribute_type($self, i); if (arg_type == IfcUtil::Argument_AGGREGATE_OF_AGGREGATE_OF_DOUBLE) { self->set_attribute_value(i, v); } else { throw IfcParse::IfcException("Attribute not set"); } } void setArgumentAsAggregateOfAggregateOfEntityInstance(unsigned int i, aggregate_of_aggregate_of_instance::ptr v) { IfcUtil::ArgumentType arg_type = helper_fn_attribute_type($self, i); if (arg_type == IfcUtil::Argument_AGGREGATE_OF_AGGREGATE_OF_ENTITY_INSTANCE) { self->set_attribute_value(i, v); } else { throw IfcParse::IfcException("Attribute not set"); } } } // Expose FileDescription and FileName header entities // to make them readable even if they were not filled properly before. // Though it is invalid IFC, technically. // FileSchema is not exposed as IFC file won't load if it's invalid. %extend IfcParse::FileDescription { AttributeValue description() const { return $self->getArgument(0); } AttributeValue implementation_level() const { return $self->getArgument(1); } }; %extend IfcParse::FileName { AttributeValue name() const { return $self->getArgument(0); } AttributeValue time_stamp() const { return $self->getArgument(1); } AttributeValue author() const { return $self->getArgument(2); } AttributeValue organization() const { return $self->getArgument(3); } AttributeValue preprocessor_version() const { return $self->getArgument(4); } AttributeValue originating_system() const { return $self->getArgument(5); } AttributeValue authorization() const { return $self->getArgument(6); } }; %extend IfcParse::IfcSpfHeader { %pythoncode %{ # Hide the getters with read-only property implementations file_description = property(file_description) file_name = property(file_name) file_schema = property(file_schema) %} }; %extend IfcParse::FileDescription { %pythoncode %{ # Hide the getters with read-write property implementations description = property(description, description) implementation_level = property(implementation_level, implementation_level) %} }; %extend IfcParse::FileName { %pythoncode %{ name = property(name, name) time_stamp = property(time_stamp, time_stamp) author = property(author, author) organization = property(organization, organization) preprocessor_version = property(preprocessor_version, preprocessor_version) originating_system = property(originating_system, originating_system) authorization = property(authorization, authorization) %} }; %extend IfcParse::FileSchema { %pythoncode %{ # Hide the getters with read-write property implementations schema_identifiers = property(schema_identifiers, schema_identifiers) %} }; %include "../ifcparse/ifc_parse_api.h" %include "../ifcparse/IfcSpfHeader.h" %include "../ifcparse/IfcFile.h" %include "../ifcparse/IfcBaseClass.h" %include "../ifcparse/IfcSchema.h" // The IfcFile* returned by open() is to be freed by SWIG/Python %newobject open; %newobject read; %newobject parse_ifcxml; %inline %{ IfcParse::IfcFile* open(const std::string& fn) { IfcParse::IfcFile* f; Py_BEGIN_ALLOW_THREADS; f = new IfcParse::IfcFile(fn); Py_END_ALLOW_THREADS; return f; } IfcParse::IfcFile* read(const std::string& data) { char* copiedData = new char[data.length()]; memcpy(copiedData, data.c_str(), data.length()); IfcParse::IfcFile* f; Py_BEGIN_ALLOW_THREADS; f = new IfcParse::IfcFile((void *)copiedData, data.length()); Py_END_ALLOW_THREADS; return f; } const char* version() { return IFCOPENSHELL_VERSION; } IfcUtil::IfcBaseClass* new_IfcBaseClass(const std::string& schema_identifier, const std::string& name) { const IfcParse::schema_definition* schema = IfcParse::schema_by_name(schema_identifier); const IfcParse::declaration* decl = schema->declaration_by_name(name); IfcEntityInstanceData data(storage_t(decl->as_entity() ? decl->as_entity()->attribute_count() : 1)); auto inst = schema->instantiate(decl, std::move(data)); if (auto entinst = inst->as()) { entinst->populate_derived(); } return inst; } %} %extend IfcParse::named_type { %pythoncode %{ def __repr__(self): return repr(self.declared_type()) %} } %extend IfcParse::simple_type { %pythoncode %{ def __repr__(self): return "<%s>" % self.declared_type() %} } %extend IfcParse::aggregation_type { std::string type_of_aggregation_string() const { static const char* const aggr_strings[] = {"array", "bag", "list", "set"}; return aggr_strings[(int) $self->type_of_aggregation()]; } %pythoncode %{ def __repr__(self): format_bound = lambda i: "?" if i == -1 else str(i) return "<%s [%s:%s] of %r>" % ( self.type_of_aggregation_string(), format_bound(self.bound1()), format_bound(self.bound2()), self.type_of_element() ) %} } %extend IfcParse::type_declaration { %pythoncode %{ def __repr__(self): return "" % (self.name(), self.declared_type()) %} std::vector argument_types() { std::vector r; auto at = IfcUtil::Argument_UNKNOWN; auto pt = $self->declared_type(); if (pt) { at = IfcUtil::from_parameter_type(pt); } r.push_back(IfcUtil::ArgumentTypeToString(at)); return r; } } %extend IfcParse::select_type { %pythoncode %{ def __repr__(self): return "