From cef1c86f6d4f85c9a8f6329b6bcef5e2e15b73b2 Mon Sep 17 00:00:00 2001 From: Dion Moult Date: Tue, 30 Nov 2021 13:25:02 +1100 Subject: [PATCH] Experimental get_inverse_cardinality proposal. See #1904. --- src/ifcopenshell-python/ifcopenshell/file.py | 10 ++++++++++ src/ifcparse/IfcFile.h | 1 + src/ifcparse/IfcParse.cpp | 19 +++++++++++++++++++ src/ifcwrap/IfcParseWrapper.i | 3 +++ 4 files changed, 33 insertions(+) diff --git a/src/ifcopenshell-python/ifcopenshell/file.py b/src/ifcopenshell-python/ifcopenshell/file.py index d34086c175..5157d4ae23 100644 --- a/src/ifcopenshell-python/ifcopenshell/file.py +++ b/src/ifcopenshell-python/ifcopenshell/file.py @@ -391,6 +391,16 @@ class file(object): return inverses return set(inverses) + def get_inverse_cardinality(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 + :rtype: int + """ + return self.wrapped_data.get_inverse_cardinality(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 f4377e62db..349fb5eae0 100644 --- a/src/ifcparse/IfcFile.h +++ b/src/ifcparse/IfcFile.h @@ -249,6 +249,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); 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 0aaff497b0..a7f83cf557 100644 --- a/src/ifcparse/IfcParse.cpp +++ b/src/ifcparse/IfcParse.cpp @@ -2387,6 +2387,25 @@ aggregate_of_instance::ptr IfcFile::getInverse(int instance_id, const IfcParse:: return return_value; } + +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; +} + + void IfcFile::setDefaultHeaderValues() { const std::string empty_string = ""; std::vector file_description, schema_identifiers, empty_vector; diff --git a/src/ifcwrap/IfcParseWrapper.i b/src/ifcwrap/IfcParseWrapper.i index 93fc951475..728374215a 100644 --- a/src/ifcwrap/IfcParseWrapper.i +++ b/src/ifcwrap/IfcParseWrapper.i @@ -88,6 +88,9 @@ 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()); + } void write(const std::string& fn) { std::ofstream f(IfcUtil::path::from_utf8(fn).c_str());