get_total_inverses now efficiently gets the full number of references to an entity

This commit is contained in:
Dion Moult
2021-12-01 15:05:00 +11:00
committed by Thomas Krijnen
parent cef1c86f6d
commit 5ad6d455f9
4 changed files with 21 additions and 49 deletions
+3 -3
View File
@@ -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.
+4 -2
View File
@@ -78,6 +78,7 @@ public:
typedef std::tuple<int, int, int> inverse_attr_record;
enum INVERSE_ATTR { INSTANCE_ID, INSTANCE_TYPE, ATTRIBUTE_INDEX };
typedef std::map<inverse_attr_record, std::vector<int> > entities_by_ref_t;
typedef std::map<int, std::vector<int> > entities_by_ref_excl_t;
typedef std::map<unsigned int, aggregate_of_instance::ptr> 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 <class T>
typename T::list::ptr getInverse(int instance_id, int attribute_index) {
+12 -42
View File
@@ -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<int>& ids = byref_excl[{inst->data().id(), from_entity->index_in_schema(), attribute_index}];
std::vector<int>& ids = byref_excl[inst->data().id()];
std::vector<int>::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<int>::max(), std::numeric_limits<int>::max() })
);
byref_excl.erase(
byref_excl.lower_bound({ id,-1,-1 }),
byref_excl.upper_bound({ id, std::numeric_limits<int>::max(), std::numeric_limits<int>::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<int>::max(), std::numeric_limits<int>::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<INSTANCE_ID>(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<int>::max(), std::numeric_limits<int>::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<int>::max(), std::numeric_limits<int>::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();
+2 -2
View File
@@ -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) {