diff --git a/src/ifcopenshell-python/ifcopenshell/file.py b/src/ifcopenshell-python/ifcopenshell/file.py index 5157d4ae23..9eb6477273 100644 --- a/src/ifcopenshell-python/ifcopenshell/file.py +++ b/src/ifcopenshell-python/ifcopenshell/file.py @@ -391,15 +391,15 @@ class file(object): return inverses return set(inverses) - def get_inverse_cardinality(self, inst): + def get_total_inverses(self, inst): """Returns the number of entities that reference this entity :param inst: The entity instance to get inverse relationships :type inst: ifcopenshell.entity_instance.entity_instance - :returns: 0 if no references, 1 if one reference, or 2 if more than one reference + :returns: The total number of references :rtype: int """ - return self.wrapped_data.get_inverse_cardinality(inst.wrapped_data) + return self.wrapped_data.get_total_inverses(inst.wrapped_data) def remove(self, inst): """Deletes an IFC object in the file. diff --git a/src/ifcparse/IfcFile.h b/src/ifcparse/IfcFile.h index 349fb5eae0..d8ea3a47c6 100644 --- a/src/ifcparse/IfcFile.h +++ b/src/ifcparse/IfcFile.h @@ -78,6 +78,7 @@ public: typedef std::tuple inverse_attr_record; enum INVERSE_ATTR { INSTANCE_ID, INSTANCE_TYPE, ATTRIBUTE_INDEX }; typedef std::map > entities_by_ref_t; + typedef std::map > entities_by_ref_excl_t; typedef std::map ref_map_t; typedef entity_by_id_t::const_iterator const_iterator; @@ -132,7 +133,8 @@ private: entity_by_id_t byid; entities_by_type_t bytype; entities_by_type_t bytype_excl; - entities_by_ref_t byref, byref_excl; + entities_by_ref_t byref; + entities_by_ref_excl_t byref_excl; ref_map_t by_ref_cached_; entity_by_guid_t byguid; entity_entity_map_t entity_file_map; @@ -249,7 +251,7 @@ public: aggregate_of_instance::ptr traverse_breadth_first(IfcUtil::IfcBaseClass* instance, int max_level=-1); aggregate_of_instance::ptr getInverse(int instance_id, const IfcParse::declaration* type, int attribute_index); - int getInverseCardinality(int instance_id); + int getTotalInverses(int instance_id); template typename T::list::ptr getInverse(int instance_id, int attribute_index) { diff --git a/src/ifcparse/IfcParse.cpp b/src/ifcparse/IfcParse.cpp index a7f83cf557..89f8af4a0e 100644 --- a/src/ifcparse/IfcParse.cpp +++ b/src/ifcparse/IfcParse.cpp @@ -972,7 +972,7 @@ void IfcParse::IfcFile::try_read_semicolon() { void IfcParse::IfcFile::register_inverse(unsigned id_from, const IfcParse::entity* from_entity, Token t, int attribute_index) { // Assume a check on token type has already been performed auto e = from_entity; - byref_excl[{t.value_int, e->index_in_schema(), attribute_index}].push_back(id_from); + byref_excl[t.value_int].push_back(id_from); while (e) { byref[{t.value_int, e->index_in_schema(), attribute_index}].push_back(id_from); e = e->supertype(); @@ -981,7 +981,7 @@ void IfcParse::IfcFile::register_inverse(unsigned id_from, const IfcParse::entit void IfcParse::IfcFile::register_inverse(unsigned id_from, const IfcParse::entity* from_entity, IfcUtil::IfcBaseClass* inst, int attribute_index) { auto e = from_entity; - byref_excl[{inst->data().id(), e->index_in_schema(), attribute_index}].push_back(id_from); + byref_excl[inst->data().id()].push_back(id_from); while (e) { byref[{inst->data().id(), e->index_in_schema(), attribute_index}].push_back(id_from); e = e->supertype(); @@ -1002,7 +1002,7 @@ void IfcParse::IfcFile::unregister_inverse(unsigned id_from, const IfcParse::ent e = e->supertype(); } - std::vector& ids = byref_excl[{inst->data().id(), from_entity->index_in_schema(), attribute_index}]; + std::vector& ids = byref_excl[inst->data().id()]; std::vector::iterator it = std::find(ids.begin(), ids.end(), id_from); if (it == ids.end()) { // @todo inverses also need to be populated when multiple instances are added to a new file. @@ -2100,11 +2100,8 @@ void IfcFile::process_deletion_() { byref.upper_bound({ id, std::numeric_limits::max(), std::numeric_limits::max() }) ); - byref_excl.erase( - byref_excl.lower_bound({ id,-1,-1 }), - byref_excl.upper_bound({ id, std::numeric_limits::max(), std::numeric_limits::max() }) - ); - + byref_excl.erase(id); + // This is based on traversal which needs instances to still be contained in the map. // another option would be to keep byid intact for the remainder of this loop aggregate_of_instance::ptr entity_attributes = traverse(entity, 1); @@ -2124,13 +2121,7 @@ void IfcFile::process_deletion_() { } } { - auto lower = byref_excl.lower_bound({ name,-1,-1 }); - auto upper = byref_excl.upper_bound({ name, std::numeric_limits::max(), std::numeric_limits::max() }); - - for (auto byref_it = lower; byref_it != upper; ++byref_it) { - auto& ids = byref_it->second; - ids.erase(std::remove(ids.begin(), ids.end(), id), ids.end()); - } + byref_excl.erase(name); } by_ref_cached_.erase(name); } @@ -2210,7 +2201,7 @@ void IfcFile::process_deletion_() { } for (auto it = byref_excl.begin(); it != byref_excl.end();) { - bool do_delete = batch_deletion_ids_.get<1>().find(std::get(it->first)) != batch_deletion_ids_.get<1>().end(); + bool do_delete = batch_deletion_ids_.get<1>().find(it->first) != batch_deletion_ids_.get<1>().end(); if (!do_delete) { it->second.erase(std::remove_if(it->second.begin(), it->second.end(), [this](int x) { return batch_deletion_ids_.get<1>().find(x) != batch_deletion_ids_.get<1>().end(); @@ -2249,18 +2240,10 @@ aggregate_of_instance::ptr IfcFile::instances_by_type_excl_subtypes(const std::s } aggregate_of_instance::ptr IfcFile::instances_by_reference(int t) { - auto lower = byref_excl.lower_bound({ t,-1,-1 }); - auto upper = byref_excl.upper_bound({ t, std::numeric_limits::max(), std::numeric_limits::max() }); - aggregate_of_instance::ptr ret(new aggregate_of_instance); - for (auto it = lower; it != upper; it++) { - for (auto& i : it->second) { - ret->push(instance_by_id(i)); - } + for (auto& i : byref_excl[t]) { + ret->push(instance_by_id(i)); } - - by_ref_cached_[t] = ret; - return ret; } @@ -2388,21 +2371,8 @@ aggregate_of_instance::ptr IfcFile::getInverse(int instance_id, const IfcParse:: } -int IfcFile::getInverseCardinality(int instance_id) { - auto lower = byref_excl.lower_bound({ instance_id,-1,-1 }); - auto upper = byref_excl.upper_bound({ instance_id, std::numeric_limits::max(), std::numeric_limits::max() }); - - int total_references = 0; - for (auto it = lower; it != upper; it++) { - for (auto& i : it->second) { - total_references++; - if (total_references > 1) { - return total_references; - } - } - } - - return total_references; +int IfcFile::getTotalInverses(int instance_id) { + return byref_excl[instance_id].size(); } @@ -2507,7 +2477,7 @@ void IfcParse::IfcFile::build_inverses_(IfcUtil::IfcBaseClass* inst) { if (attr->declaration().as_entity()) { unsigned entity_attribute_id = attr->data().id(); auto decl = inst->declaration().as_entity(); - byref_excl[{entity_attribute_id, decl->index_in_schema(), idx}].push_back(inst->data().id()); + byref_excl[entity_attribute_id].push_back(inst->data().id()); while (decl) { byref[{entity_attribute_id, decl->index_in_schema(), idx}].push_back(inst->data().id()); decl = decl->supertype(); diff --git a/src/ifcwrap/IfcParseWrapper.i b/src/ifcwrap/IfcParseWrapper.i index 728374215a..ec19a2844a 100644 --- a/src/ifcwrap/IfcParseWrapper.i +++ b/src/ifcwrap/IfcParseWrapper.i @@ -88,8 +88,8 @@ static IfcUtil::ArgumentType helper_fn_attribute_type(const IfcUtil::IfcBaseClas aggregate_of_instance::ptr get_inverse(IfcUtil::IfcBaseClass* e) { return $self->getInverse(e->data().id(), 0, -1); } - int get_inverse_cardinality(IfcUtil::IfcBaseClass* e) { - return $self->getInverseCardinality(e->data().id()); + int get_total_inverses(IfcUtil::IfcBaseClass* e) { + return $self->getTotalInverses(e->data().id()); } void write(const std::string& fn) {