/******************************************************************************** * * * This file is part of IfcOpenShell. * * * * IfcOpenShell is free software: you can redistribute it and/or modify * * it under the terms of the Lesser GNU General Public License as published by * * the Free Software Foundation, either version 3.0 of the License, or * * (at your option) any later version. * * * * IfcOpenShell is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * Lesser GNU General Public License for more details. * * * * You should have received a copy of the Lesser GNU General Public License * * along with this program. If not, see . * * * ********************************************************************************/ class multifile_instance_locator : public IfcParse::abstract_instance_locator { public: typedef std::function mapping_t; typedef std::pair< std::vector, std::vector< std::vector > > population_t; typedef std::vector::const_iterator full_const_iterator; private: H5::H5File* root_file_; mapping_t mapping_; std::set initial_population_set_; std::set initial_types_included_set_; population_t initial_population_; population_t subsequent_population_; std::vector subsequent_minus_initial_; H5::Group* initial_group_; H5::Group* subsequent_group_; H5::H5File* subsequent_file_; std::string root_; public: template multifile_instance_locator(H5::H5File& root_file, H5::Group& group, mapping_t mapping, ForwardIterator b, ForwardIterator e) : root_file_(&root_file) , mapping_(mapping) , initial_group_(&group) , subsequent_group_(nullptr) { initial_population_set_.insert(b, e); std::set names_set; std::for_each(b, e, [this, &names_set](IfcUtil::IfcBaseClass* inst) { IfcSchema::Type::Enum ty = inst->declaration().type(); if (names_set.find(ty) == names_set.end()) { initial_population_.first.push_back(ty); names_set.insert(ty); } }); std::sort(initial_population_.first.begin(), initial_population_.first.end()); std::for_each(this->begin(), this->end(), [this, &b, &e](IfcSchema::Type::Enum t) { std::vector by_type; std::for_each(b, e, [t,&by_type](IfcUtil::IfcBaseClass* inst) { if (inst->declaration().type() == t && inst->declaration().as_entity()) { by_type.push_back((IfcUtil::IfcBaseEntity*) inst); } }); std::sort(by_type.begin(), by_type.end(), [](IfcUtil::IfcBaseEntity* i1, IfcUtil::IfcBaseEntity* i2) { return i1->data().id() < i2->data().id(); }); initial_population_.second.emplace_back(by_type); }); } template multifile_instance_locator(ForwardIteratorTypes types_all_begin, ForwardIteratorTypes types_all_end, ForwardIteratorInsts insts_begin, ForwardIteratorInsts insts_end) { initial_population_.first.assign(types_all_begin, types_all_end); std::sort(initial_population_.first.begin(), initial_population_.first.end()); std::for_each(this->begin(), this->end(), [this, &insts_begin, &insts_end](IfcSchema::Type::Enum t) { std::vector by_type; std::for_each(insts_begin, insts_end, [t, &by_type](IfcUtil::IfcBaseClass* inst) { if (inst->declaration().type() == t && inst->declaration().as_entity()) { by_type.push_back((IfcUtil::IfcBaseEntity*) inst); } }); std::sort(by_type.begin(), by_type.end(), [](IfcUtil::IfcBaseEntity* i1, IfcUtil::IfcBaseEntity* i2) { return i1->data().id() < i2->data().id(); }); initial_population_.second.emplace_back(by_type); }); } const_iterator begin() const { if (subsequent_group_) { return subsequent_population_.first.begin(); } else { return initial_population_.first.begin(); } } const_iterator end() const { if (subsequent_group_) { return subsequent_population_.first.end(); } else { return initial_population_.first.end(); } } full_const_iterator full_begin() const { return subsequent_minus_initial_.begin(); } full_const_iterator full_end() const { return subsequent_minus_initial_.end(); } const std::vector& instances(IfcSchema::Type::Enum t) { if (subsequent_group_) { return subsequent_population_.second[std::lower_bound(begin(), end(), t) - begin()]; } else { return initial_population_.second[std::lower_bound(begin(), end(), t) - begin()]; } } std::pair operator()(IfcUtil::IfcBaseClass* v) { throw std::runtime_error("This locator can only be used in referenced profile"); } void make_reference(IfcUtil::IfcBaseClass* v, void*& ptr) { v = mapping_(v); IfcSchema::Type::Enum t = v->declaration().type(); population_t* pop; H5::Group* group; boost::optional current_root; if (initial_population_set_.find(v) != initial_population_set_.end()) { pop = &initial_population_; group = initial_group_; current_root = boost::none; } else { pop = &subsequent_population_; group = subsequent_group_; current_root = root_; } int a = std::lower_bound(pop->first.begin(), pop->first.end(), t) - pop->first.begin(); auto& vec = pop->second[a]; hsize_t coord = std::lower_bound(vec.begin(), vec.end(), v, [](IfcUtil::IfcBaseClass* other, IfcUtil::IfcBaseClass* val) { return other->data().id() < val->data().id(); }) - vec.begin(); hsize_t dims = instances(v->declaration().type()).size(); H5::DataSpace space(1, &dims); space.selectElements(H5S_SELECT_SET, 1, &coord); const std::string path = IfcSchema::Type::ToString(pop->first[a]); std::string full_path = group->getObjName() + "/" + path + "_instances"; root_file_->reference(ptr, full_path, space); ptr = static_cast(ptr) + sizeof(hdset_reg_ref_t); } void next(const std::string& name, H5::Group& group, IfcParse::IfcFile* f) { subsequent_group_ = &group; root_ = name; subsequent_population_.first.clear(); subsequent_population_.second.clear(); subsequent_minus_initial_.clear(); auto f_begin = f->begin(); auto f_end = f->end(); std::set names_set; std::for_each(f_begin, f_end, [this, &names_set](auto& pair) { IfcUtil::IfcBaseClass* inst = mapping_(pair.second); if (initial_population_set_.find(inst) == initial_population_set_.end()) { IfcSchema::Type::Enum ty = inst->declaration().type(); if (names_set.find(ty) == names_set.end()) { subsequent_population_.first.push_back(ty); names_set.insert(ty); } subsequent_minus_initial_.push_back(inst); } }); auto& names = subsequent_population_.first; std::sort(names.begin(), names.end()); auto& vecs = subsequent_population_.second; vecs.resize(names.size()); std::for_each(f_begin, f_end, [this, &names, &vecs](auto& pair) { IfcUtil::IfcBaseClass* inst = mapping_(pair.second); if (initial_population_set_.find(inst) == initial_population_set_.end() && inst->declaration().as_entity()) { IfcSchema::Type::Enum ty = inst->declaration().type(); auto a = std::lower_bound(names.begin(), names.end(), ty) - names.begin(); auto& by_type = vecs[a]; by_type.push_back((IfcUtil::IfcBaseEntity*) inst); } }); std::for_each(vecs.begin(), vecs.end(), [](auto& vec) { std::sort(vec.begin(), vec.end(), [](IfcUtil::IfcBaseEntity* i1, IfcUtil::IfcBaseEntity* i2) { return i1->data().id() < i2->data().id(); }); }); } };