mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-10-03 05:22:06 +00:00
#2408 ifcopenshell.file.get_inverse(with_attribute_indices)
This commit is contained in:
@@ -377,17 +377,29 @@ class file(object):
|
|||||||
|
|
||||||
return [entity_instance(e, self) for e in fn(inst.wrapped_data, max_levels)]
|
return [entity_instance(e, self) for e in fn(inst.wrapped_data, max_levels)]
|
||||||
|
|
||||||
def get_inverse(self, inst, allow_duplicate=False):
|
def get_inverse(self, inst, allow_duplicate=False, with_attribute_indices=False):
|
||||||
"""Return a list of entities that reference this entity
|
"""Return a list 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
|
||||||
|
:param allow_duplicate: Returns a `list` when True, `set` when False
|
||||||
|
:param with_attribute_indices: Returns pairs of <i, idx>
|
||||||
|
where i[idx] is inst or contains inst. Requires allow_duplicate=True
|
||||||
:returns: A list of ifcopenshell.entity_instance.entity_instance objects
|
:returns: A list of ifcopenshell.entity_instance.entity_instance objects
|
||||||
:rtype: list
|
:rtype: list
|
||||||
"""
|
"""
|
||||||
|
if with_attribute_indices and not allow_duplicate:
|
||||||
|
raise ValueError("with_attribute_indices requires allow_duplicate to be True")
|
||||||
|
|
||||||
inverses = [entity_instance(e, self) for e in self.wrapped_data.get_inverse(inst.wrapped_data)]
|
inverses = [entity_instance(e, self) for e in self.wrapped_data.get_inverse(inst.wrapped_data)]
|
||||||
|
|
||||||
if allow_duplicate:
|
if allow_duplicate:
|
||||||
|
if with_attribute_indices:
|
||||||
|
idxs = self.wrapped_data.get_inverse_indices(inst.wrapped_data)
|
||||||
|
return list(zip(inverses, idxs))
|
||||||
|
else:
|
||||||
return inverses
|
return inverses
|
||||||
|
|
||||||
return set(inverses)
|
return set(inverses)
|
||||||
|
|
||||||
def get_total_inverses(self, inst):
|
def get_total_inverses(self, inst):
|
||||||
|
|||||||
@@ -252,7 +252,12 @@ public:
|
|||||||
/// breadth-first search
|
/// breadth-first search
|
||||||
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);
|
||||||
|
|
||||||
|
/// Get the attribute indices corresponding to the list of entity instances
|
||||||
|
/// returned by getInverse().
|
||||||
|
std::vector<int> get_inverse_indices(int instance_id);
|
||||||
|
|
||||||
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 getTotalInverses(int instance_id);
|
int getTotalInverses(int instance_id);
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
|
|||||||
@@ -2428,6 +2428,47 @@ std::string IfcFile::createTimestamp() const {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<int> IfcFile::get_inverse_indices(int instance_id) {
|
||||||
|
std::vector<int> return_value;
|
||||||
|
|
||||||
|
auto lower = byref.lower_bound({ instance_id, -1, -1 });
|
||||||
|
auto upper = byref.upper_bound({ instance_id, std::numeric_limits<int>::max(), std::numeric_limits<int>::max() });
|
||||||
|
|
||||||
|
// Mapping of instance id to attribute offset.
|
||||||
|
std::map<int, std::vector<int>> mapping;
|
||||||
|
|
||||||
|
for (auto it = lower; it != upper; ++it) {
|
||||||
|
for (auto& i : it->second) {
|
||||||
|
// We only take the tuple for the type that id=i actually is, in order not
|
||||||
|
// to count double. Because byref contains mappings for every supertype of id=i.
|
||||||
|
if (instance_by_id(i)->declaration().index_in_schema() == std::get<1>(it->first)) {
|
||||||
|
mapping[i].push_back(std::get<2>(it->first));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto refs = instances_by_reference(instance_id);
|
||||||
|
|
||||||
|
for (auto& r : *refs) {
|
||||||
|
auto it = mapping.find(r->data().id());
|
||||||
|
if (it == mapping.end() || it->second.empty()) {
|
||||||
|
throw IfcException("Internal error");
|
||||||
|
}
|
||||||
|
return_value.push_back(it->second.front());
|
||||||
|
it->second.erase(it->second.begin());
|
||||||
|
if (it->second.empty()) {
|
||||||
|
mapping.erase(it);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test whether all mappings where indeed used.
|
||||||
|
if (!mapping.empty()) {
|
||||||
|
throw IfcException("Internal error");
|
||||||
|
}
|
||||||
|
|
||||||
|
return return_value;
|
||||||
|
}
|
||||||
|
|
||||||
aggregate_of_instance::ptr IfcFile::getInverse(int instance_id, const IfcParse::declaration* type, int attribute_index) {
|
aggregate_of_instance::ptr IfcFile::getInverse(int instance_id, const IfcParse::declaration* type, int attribute_index) {
|
||||||
if (type == nullptr && attribute_index == -1) {
|
if (type == nullptr && attribute_index == -1) {
|
||||||
return instances_by_reference(instance_id);
|
return instances_by_reference(instance_id);
|
||||||
|
|||||||
@@ -85,9 +85,15 @@ static IfcUtil::ArgumentType helper_fn_attribute_type(const IfcUtil::IfcBaseClas
|
|||||||
IfcUtil::IfcBaseClass* by_guid(const std::string& guid) {
|
IfcUtil::IfcBaseClass* by_guid(const std::string& guid) {
|
||||||
return $self->instance_by_guid(guid);
|
return $self->instance_by_guid(guid);
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<int> get_inverse_indices(IfcUtil::IfcBaseClass* e) {
|
||||||
|
return $self->get_inverse_indices(e->data().id());
|
||||||
|
}
|
||||||
|
|
||||||
int get_total_inverses(IfcUtil::IfcBaseClass* e) {
|
int get_total_inverses(IfcUtil::IfcBaseClass* e) {
|
||||||
return $self->getTotalInverses(e->data().id());
|
return $self->getTotalInverses(e->data().id());
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user