diff --git a/src/ifcgeom/IfcGeomIteratorImplementation.h b/src/ifcgeom/IfcGeomIteratorImplementation.h index 593c09f658..ec1ec5a9c6 100644 --- a/src/ifcgeom/IfcGeomIteratorImplementation.h +++ b/src/ifcgeom/IfcGeomIteratorImplementation.h @@ -107,66 +107,6 @@ namespace { std::vector breps; std::vector elements; }; - - IfcGeom::Element* process_based_on_settings( - const IfcGeom::IteratorSettings& settings, - IfcGeom::BRepElement* elem, - IfcGeom::TriangulationElement* previous=nullptr) - { - if (settings.get(IfcGeom::IteratorSettings::USE_BREP_DATA)) { - try { - return new IfcGeom::SerializedElement(*elem); - } catch (...) { - Logger::Message(Logger::LOG_ERROR, "Getting a serialized element from model failed."); - return nullptr; - } - } else if (!settings.get(IfcGeom::IteratorSettings::DISABLE_TRIANGULATION)) { - try { - if (!previous) { - return new IfcGeom::TriangulationElement(*elem); - } else { - return new IfcGeom::TriangulationElement(*elem, previous->geometry_pointer()); - } - } catch (...) { - Logger::Message(Logger::LOG_ERROR, "Getting a triangulation element from model failed."); - return nullptr; - } - } else { - return elem; - } - } - - void create_element( - IfcGeom::MAKE_TYPE_NAME(Kernel)* kernel, - const IfcGeom::IteratorSettings& settings, - geometry_conversion_task* rep) - { - IfcSchema::IfcRepresentation *representation = rep->representation; - IfcSchema::IfcProduct *product = *rep->products->begin(); - auto brep = kernel->create_brep_for_representation_and_product(settings, representation, product); - if (!brep) { - return; - } - - auto elem = process_based_on_settings(settings, brep); - if (!elem) { - return; - } - - rep->breps = { brep }; - rep->elements = { elem }; - - for (auto it = rep->products->begin() + 1; it != rep->products->end(); ++it) { - auto brep2 = kernel->create_brep_for_processed_representation(settings, representation, *it, brep); - if (brep2) { - auto elem2 = process_based_on_settings(settings, brep2, dynamic_cast(elem)); - if (elem2) { - rep->breps.push_back(brep2); - rep->elements.push_back(elem2); - } - } - } - } } namespace IfcGeom { @@ -380,7 +320,17 @@ namespace IfcGeom { } // for } // while - std::future fu = std::async(std::launch::async, create_element, K, std::ref(settings), &rep); + std::future fu = std::async( + std::launch::async, [this]( + IfcGeom::MAKE_TYPE_NAME(Kernel)* kernel, + const IfcGeom::IteratorSettings& settings, + geometry_conversion_task* rep) { + return this->create_element_(kernel, settings, rep); + }, + K, + std::ref(settings), + &rep); + threadpool.emplace_back(std::move(fu)); } @@ -766,6 +716,44 @@ namespace IfcGeom { } } + std::mutex caching_mutex_; + + template + Element* decorate_with_cache_(GeometrySerializer::read_type rt, const std::string& product_guid, const std::string& representation_id, Fn f) { + + bool read_from_cache = false; + Element* element = nullptr; + +#ifdef WITH_HDF5 + if (cache_) { + std::lock_guard lk(caching_mutex_); + + auto from_cache = cache_->read(*ifc_file, product_guid, representation_id, rt); + if (from_cache) { + read_from_cache = true; + element = from_cache; + } + } +#endif + if (!read_from_cache) { + element = f(); + } + +#ifdef WITH_HDF5 + if (cache_ && !read_from_cache && element) { + std::lock_guard lk(caching_mutex_); + + if (rt == GeometrySerializer::READ_TRIANGULATION) { + cache_->write((IfcGeom::TriangulationElement*) element); + } else { + cache_->write((IfcGeom::BRepElement*)element); + } + } +#endif + + return element; + } + BRepElement* create_shape_model_for_next_entity() { for (;;) { auto rp = get_next_task(); @@ -777,26 +765,13 @@ namespace IfcGeom { Logger::SetProduct(product); - bool read_from_cache = false; - BRepElement* element; - -#ifdef WITH_HDF5 - if (cache_) { - auto from_cache = cache_->read(*ifc_file, product->GlobalId(), representation->data().id()); - if (from_cache) { - read_from_cache = true; - element = (BRepElement*) from_cache; - } - } -#endif - - if (!read_from_cache) { + BRepElement* element = (BRepElement*)decorate_with_cache_(GeometrySerializer::READ_BREP, product->GlobalId(), std::to_string(representation->data().id()), [this, product, representation]() { if (ifcproduct_iterator == ifcproducts->begin() || !geometry_reuse_ok_for_current_representation_) { - element = kernel.create_brep_for_representation_and_product(settings, representation, product); + return kernel.create_brep_for_representation_and_product(settings, representation, product); } else { - element = kernel.create_brep_for_processed_representation(settings, representation, product, current_shape_model); + return kernel.create_brep_for_processed_representation(settings, representation, product, current_shape_model); } - } + }); Logger::SetProduct(boost::none); @@ -805,12 +780,6 @@ namespace IfcGeom { continue; } -#ifdef WITH_HDF5 - if (cache_ && !read_from_cache) { - cache_->write(element); - } -#endif - return element; } } @@ -825,6 +794,82 @@ namespace IfcGeom { current_shape_model = 0; } + void create_element_( + IfcGeom::MAKE_TYPE_NAME(Kernel)* kernel, + const IfcGeom::IteratorSettings& settings, + geometry_conversion_task* rep) + { + IfcSchema::IfcRepresentation *representation = rep->representation; + IfcSchema::IfcProduct *product = *rep->products->begin(); + + IfcGeom::BRepElement* brep = static_cast(decorate_with_cache_(GeometrySerializer::READ_BREP, product->GlobalId(), std::to_string(representation->data().id()), [kernel, settings, product, representation]() { + return kernel->create_brep_for_representation_and_product(settings, representation, product); + })); + + if (!brep) { + return; + } + + auto elem = process_based_on_settings(settings, brep); + if (!elem) { + return; + } + + rep->breps = { brep }; + rep->elements = { elem }; + + for (auto it = rep->products->begin() + 1; it != rep->products->end(); ++it) { + auto product2 = *it; + IfcGeom::BRepElement* brep2 = static_cast(decorate_with_cache_(GeometrySerializer::READ_BREP, product2->GlobalId(), std::to_string(representation->data().id()), [kernel, settings, product2, representation, brep]() { + return kernel->create_brep_for_processed_representation(settings, representation, product2, brep); + })); + if (brep2) { + auto elem2 = process_based_on_settings(settings, brep2, dynamic_cast(elem)); + if (elem2) { + rep->breps.push_back(brep2); + rep->elements.push_back(elem2); + } + } + } + } + + IfcGeom::Element* process_based_on_settings( + const IfcGeom::IteratorSettings& settings, + IfcGeom::BRepElement* elem, + IfcGeom::TriangulationElement* previous = nullptr) + { + if (settings.get(IfcGeom::IteratorSettings::USE_BREP_DATA)) { + try { + return new IfcGeom::SerializedElement(*elem); + } catch (...) { + Logger::Message(Logger::LOG_ERROR, "Getting a serialized element from model failed."); + return nullptr; + } + } else if (!settings.get(IfcGeom::IteratorSettings::DISABLE_TRIANGULATION)) { + // the part before the hyphen is the representation id + auto gid2 = elem->geometry().id(); + auto hyphen = gid2.find("-"); + if (hyphen != std::string::npos) { + gid2 = gid2.substr(0, hyphen); + } + + return decorate_with_cache_(GeometrySerializer::READ_TRIANGULATION, elem->guid(), gid2, [elem, previous]() { + try { + if (!previous) { + return new TriangulationElement(*elem); + } else { + return new TriangulationElement(*elem, previous->geometry_pointer()); + } + } catch (...) { + Logger::Message(Logger::LOG_ERROR, "Getting a triangulation element from model failed."); + } + return (TriangulationElement*)nullptr; + }); + } else { + return elem; + } + } + public: /// Returns what would be the product for the next shape representation /// @todo Double-check and test the impl. @@ -1023,43 +1068,25 @@ namespace IfcGeom { Logger::Message(Logger::LOG_ERROR, "Getting a serialized element from model failed."); } } else if (!settings.get(IteratorSettings::DISABLE_TRIANGULATION)) { - - bool read_from_cache = false; - -#ifdef WITH_HDF5 - if (cache_) { - // the part before the hyphen is the representation id - auto gid2 = next_shape_model->geometry().id(); - auto hyphen = gid2.find("-"); - if (hyphen != std::string::npos) { - gid2 = gid2.substr(0, hyphen); - } - - auto from_cache = cache_->read(*ifc_file, next_shape_model->guid(), boost::lexical_cast(gid2), GeometrySerializer::READ_TRIANGULATION); - if (from_cache) { - read_from_cache = true; - next_triangulation = (TriangulationElement*)from_cache; - } + // the part before the hyphen is the representation id + auto gid2 = next_shape_model->geometry().id(); + auto hyphen = gid2.find("-"); + if (hyphen != std::string::npos) { + gid2 = gid2.substr(0, hyphen); } -#endif - if (!read_from_cache) { + next_triangulation = (TriangulationElement*)decorate_with_cache_(GeometrySerializer::READ_TRIANGULATION, next_shape_model->guid(), gid2, [this, next_shape_model]() { try { if (ifcproduct_iterator == ifcproducts->begin() || !geometry_reuse_ok_for_current_representation_) { - next_triangulation = new TriangulationElement(*next_shape_model); + return new TriangulationElement(*next_shape_model); } else { - next_triangulation = new TriangulationElement(*next_shape_model, current_triangulation->geometry_pointer()); + return new TriangulationElement(*next_shape_model, current_triangulation->geometry_pointer()); } - -#ifdef WITH_HDF5 - if (cache_) { - cache_->write(next_triangulation); - } -#endif } catch (...) { Logger::Message(Logger::LOG_ERROR, "Getting a triangulation element from model failed."); } - } + return (TriangulationElement*) nullptr; + }); } } diff --git a/src/ifcgeom_schema_agnostic/GeometrySerializer.h b/src/ifcgeom_schema_agnostic/GeometrySerializer.h index d92aea9533..ccea3ff729 100644 --- a/src/ifcgeom_schema_agnostic/GeometrySerializer.h +++ b/src/ifcgeom_schema_agnostic/GeometrySerializer.h @@ -110,7 +110,7 @@ public: virtual void write(const IfcGeom::TriangulationElement* o) = 0; virtual void write(const IfcGeom::BRepElement* o) = 0; virtual void setUnitNameAndMagnitude(const std::string& name, float magnitude) = 0; - virtual const IfcGeom::Element* read(IfcParse::IfcFile& f, const std::string& guid, unsigned int representation_id, read_type rt = READ_BREP) = 0; + virtual IfcGeom::Element* read(IfcParse::IfcFile& f, const std::string& guid, const std::string& representation_id, read_type rt = READ_BREP) = 0; const SerializerSettings& settings() const { return settings_; } SerializerSettings& settings() { return settings_; } @@ -132,7 +132,7 @@ class WriteOnlyGeometrySerializer : public GeometrySerializer { public: WriteOnlyGeometrySerializer(const SerializerSettings& settings) : GeometrySerializer(settings) {} - virtual const IfcGeom::Element* read(IfcParse::IfcFile&, const std::string&, unsigned int, read_type = READ_BREP) { + virtual IfcGeom::Element* read(IfcParse::IfcFile&, const std::string&, const std::string&, read_type = READ_BREP) { throw std::runtime_error("Not supported"); }; }; diff --git a/src/serializers/HdfSerializer.cpp b/src/serializers/HdfSerializer.cpp index d35517bf87..c42e64141e 100644 --- a/src/serializers/HdfSerializer.cpp +++ b/src/serializers/HdfSerializer.cpp @@ -41,10 +41,10 @@ #define read_shape read_text #endif -herr_t print_stack(hid_t, void*) { - /* +herr_t print_stack(hid_t /*estack*/, void*) { // For debugging: when using IfcConvert on Windows with wcout, // it's difficult to get console output of HDF5 stack traces. + /* auto f = fopen("temp.txt", "w"); H5Eprint(estack, f); fclose(f); @@ -258,13 +258,11 @@ void HdfSerializer::remove(const std::string& guid) { } } -const IfcGeom::Element* HdfSerializer::read(IfcParse::IfcFile& f, const std::string& guid, unsigned int representation_id, read_type rt) { +IfcGeom::Element* HdfSerializer::read(IfcParse::IfcFile& f, const std::string& guid, const std::string& representation_id_str, read_type rt) { if (!H5Lexists(file.getId(), guid.c_str(), H5P_DEFAULT)) { return nullptr; } - auto representation_id_str = std::to_string(representation_id); - auto element_group = file.openGroup(guid); if (!H5Lexists(element_group.getId(), representation_id_str.c_str(), H5P_DEFAULT)) { return nullptr; @@ -287,7 +285,7 @@ const IfcGeom::Element* HdfSerializer::read(IfcParse::IfcFile& f, const std::str m44[2][0], m44[2][1], m44[2][2], m44[2][3] ); - auto representation_group = element_group.openGroup(std::to_string(representation_id)); + auto representation_group = element_group.openGroup(representation_id_str); std::string geom_id = read_scalar_attribute(representation_group, "geom_id"); IfcGeom::ElementSettings element_settings(settings_, f.getUnit("LENGTHUNIT").second, type); diff --git a/src/serializers/HdfSerializer.h b/src/serializers/HdfSerializer.h index 2b18791a48..25ae0f098e 100644 --- a/src/serializers/HdfSerializer.h +++ b/src/serializers/HdfSerializer.h @@ -97,7 +97,7 @@ public: void write(const IfcGeom::TriangulationElement* o); void remove(const std::string& guid); - const IfcGeom::Element* read(IfcParse::IfcFile& f, const std::string& guid, unsigned int representation_id, read_type rt = READ_BREP); + IfcGeom::Element* read(IfcParse::IfcFile& f, const std::string& guid, const std::string&, read_type rt = READ_BREP); void finalize() {} bool isTesselated() const { return false; }