mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-26 02:07:36 +00:00
#1674 store inverse references as tuple of (id type index)
This commit is contained in:
+19
-5
@@ -74,7 +74,9 @@ public:
|
|||||||
typedef std::map<const IfcParse::declaration*, aggregate_of_instance::ptr> entities_by_type_t;
|
typedef std::map<const IfcParse::declaration*, aggregate_of_instance::ptr> entities_by_type_t;
|
||||||
typedef boost::unordered_map<unsigned int, IfcUtil::IfcBaseClass*> entity_by_id_t;
|
typedef boost::unordered_map<unsigned int, IfcUtil::IfcBaseClass*> entity_by_id_t;
|
||||||
typedef std::map<std::string, IfcUtil::IfcBaseClass*> entity_by_guid_t;
|
typedef std::map<std::string, IfcUtil::IfcBaseClass*> entity_by_guid_t;
|
||||||
typedef std::map<unsigned int, std::vector<unsigned int> > entities_by_ref_t;
|
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<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;
|
||||||
|
|
||||||
@@ -239,6 +241,18 @@ public:
|
|||||||
|
|
||||||
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);
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
typename T::list::ptr getInverse(int instance_id, int attribute_index) {
|
||||||
|
aggregate_of_instance::ptr return_value(new aggregate_of_instance);
|
||||||
|
auto it = byref.find({ instance_id, T::Class().index_in_schema(), attribute_index });
|
||||||
|
if (it != byref.end()) {
|
||||||
|
for (auto& i : it->second) {
|
||||||
|
return_value->push((T*)instance_by_id(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return return_value;
|
||||||
|
}
|
||||||
|
|
||||||
/// Marks entity as modified so that potential cache for it is invalidated.
|
/// Marks entity as modified so that potential cache for it is invalidated.
|
||||||
/// @todo Currently the whole cache is invalidated. Implement more fine-grained invalidation.
|
/// @todo Currently the whole cache is invalidated. Implement more fine-grained invalidation.
|
||||||
void mark_entity_as_modified(int id);
|
void mark_entity_as_modified(int id);
|
||||||
@@ -269,13 +283,13 @@ public:
|
|||||||
|
|
||||||
std::string createTimestamp() const;
|
std::string createTimestamp() const;
|
||||||
|
|
||||||
size_t load(unsigned entity_instance_name, Argument**& attributes, size_t num_attributes);
|
size_t load(unsigned entity_instance_name, const IfcParse::entity* entity, Argument**& attributes, size_t num_attributes);
|
||||||
void seek_to(const IfcEntityInstanceData& data);
|
void seek_to(const IfcEntityInstanceData& data);
|
||||||
void try_read_semicolon();
|
void try_read_semicolon();
|
||||||
|
|
||||||
void register_inverse(unsigned, Token);
|
void register_inverse(unsigned, const IfcParse::entity* from_entity, Token, int attribute_index);
|
||||||
void register_inverse(unsigned, IfcUtil::IfcBaseClass*);
|
void register_inverse(unsigned, const IfcParse::entity* from_entity, IfcUtil::IfcBaseClass*, int attribute_index);
|
||||||
void unregister_inverse(unsigned, IfcUtil::IfcBaseClass*);
|
void unregister_inverse(unsigned, const IfcParse::entity* from_entity, IfcUtil::IfcBaseClass*, int attribute_index);
|
||||||
|
|
||||||
const IfcParse::schema_definition* schema() const { return schema_; }
|
const IfcParse::schema_definition* schema() const { return schema_; }
|
||||||
|
|
||||||
|
|||||||
+129
-101
@@ -663,12 +663,21 @@ namespace {
|
|||||||
{}
|
{}
|
||||||
|
|
||||||
void push_back(const T& t) {
|
void push_back(const T& t) {
|
||||||
|
// @todo this should log a warning when the size is exceeded
|
||||||
if (array_ && index_ < size_) {
|
if (array_ && index_ < size_) {
|
||||||
array_[index_++] = t;
|
array_[index_++] = t;
|
||||||
} else if (vector_) {
|
} else if (vector_) {
|
||||||
vector_->push_back(t);
|
vector_->push_back(t);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t index() const {
|
||||||
|
if (vector_) {
|
||||||
|
return vector_->size();
|
||||||
|
} else {
|
||||||
|
return index_;
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -676,7 +685,7 @@ namespace {
|
|||||||
// Reads the arguments from a list of token
|
// Reads the arguments from a list of token
|
||||||
// Aditionally, registers the ids (i.e. #[\d]+) in the inverse map
|
// Aditionally, registers the ids (i.e. #[\d]+) in the inverse map
|
||||||
//
|
//
|
||||||
size_t IfcParse::IfcFile::load(unsigned entity_instance_name, Argument**& attributes, size_t num_attributes) {
|
size_t IfcParse::IfcFile::load(unsigned entity_instance_name, const IfcParse::entity* entity, Argument**& attributes, size_t num_attributes) {
|
||||||
Token next = tokens->Next();
|
Token next = tokens->Next();
|
||||||
|
|
||||||
std::vector<Argument*>* vector = 0;
|
std::vector<Argument*>* vector = 0;
|
||||||
@@ -696,13 +705,15 @@ size_t IfcParse::IfcFile::load(unsigned entity_instance_name, Argument**& attrib
|
|||||||
} else if ( TokenFunc::isOperator(next,'(') ) {
|
} else if ( TokenFunc::isOperator(next,'(') ) {
|
||||||
return_value++;
|
return_value++;
|
||||||
ArgumentList* alist = new ArgumentList();
|
ArgumentList* alist = new ArgumentList();
|
||||||
alist->size() = load(entity_instance_name, alist->arguments(), 0);
|
// entity is passed along here, after all the it is the type of the instance
|
||||||
|
// that owns the list that is significant for inverse attributes
|
||||||
|
alist->size() = load(entity_instance_name, entity, alist->arguments(), 0);
|
||||||
filler.push_back(alist);
|
filler.push_back(alist);
|
||||||
} else {
|
} else {
|
||||||
return_value++;
|
return_value++;
|
||||||
if ( TokenFunc::isIdentifier(next) ) {
|
if ( TokenFunc::isIdentifier(next) ) {
|
||||||
if (!parsing_complete_) {
|
if (!parsing_complete_) {
|
||||||
register_inverse(entity_instance_name, next);
|
register_inverse(entity_instance_name, entity, next, (int) filler.index());
|
||||||
}
|
}
|
||||||
} if ( TokenFunc::isKeyword(next) ) {
|
} if ( TokenFunc::isKeyword(next) ) {
|
||||||
try {
|
try {
|
||||||
@@ -953,26 +964,39 @@ void IfcParse::IfcFile::try_read_semicolon() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void IfcParse::IfcFile::register_inverse(unsigned id_from, Token t) {
|
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
|
||||||
byref[t.value_int].push_back(id_from);
|
auto e = from_entity;
|
||||||
}
|
while (e) {
|
||||||
|
byref[{t.value_int, e->index_in_schema(), attribute_index}].push_back(id_from);
|
||||||
void IfcParse::IfcFile::register_inverse(unsigned id_from, IfcUtil::IfcBaseClass* inst) {
|
e = e->supertype();
|
||||||
byref[inst->data().id()].push_back(id_from);
|
|
||||||
}
|
|
||||||
|
|
||||||
void IfcParse::IfcFile::unregister_inverse(unsigned id_from, IfcUtil::IfcBaseClass* inst) {
|
|
||||||
std::vector<unsigned int>& ids = byref[inst->data().id()];
|
|
||||||
std::vector<unsigned 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.
|
|
||||||
// throw IfcParse::IfcException("Instance not found among inverses");
|
|
||||||
} else {
|
|
||||||
ids.erase(it);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void IfcParse::IfcFile::register_inverse(unsigned id_from, const IfcParse::entity* from_entity, IfcUtil::IfcBaseClass* inst, int attribute_index) {
|
||||||
|
auto e = from_entity;
|
||||||
|
while (e) {
|
||||||
|
byref[{inst->data().id(), e->index_in_schema(), attribute_index}].push_back(id_from);
|
||||||
|
e = e->supertype();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void IfcParse::IfcFile::unregister_inverse(unsigned id_from, const IfcParse::entity* from_entity, IfcUtil::IfcBaseClass* inst, int attribute_index) {
|
||||||
|
auto e = from_entity;
|
||||||
|
while (e) {
|
||||||
|
std::vector<int>& ids = byref[{inst->data().id(), e->index_in_schema(), attribute_index}];
|
||||||
|
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.
|
||||||
|
// throw IfcParse::IfcException("Instance not found among inverses");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ids.erase(it);
|
||||||
|
}
|
||||||
|
e = e->supertype();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Returns a string representation of the entity
|
// Returns a string representation of the entity
|
||||||
// Note that this initializes the entity if it is not initialized
|
// Note that this initializes the entity if it is not initialized
|
||||||
@@ -1051,7 +1075,7 @@ void IfcEntityInstanceData::load() const {
|
|||||||
tmp_data = new Argument*[getArgumentCount()]{};
|
tmp_data = new Argument*[getArgumentCount()]{};
|
||||||
}
|
}
|
||||||
file->seek_to(*this);
|
file->seek_to(*this);
|
||||||
size_t n = file->load(id(), tmp_data, getArgumentCount());
|
size_t n = file->load(id(), type_ ? type_->as_entity() : nullptr, tmp_data, getArgumentCount());
|
||||||
if (n != getArgumentCount()) {
|
if (n != getArgumentCount()) {
|
||||||
Logger::Error("Wrong number of attributes on instance with id #" + boost::lexical_cast<std::string>(id_));
|
Logger::Error("Wrong number of attributes on instance with id #" + boost::lexical_cast<std::string>(id_));
|
||||||
}
|
}
|
||||||
@@ -1103,8 +1127,8 @@ public:
|
|||||||
: file_(file), data_(data)
|
: file_(file), data_(data)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
void operator()(IfcUtil::IfcBaseClass* inst) {
|
void operator()(IfcUtil::IfcBaseClass* inst, int index) {
|
||||||
file_.unregister_inverse(data_.id(), inst);
|
file_.unregister_inverse(data_.id(), data_.type()->as_entity(), inst, index);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1118,8 +1142,8 @@ public:
|
|||||||
: file_(file), data_(data)
|
: file_(file), data_(data)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
void operator()(IfcUtil::IfcBaseClass* inst) {
|
void operator()(IfcUtil::IfcBaseClass* inst, int index) {
|
||||||
file_.register_inverse(data_.id(), inst);
|
file_.register_inverse(data_.id(), data_.type()->as_entity(), inst, index);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1141,33 +1165,34 @@ class apply_individual_instance_visitor {
|
|||||||
private:
|
private:
|
||||||
Argument* attribute_;
|
Argument* attribute_;
|
||||||
IfcEntityInstanceData* data_;
|
IfcEntityInstanceData* data_;
|
||||||
|
int attribute_index_;
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void apply_attribute_(T& t, Argument* attr) const {
|
void apply_attribute_(T& t, Argument* attr, int index) const {
|
||||||
if (!attr) {
|
if (!attr) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (attr->type() == IfcUtil::Argument_ENTITY_INSTANCE) {
|
if (attr->type() == IfcUtil::Argument_ENTITY_INSTANCE) {
|
||||||
IfcUtil::IfcBaseClass* inst = *attr;
|
IfcUtil::IfcBaseClass* inst = *attr;
|
||||||
t(inst);
|
t(inst, index);
|
||||||
} else if (attr->type() == IfcUtil::Argument_AGGREGATE_OF_ENTITY_INSTANCE) {
|
} else if (attr->type() == IfcUtil::Argument_AGGREGATE_OF_ENTITY_INSTANCE) {
|
||||||
aggregate_of_instance::ptr entity_list_attribute = *attr;
|
aggregate_of_instance::ptr entity_list_attribute = *attr;
|
||||||
for (aggregate_of_instance::it it = entity_list_attribute->begin(); it != entity_list_attribute->end(); ++it) {
|
for (aggregate_of_instance::it it = entity_list_attribute->begin(); it != entity_list_attribute->end(); ++it) {
|
||||||
t(*it);
|
t(*it, index);
|
||||||
}
|
}
|
||||||
} else if (attr->type() == IfcUtil::Argument_AGGREGATE_OF_AGGREGATE_OF_ENTITY_INSTANCE) {
|
} else if (attr->type() == IfcUtil::Argument_AGGREGATE_OF_AGGREGATE_OF_ENTITY_INSTANCE) {
|
||||||
aggregate_of_aggregate_of_instance::ptr entity_list_attribute = *attr;
|
aggregate_of_aggregate_of_instance::ptr entity_list_attribute = *attr;
|
||||||
for (aggregate_of_aggregate_of_instance::outer_it it = entity_list_attribute->begin(); it != entity_list_attribute->end(); ++it) {
|
for (aggregate_of_aggregate_of_instance::outer_it it = entity_list_attribute->begin(); it != entity_list_attribute->end(); ++it) {
|
||||||
for (aggregate_of_aggregate_of_instance::inner_it jt = it->begin(); jt != it->end(); ++jt) {
|
for (aggregate_of_aggregate_of_instance::inner_it jt = it->begin(); jt != it->end(); ++jt) {
|
||||||
t(*jt);
|
t(*jt, index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
public:
|
public:
|
||||||
apply_individual_instance_visitor(Argument* attribute)
|
apply_individual_instance_visitor(Argument* attribute, int idx)
|
||||||
: attribute_(attribute), data_(0)
|
: attribute_(attribute), data_(0), attribute_index_(idx)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
apply_individual_instance_visitor(IfcEntityInstanceData* data)
|
apply_individual_instance_visitor(IfcEntityInstanceData* data)
|
||||||
@@ -1177,11 +1202,11 @@ public:
|
|||||||
template <typename T>
|
template <typename T>
|
||||||
void apply(T& t) const {
|
void apply(T& t) const {
|
||||||
if (attribute_) {
|
if (attribute_) {
|
||||||
apply_attribute_(t, attribute_);
|
apply_attribute_(t, attribute_, attribute_index_);
|
||||||
} else {
|
} else {
|
||||||
for (size_t i = 0; i < data_->getArgumentCount(); ++i) {
|
for (size_t i = 0; i < data_->getArgumentCount(); ++i) {
|
||||||
Argument* attr = data_->getArgument(i);
|
Argument* attr = data_->getArgument(i);
|
||||||
apply_attribute_(t, attr);
|
apply_attribute_(t, attr, i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -1317,14 +1342,14 @@ void IfcEntityInstanceData::setArgument(size_t i, Argument* a, IfcUtil::Argument
|
|||||||
Argument* current_attribute = attributes_[i];
|
Argument* current_attribute = attributes_[i];
|
||||||
if (this->file) {
|
if (this->file) {
|
||||||
unregister_inverse_visitor visitor(*this->file, *this);
|
unregister_inverse_visitor visitor(*this->file, *this);
|
||||||
apply_individual_instance_visitor(current_attribute).apply(visitor);
|
apply_individual_instance_visitor(current_attribute, i).apply(visitor);
|
||||||
}
|
}
|
||||||
delete attributes_[i];
|
delete attributes_[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this->file) {
|
if (this->file) {
|
||||||
register_inverse_visitor visitor(*this->file, *this);
|
register_inverse_visitor visitor(*this->file, *this);
|
||||||
apply_individual_instance_visitor(copy).apply(visitor);
|
apply_individual_instance_visitor(copy, i).apply(visitor);
|
||||||
|
|
||||||
this->file->mark_entity_as_modified(id_);
|
this->file->mark_entity_as_modified(id_);
|
||||||
}
|
}
|
||||||
@@ -1428,6 +1453,9 @@ void IfcFile::initialize_(IfcParse::IfcSpfStream* s) {
|
|||||||
unsigned current_id = 0;
|
unsigned current_id = 0;
|
||||||
int progress = 0;
|
int progress = 0;
|
||||||
Logger::Status("Scanning file...");
|
Logger::Status("Scanning file...");
|
||||||
|
|
||||||
|
int paren_stack_depth = 0;
|
||||||
|
int attribute_index = -1;
|
||||||
|
|
||||||
while (!stream->eof) {
|
while (!stream->eof) {
|
||||||
if (token_stream[0].type == IfcParse::Token_IDENTIFIER &&
|
if (token_stream[0].type == IfcParse::Token_IDENTIFIER &&
|
||||||
@@ -1435,6 +1463,8 @@ void IfcFile::initialize_(IfcParse::IfcSpfStream* s) {
|
|||||||
token_stream[1].value_char == '=' &&
|
token_stream[1].value_char == '=' &&
|
||||||
token_stream[2].type == IfcParse::Token_KEYWORD)
|
token_stream[2].type == IfcParse::Token_KEYWORD)
|
||||||
{
|
{
|
||||||
|
attribute_index = 0;
|
||||||
|
|
||||||
current_id = (unsigned) TokenFunc::asIdentifier(token_stream[0]);
|
current_id = (unsigned) TokenFunc::asIdentifier(token_stream[0]);
|
||||||
const IfcParse::declaration* entity_type;
|
const IfcParse::declaration* entity_type;
|
||||||
try {
|
try {
|
||||||
@@ -1466,6 +1496,9 @@ void IfcFile::initialize_(IfcParse::IfcSpfStream* s) {
|
|||||||
} catch (const IfcException& ex) {
|
} catch (const IfcException& ex) {
|
||||||
Logger::Message(Logger::LOG_ERROR,ex.what());
|
Logger::Message(Logger::LOG_ERROR,ex.what());
|
||||||
}
|
}
|
||||||
|
// this has consumed the instance tokens, set stack depth to 0
|
||||||
|
paren_stack_depth = 0;
|
||||||
|
attribute_index = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
const IfcParse::declaration* ty = &instance->declaration();
|
const IfcParse::declaration* ty = &instance->declaration();
|
||||||
@@ -1503,7 +1536,16 @@ void IfcFile::initialize_(IfcParse::IfcSpfStream* s) {
|
|||||||
|
|
||||||
MaxId = (std::max)(MaxId, current_id);
|
MaxId = (std::max)(MaxId, current_id);
|
||||||
} else if (token_stream[0].type == IfcParse::Token_IDENTIFIER && instance) {
|
} else if (token_stream[0].type == IfcParse::Token_IDENTIFIER && instance) {
|
||||||
register_inverse(current_id, token_stream[0]);
|
register_inverse(current_id, instance->declaration().as_entity(), token_stream[0], attribute_index);
|
||||||
|
} else if (token_stream[0].type == IfcParse::Token_OPERATOR && token_stream[0].value_char == '(') {
|
||||||
|
paren_stack_depth++;
|
||||||
|
} else if (token_stream[0].type == IfcParse::Token_OPERATOR && token_stream[0].value_char == ')') {
|
||||||
|
paren_stack_depth--;
|
||||||
|
if (paren_stack_depth == 0) {
|
||||||
|
attribute_index = -1;
|
||||||
|
}
|
||||||
|
} else if (paren_stack_depth == 1 && token_stream[0].type == IfcParse::Token_OPERATOR && token_stream[0].value_char == ',') {
|
||||||
|
attribute_index++;
|
||||||
}
|
}
|
||||||
|
|
||||||
advance:
|
advance:
|
||||||
@@ -1590,7 +1632,7 @@ public:
|
|||||||
, max_level_(max_level)
|
, max_level_(max_level)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
void operator()(IfcUtil::IfcBaseClass* inst);
|
void operator()(IfcUtil::IfcBaseClass* inst, int index);
|
||||||
};
|
};
|
||||||
|
|
||||||
void traverse_(IfcUtil::IfcBaseClass* instance, std::set<IfcUtil::IfcBaseClass*>& visited, traversal_recorder& list, int level, int max_level) {
|
void traverse_(IfcUtil::IfcBaseClass* instance, std::set<IfcUtil::IfcBaseClass*>& visited, traversal_recorder& list, int level, int max_level) {
|
||||||
@@ -1606,7 +1648,7 @@ void traverse_(IfcUtil::IfcBaseClass* instance, std::set<IfcUtil::IfcBaseClass*>
|
|||||||
apply_individual_instance_visitor(&instance->data()).apply(visit);
|
apply_individual_instance_visitor(&instance->data()).apply(visit);
|
||||||
}
|
}
|
||||||
|
|
||||||
void traversal_visitor::operator()(IfcUtil::IfcBaseClass* inst) {
|
void traversal_visitor::operator()(IfcUtil::IfcBaseClass* inst, int /* index */) {
|
||||||
traverse_(inst, visited_, list_, level_, max_level_);
|
traverse_(inst, visited_, list_, level_, max_level_);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1984,8 +2026,11 @@ void IfcFile::process_deletion_() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!batch_mode_) {
|
if (!batch_mode_) {
|
||||||
byref.erase(id);
|
byref.erase(
|
||||||
|
byref.lower_bound({ id,-1,-1 }),
|
||||||
|
byref.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);
|
||||||
@@ -1995,9 +2040,11 @@ void IfcFile::process_deletion_() {
|
|||||||
const unsigned int name = entity_attribute->data().id();
|
const unsigned int name = entity_attribute->data().id();
|
||||||
// Do not update inverses for simple types (which have id()==0 in IfcOpenShell).
|
// Do not update inverses for simple types (which have id()==0 in IfcOpenShell).
|
||||||
if (name != 0) {
|
if (name != 0) {
|
||||||
entities_by_ref_t::iterator byref_it = byref.find(name);
|
auto lower = byref.lower_bound({ name,-1,-1 });
|
||||||
if (byref_it != byref.end()) {
|
auto upper = byref.upper_bound({ name, std::numeric_limits<int>::max(), std::numeric_limits<int>::max() });
|
||||||
std::vector<unsigned>& ids = byref_it->second;
|
|
||||||
|
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());
|
ids.erase(std::remove(ids.begin(), ids.end(), id), ids.end());
|
||||||
}
|
}
|
||||||
by_ref_cached_.erase(name);
|
by_ref_cached_.erase(name);
|
||||||
@@ -2063,7 +2110,7 @@ void IfcFile::process_deletion_() {
|
|||||||
|
|
||||||
if (batch_mode_) {
|
if (batch_mode_) {
|
||||||
for (auto it = byref.begin(); it != byref.end();) {
|
for (auto it = byref.begin(); it != byref.end();) {
|
||||||
bool do_delete = batch_deletion_ids_.get<1>().find(it->first) != batch_deletion_ids_.get<1>().end();
|
bool do_delete = batch_deletion_ids_.get<1>().find(std::get<INSTANCE_ID>(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();
|
||||||
@@ -2103,25 +2150,18 @@ 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) {
|
||||||
entities_by_ref_t::const_iterator it = byref.find(t);
|
auto lower = byref.lower_bound({ t,-1,-1 });
|
||||||
aggregate_of_instance::ptr ret;
|
auto upper = byref.upper_bound({ t, std::numeric_limits<int>::max(), std::numeric_limits<int>::max() });
|
||||||
if (it != byref.end()) {
|
|
||||||
ref_map_t::const_iterator cached_it = by_ref_cached_.find(t);
|
aggregate_of_instance::ptr ret(new aggregate_of_instance);
|
||||||
if (cached_it != by_ref_cached_.end()) {
|
for (auto it = lower; it != upper; it++) {
|
||||||
ret = cached_it->second;
|
for (auto& i : it->second) {
|
||||||
}
|
ret->push(instance_by_id(i));
|
||||||
else {
|
}
|
||||||
if (it->second.size()) {
|
|
||||||
ret.reset(new aggregate_of_instance);
|
|
||||||
ret->reserve((unsigned)it->second.size());
|
|
||||||
const std::vector<unsigned>& ids = it->second;
|
|
||||||
for (std::vector<unsigned>::const_iterator jt = ids.begin(); jt != ids.end(); ++jt) {
|
|
||||||
ret->push(instance_by_id(*jt));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
by_ref_cached_[t] = ret;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
by_ref_cached_[t] = ret;
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2220,37 +2260,32 @@ std::string IfcFile::createTimestamp() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
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) {
|
||||||
IfcUtil::IfcBaseClass* instance = instance_by_id(instance_id);
|
if (type == nullptr && attribute_index == -1) {
|
||||||
|
return instances_by_reference(instance_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
aggregate_of_instance::ptr return_value(new aggregate_of_instance);
|
||||||
|
|
||||||
|
if (attribute_index == -1) {
|
||||||
|
auto lower = byref.lower_bound({ instance_id, type->index_in_schema(), -1 });
|
||||||
|
auto upper = byref.upper_bound({ instance_id, type->index_in_schema(), std::numeric_limits<int>::max() });
|
||||||
|
|
||||||
aggregate_of_instance::ptr l = aggregate_of_instance::ptr(new aggregate_of_instance);
|
for (auto it = lower; it != upper; ++it) {
|
||||||
aggregate_of_instance::ptr all = instances_by_reference(instance_id);
|
for (auto& i : it->second) {
|
||||||
if (!all) return l;
|
return_value->push(instance_by_id(i));
|
||||||
|
|
||||||
for(aggregate_of_instance::it it = all->begin(); it != all->end(); ++it) {
|
|
||||||
bool valid = type == 0 || (*it)->declaration().is(*type);
|
|
||||||
if (valid && attribute_index >= 0) {
|
|
||||||
try {
|
|
||||||
Argument* arg = (*it)->data().getArgument(attribute_index);
|
|
||||||
if (arg->type() == IfcUtil::Argument_ENTITY_INSTANCE) {
|
|
||||||
valid = instance == *arg;
|
|
||||||
} else if (arg->type() == IfcUtil::Argument_AGGREGATE_OF_ENTITY_INSTANCE) {
|
|
||||||
aggregate_of_instance::ptr li = *arg;
|
|
||||||
valid = li->contains(instance);
|
|
||||||
} else if (arg->type() == IfcUtil::Argument_AGGREGATE_OF_AGGREGATE_OF_ENTITY_INSTANCE) {
|
|
||||||
aggregate_of_aggregate_of_instance::ptr li = *arg;
|
|
||||||
valid = li->contains(instance);
|
|
||||||
}
|
|
||||||
} catch (const IfcException& e) {
|
|
||||||
valid = false;
|
|
||||||
Logger::Error(e);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (valid) {
|
} else {
|
||||||
l->push(*it);
|
auto it = byref.find({ instance_id, type->index_in_schema(), attribute_index });
|
||||||
|
if (it != byref.end()) {
|
||||||
|
for (auto& i : it->second) {
|
||||||
|
return_value->push(instance_by_id(i));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return l;
|
|
||||||
|
return return_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
void IfcFile::setDefaultHeaderValues() {
|
void IfcFile::setDefaultHeaderValues() {
|
||||||
@@ -2345,24 +2380,17 @@ std::pair<IfcUtil::IfcBaseClass*, double> IfcFile::getUnit(const std::string& un
|
|||||||
|
|
||||||
void IfcParse::IfcFile::build_inverses_(IfcUtil::IfcBaseClass* inst) {
|
void IfcParse::IfcFile::build_inverses_(IfcUtil::IfcBaseClass* inst) {
|
||||||
aggregate_of_instance::ptr entity_attributes(new aggregate_of_instance);
|
aggregate_of_instance::ptr entity_attributes(new aggregate_of_instance);
|
||||||
try {
|
|
||||||
entity_attributes = traverse(inst, 1);
|
|
||||||
} catch (const std::exception& e) {
|
|
||||||
Logger::Error(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (aggregate_of_instance::it it = entity_attributes->begin(); it != entity_attributes->end(); ++it) {
|
std::function<void(IfcUtil::IfcBaseClass*,int)> fn = [this](IfcUtil::IfcBaseClass* inst, int idx) {
|
||||||
IfcUtil::IfcBaseClass* entity_attribute = *it;
|
if (inst->declaration().as_entity()) {
|
||||||
if (*it == inst) continue;
|
unsigned entity_attribute_id = inst->data().id();
|
||||||
try {
|
auto decl = inst->declaration().as_entity();
|
||||||
if (entity_attribute->declaration().as_entity()) {
|
while (decl) {
|
||||||
unsigned entity_attribute_id = entity_attribute->data().id();
|
byref[{entity_attribute_id, decl->index_in_schema(), idx}].push_back(inst->data().id());
|
||||||
byref[entity_attribute_id].push_back(inst->data().id());
|
decl = decl->supertype();
|
||||||
}
|
}
|
||||||
} catch (const std::exception& e) {
|
|
||||||
Logger::Error(e);
|
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
void IfcParse::IfcFile::build_inverses() {
|
void IfcParse::IfcFile::build_inverses() {
|
||||||
|
|||||||
Reference in New Issue
Block a user