From 952400bd58c7c35b11f5936a736dbf46cb07d8dc Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Fri, 11 Apr 2025 15:52:40 +0200 Subject: [PATCH] Support defined types with instance references in parser (IfcPropertySetDefinitionSet; #6330) --- src/ifcparse/IfcFile.cpp | 14 +++---- src/ifcparse/IfcFile.h | 2 +- src/ifcparse/IfcParse.cpp | 80 ++++++++++++++++++++++++++++++++++++--- 3 files changed, 82 insertions(+), 14 deletions(-) diff --git a/src/ifcparse/IfcFile.cpp b/src/ifcparse/IfcFile.cpp index bd312d51cb..3e50bd154c 100644 --- a/src/ifcparse/IfcFile.cpp +++ b/src/ifcparse/IfcFile.cpp @@ -225,7 +225,7 @@ namespace { } } -IfcEntityInstanceData IfcParse::parse_context::construct(int name, unresolved_references& references_to_resolve, const IfcParse::declaration* decl, boost::optional expected_size) { +IfcEntityInstanceData IfcParse::parse_context::construct(int name, unresolved_references& references_to_resolve, const IfcParse::declaration* decl, boost::optional expected_size, int resolve_reference_index) { std::vector parameter_types; std::unique_ptr transient_named_type; @@ -274,16 +274,16 @@ IfcEntityInstanceData IfcParse::parse_context::construct(int name, unresolved_re auto index = (uint8_t) std::distance(tokens_.begin(), it); - boost::apply_visitor([this, &storage, name, &references_to_resolve, index, param_type](const auto& v) { + boost::apply_visitor([this, &storage, name, &references_to_resolve, index, param_type, resolve_reference_index](const auto& v) { if constexpr (std::is_same_v, IfcParse::Token>) { - dispatch_token(name, index, v, param_type && param_type->as_named_type() ? param_type->as_named_type()->declared_type() : nullptr, [this, &storage, name, &references_to_resolve, index](auto v) { + dispatch_token(name, index, v, param_type && param_type->as_named_type() ? param_type->as_named_type()->declared_type() : nullptr, [this, &storage, name, &references_to_resolve, index, resolve_reference_index](auto v) { if constexpr (std::is_same_v, IfcParse::reference_or_simple_type>) { if (name > 0) { references_to_resolve.push_back(std::make_pair( // @todo previously this was storage but apparently the // pointer is not constant with the moving and temporary nature // maybe it ought to be and in that case a pointer is more direct - MutableAttributeValue{ name, index }, + MutableAttributeValue{ name, resolve_reference_index == -1 ? index : (uint8_t) resolve_reference_index }, v )); } @@ -298,14 +298,14 @@ IfcEntityInstanceData IfcParse::parse_context::construct(int name, unresolved_re pt = pt->as_named_type()->declared_type()->as_type_declaration()->declared_type(); } } - construct_<0>(name, index, *v, pt ? pt->as_aggregation_type() : nullptr, [this, &storage, name, &references_to_resolve, index](const auto& v) { + construct_<0>(name, index, *v, pt ? pt->as_aggregation_type() : nullptr, [this, &storage, name, &references_to_resolve, index, resolve_reference_index](const auto& v) { if constexpr (std::is_same_v, std::vector>) { if (name > 0) { - references_to_resolve.push_back({ {name, index }, v }); + references_to_resolve.push_back({ {name, resolve_reference_index == -1 ? index : (uint8_t)resolve_reference_index }, v }); } } else if constexpr (std::is_same_v, std::vector>>) { if (name > 0) { - references_to_resolve.push_back({ {name, index }, v }); + references_to_resolve.push_back({ {name, resolve_reference_index == -1 ? index : (uint8_t)resolve_reference_index }, v }); } } else { storage.set(index, v); diff --git a/src/ifcparse/IfcFile.h b/src/ifcparse/IfcFile.h index acfe6f4c89..2127dc4d23 100644 --- a/src/ifcparse/IfcFile.h +++ b/src/ifcparse/IfcFile.h @@ -100,7 +100,7 @@ struct parse_context { void push(IfcUtil::IfcBaseClass* inst); - IfcEntityInstanceData construct(int name, unresolved_references& references_to_resolve, const IfcParse::declaration* decl, boost::optional expected_size); + IfcEntityInstanceData construct(int name, unresolved_references& references_to_resolve, const IfcParse::declaration* decl, boost::optional expected_size, int resolve_reference_index=-1); }; /// This class provides several static convenience functions and variables diff --git a/src/ifcparse/IfcParse.cpp b/src/ifcparse/IfcParse.cpp index f1a9237d57..b2e4edc609 100644 --- a/src/ifcparse/IfcParse.cpp +++ b/src/ifcparse/IfcParse.cpp @@ -720,8 +720,14 @@ void IfcParse::IfcFile::load(unsigned entity_instance_name, const IfcParse::enti const auto* decl = schema_->declaration_by_name(TokenFunc::asStringRef(next)); parse_context ps; tokens->Next(); - load(0, nullptr, ps, -1); - auto* simple_type_instance = schema_->instantiate(decl, ps.construct(-1, references_to_resolve, decl, boost::none)); + // The only case we know where a defined type contains entity + // instance references is IfcPropertySetDefinitionSet. For + // that purpose we propagate the entity_instance_name to + // register inverses to the host entity (and not the defined + // type) and to be able to actually register the references in + // the 2nd pass. + load(entity_instance_name, entity, ps, attribute_index == -1 ? (int)attribute_index_within_data : attribute_index); + auto* simple_type_instance = schema_->instantiate(decl, ps.construct(entity_instance_name, references_to_resolve, decl, boost::none, attribute_index == -1 ? (int)attribute_index_within_data : attribute_index)); //@todo decide addEntity(((IfcUtil::IfcBaseClass*)*entity)); context.push(simple_type_instance); simple_type_instance->file_ = this; @@ -1428,10 +1434,40 @@ void IfcFile::initialize_(IfcParse::IfcSpfStream* s) { if (it == byid_.end()) { Logger::Error("Instance reference #" + std::to_string(*name) + " used by instance #" + std::to_string(ref) + " at attribute index " + std::to_string(refattr) + " not found at offset " + std::to_string(name->file_offset)); } else { - byid_[p.first.name_]->data().storage_.set(p.first.index_, it->second); + auto* storage = &byid_[p.first.name_]->data().storage_; + auto attr_index = p.first.index_; + + if (storage->has(attr_index)) { + auto inst = storage->get(attr_index); + if (!inst->declaration().as_entity()) { + storage = &inst->data().storage_; + attr_index = 0; + } + } + + if (storage->has(attr_index)) { + storage->set(attr_index, it->second); + } else { + Logger::Error("Duplicate definition for instance reference"); + } } } else if (auto* inst = boost::get(v)) { - byid_[p.first.name_]->data().storage_.set(p.first.index_, *inst); + auto* storage = &byid_[p.first.name_]->data().storage_; + auto attr_index = p.first.index_; + + if (storage->has(attr_index)) { + auto inst = storage->get(attr_index); + if (!inst->declaration().as_entity()) { + storage = &inst->data().storage_; + attr_index = 0; + } + } + + if (storage->has(attr_index)) { + storage->set(attr_index, *inst); + } else { + Logger::Error("Duplicate definition for instance reference"); + } } } else if (auto* v = boost::get>(&p.second)) { aggregate_of_instance::ptr instances(new aggregate_of_instance); @@ -1448,7 +1484,23 @@ void IfcFile::initialize_(IfcParse::IfcSpfStream* s) { instances->push(*inst); } } - byid_[p.first.name_]->data().storage_.set(p.first.index_, instances); + + auto* storage = &byid_[p.first.name_]->data().storage_; + auto attr_index = p.first.index_; + + if (storage->has(attr_index)) { + auto inst = storage->get(attr_index); + if (!inst->declaration().as_entity()) { + storage = &inst->data().storage_; + attr_index = 0; + } + } + + if (storage->has(attr_index)) { + storage->set(attr_index, instances); + } else { + Logger::Error("Duplicate definition for instance reference"); + } } else if (auto* v = boost::get>>(&p.second)) { aggregate_of_aggregate_of_instance::ptr instances(new aggregate_of_aggregate_of_instance); for (const auto& vi : *v) { @@ -1467,7 +1519,23 @@ void IfcFile::initialize_(IfcParse::IfcSpfStream* s) { } instances->push(inner); } - byid_[p.first.name_]->data().storage_.set(p.first.index_, instances); + + auto* storage = &byid_[p.first.name_]->data().storage_; + auto attr_index = p.first.index_; + + if (storage->has(attr_index)) { + auto inst = storage->get(attr_index); + if (!inst->declaration().as_entity()) { + storage = &inst->data().storage_; + attr_index = 0; + } + } + + if (storage->has(attr_index)) { + storage->set(attr_index, instances); + } else { + Logger::Error("Duplicate definition for instance reference"); + } } }