mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-28 15:53:00 +00:00
get_total_inverses now efficiently gets the full number of references to an entity
This commit is contained in:
committed by
Thomas Krijnen
parent
cef1c86f6d
commit
5ad6d455f9
@@ -391,15 +391,15 @@ class file(object):
|
|||||||
return inverses
|
return inverses
|
||||||
return set(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
|
"""Returns the number of entities that reference this entity
|
||||||
|
|
||||||
:param inst: The entity instance to get inverse relationships
|
:param inst: The entity instance to get inverse relationships
|
||||||
:type inst: ifcopenshell.entity_instance.entity_instance
|
: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
|
: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):
|
def remove(self, inst):
|
||||||
"""Deletes an IFC object in the file.
|
"""Deletes an IFC object in the file.
|
||||||
|
|||||||
@@ -78,6 +78,7 @@ public:
|
|||||||
typedef std::tuple<int, int, int> inverse_attr_record;
|
typedef std::tuple<int, int, int> inverse_attr_record;
|
||||||
enum INVERSE_ATTR { INSTANCE_ID, INSTANCE_TYPE, ATTRIBUTE_INDEX };
|
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<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 std::map<unsigned int, aggregate_of_instance::ptr> ref_map_t;
|
||||||
typedef entity_by_id_t::const_iterator const_iterator;
|
typedef entity_by_id_t::const_iterator const_iterator;
|
||||||
|
|
||||||
@@ -132,7 +133,8 @@ private:
|
|||||||
entity_by_id_t byid;
|
entity_by_id_t byid;
|
||||||
entities_by_type_t bytype;
|
entities_by_type_t bytype;
|
||||||
entities_by_type_t bytype_excl;
|
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_;
|
ref_map_t by_ref_cached_;
|
||||||
entity_by_guid_t byguid;
|
entity_by_guid_t byguid;
|
||||||
entity_entity_map_t entity_file_map;
|
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 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);
|
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>
|
template <class T>
|
||||||
typename T::list::ptr getInverse(int instance_id, int attribute_index) {
|
typename T::list::ptr getInverse(int instance_id, int attribute_index) {
|
||||||
|
|||||||
+12
-42
@@ -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) {
|
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
|
// Assume a check on token type has already been performed
|
||||||
auto e = from_entity;
|
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) {
|
while (e) {
|
||||||
byref[{t.value_int, e->index_in_schema(), attribute_index}].push_back(id_from);
|
byref[{t.value_int, e->index_in_schema(), attribute_index}].push_back(id_from);
|
||||||
e = e->supertype();
|
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) {
|
void IfcParse::IfcFile::register_inverse(unsigned id_from, const IfcParse::entity* from_entity, IfcUtil::IfcBaseClass* inst, int attribute_index) {
|
||||||
auto e = from_entity;
|
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) {
|
while (e) {
|
||||||
byref[{inst->data().id(), e->index_in_schema(), attribute_index}].push_back(id_from);
|
byref[{inst->data().id(), e->index_in_schema(), attribute_index}].push_back(id_from);
|
||||||
e = e->supertype();
|
e = e->supertype();
|
||||||
@@ -1002,7 +1002,7 @@ void IfcParse::IfcFile::unregister_inverse(unsigned id_from, const IfcParse::ent
|
|||||||
e = e->supertype();
|
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);
|
std::vector<int>::iterator it = std::find(ids.begin(), ids.end(), id_from);
|
||||||
if (it == ids.end()) {
|
if (it == ids.end()) {
|
||||||
// @todo inverses also need to be populated when multiple instances are added to a new file.
|
// @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.upper_bound({ id, std::numeric_limits<int>::max(), std::numeric_limits<int>::max() })
|
||||||
);
|
);
|
||||||
|
|
||||||
byref_excl.erase(
|
byref_excl.erase(id);
|
||||||
byref_excl.lower_bound({ id,-1,-1 }),
|
|
||||||
byref_excl.upper_bound({ id, std::numeric_limits<int>::max(), std::numeric_limits<int>::max() })
|
|
||||||
);
|
|
||||||
|
|
||||||
// This is based on traversal which needs instances to still be contained in the map.
|
// 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
|
// another option would be to keep byid intact for the remainder of this loop
|
||||||
aggregate_of_instance::ptr entity_attributes = traverse(entity, 1);
|
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 });
|
byref_excl.erase(name);
|
||||||
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());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
by_ref_cached_.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();) {
|
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) {
|
if (!do_delete) {
|
||||||
it->second.erase(std::remove_if(it->second.begin(), it->second.end(), [this](int x) {
|
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();
|
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) {
|
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);
|
aggregate_of_instance::ptr ret(new aggregate_of_instance);
|
||||||
for (auto it = lower; it != upper; it++) {
|
for (auto& i : byref_excl[t]) {
|
||||||
for (auto& i : it->second) {
|
ret->push(instance_by_id(i));
|
||||||
ret->push(instance_by_id(i));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
by_ref_cached_[t] = ret;
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2388,21 +2371,8 @@ aggregate_of_instance::ptr IfcFile::getInverse(int instance_id, const IfcParse::
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int IfcFile::getInverseCardinality(int instance_id) {
|
int IfcFile::getTotalInverses(int instance_id) {
|
||||||
auto lower = byref_excl.lower_bound({ instance_id,-1,-1 });
|
return byref_excl[instance_id].size();
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -2507,7 +2477,7 @@ void IfcParse::IfcFile::build_inverses_(IfcUtil::IfcBaseClass* inst) {
|
|||||||
if (attr->declaration().as_entity()) {
|
if (attr->declaration().as_entity()) {
|
||||||
unsigned entity_attribute_id = attr->data().id();
|
unsigned entity_attribute_id = attr->data().id();
|
||||||
auto decl = inst->declaration().as_entity();
|
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) {
|
while (decl) {
|
||||||
byref[{entity_attribute_id, decl->index_in_schema(), idx}].push_back(inst->data().id());
|
byref[{entity_attribute_id, decl->index_in_schema(), idx}].push_back(inst->data().id());
|
||||||
decl = decl->supertype();
|
decl = decl->supertype();
|
||||||
|
|||||||
@@ -88,8 +88,8 @@ static IfcUtil::ArgumentType helper_fn_attribute_type(const IfcUtil::IfcBaseClas
|
|||||||
aggregate_of_instance::ptr get_inverse(IfcUtil::IfcBaseClass* e) {
|
aggregate_of_instance::ptr get_inverse(IfcUtil::IfcBaseClass* e) {
|
||||||
return $self->getInverse(e->data().id(), 0, -1);
|
return $self->getInverse(e->data().id(), 0, -1);
|
||||||
}
|
}
|
||||||
int get_inverse_cardinality(IfcUtil::IfcBaseClass* e) {
|
int get_total_inverses(IfcUtil::IfcBaseClass* e) {
|
||||||
return $self->getInverseCardinality(e->data().id());
|
return $self->getTotalInverses(e->data().id());
|
||||||
}
|
}
|
||||||
|
|
||||||
void write(const std::string& fn) {
|
void write(const std::string& fn) {
|
||||||
|
|||||||
Reference in New Issue
Block a user