mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-19 14:41:25 +00:00
#1785 geometry caching on multi threaded iterator
This commit is contained in:
@@ -107,66 +107,6 @@ namespace {
|
|||||||
std::vector<IfcGeom::BRepElement*> breps;
|
std::vector<IfcGeom::BRepElement*> breps;
|
||||||
std::vector<IfcGeom::Element*> elements;
|
std::vector<IfcGeom::Element*> 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<IfcGeom::TriangulationElement*>(elem));
|
|
||||||
if (elem2) {
|
|
||||||
rep->breps.push_back(brep2);
|
|
||||||
rep->elements.push_back(elem2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace IfcGeom {
|
namespace IfcGeom {
|
||||||
@@ -380,7 +320,17 @@ namespace IfcGeom {
|
|||||||
} // for
|
} // for
|
||||||
} // while
|
} // while
|
||||||
|
|
||||||
std::future<void> fu = std::async(std::launch::async, create_element, K, std::ref(settings), &rep);
|
std::future<void> 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));
|
threadpool.emplace_back(std::move(fu));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -766,6 +716,44 @@ namespace IfcGeom {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::mutex caching_mutex_;
|
||||||
|
|
||||||
|
template <typename Fn>
|
||||||
|
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<std::mutex> 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<std::mutex> 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() {
|
BRepElement* create_shape_model_for_next_entity() {
|
||||||
for (;;) {
|
for (;;) {
|
||||||
auto rp = get_next_task();
|
auto rp = get_next_task();
|
||||||
@@ -777,26 +765,13 @@ namespace IfcGeom {
|
|||||||
|
|
||||||
Logger::SetProduct(product);
|
Logger::SetProduct(product);
|
||||||
|
|
||||||
bool read_from_cache = false;
|
BRepElement* element = (BRepElement*)decorate_with_cache_(GeometrySerializer::READ_BREP, product->GlobalId(), std::to_string(representation->data().id()), [this, product, representation]() {
|
||||||
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) {
|
|
||||||
if (ifcproduct_iterator == ifcproducts->begin() || !geometry_reuse_ok_for_current_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 {
|
} 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);
|
Logger::SetProduct(boost::none);
|
||||||
|
|
||||||
@@ -805,12 +780,6 @@ namespace IfcGeom {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef WITH_HDF5
|
|
||||||
if (cache_ && !read_from_cache) {
|
|
||||||
cache_->write(element);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return element;
|
return element;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -825,6 +794,82 @@ namespace IfcGeom {
|
|||||||
current_shape_model = 0;
|
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<IfcGeom::BRepElement*>(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<IfcGeom::BRepElement*>(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<IfcGeom::TriangulationElement*>(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:
|
public:
|
||||||
/// Returns what would be the product for the next shape representation
|
/// Returns what would be the product for the next shape representation
|
||||||
/// @todo Double-check and test the impl.
|
/// @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.");
|
Logger::Message(Logger::LOG_ERROR, "Getting a serialized element from model failed.");
|
||||||
}
|
}
|
||||||
} else if (!settings.get(IteratorSettings::DISABLE_TRIANGULATION)) {
|
} else if (!settings.get(IteratorSettings::DISABLE_TRIANGULATION)) {
|
||||||
|
// the part before the hyphen is the representation id
|
||||||
bool read_from_cache = false;
|
auto gid2 = next_shape_model->geometry().id();
|
||||||
|
auto hyphen = gid2.find("-");
|
||||||
#ifdef WITH_HDF5
|
if (hyphen != std::string::npos) {
|
||||||
if (cache_) {
|
gid2 = gid2.substr(0, hyphen);
|
||||||
// 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<int>(gid2), GeometrySerializer::READ_TRIANGULATION);
|
|
||||||
if (from_cache) {
|
|
||||||
read_from_cache = true;
|
|
||||||
next_triangulation = (TriangulationElement*)from_cache;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
if (!read_from_cache) {
|
next_triangulation = (TriangulationElement*)decorate_with_cache_(GeometrySerializer::READ_TRIANGULATION, next_shape_model->guid(), gid2, [this, next_shape_model]() {
|
||||||
try {
|
try {
|
||||||
if (ifcproduct_iterator == ifcproducts->begin() || !geometry_reuse_ok_for_current_representation_) {
|
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 {
|
} 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 (...) {
|
} catch (...) {
|
||||||
Logger::Message(Logger::LOG_ERROR, "Getting a triangulation element from model failed.");
|
Logger::Message(Logger::LOG_ERROR, "Getting a triangulation element from model failed.");
|
||||||
}
|
}
|
||||||
}
|
return (TriangulationElement*) nullptr;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -110,7 +110,7 @@ public:
|
|||||||
virtual void write(const IfcGeom::TriangulationElement* o) = 0;
|
virtual void write(const IfcGeom::TriangulationElement* o) = 0;
|
||||||
virtual void write(const IfcGeom::BRepElement* o) = 0;
|
virtual void write(const IfcGeom::BRepElement* o) = 0;
|
||||||
virtual void setUnitNameAndMagnitude(const std::string& name, float magnitude) = 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_; }
|
const SerializerSettings& settings() const { return settings_; }
|
||||||
SerializerSettings& settings() { return settings_; }
|
SerializerSettings& settings() { return settings_; }
|
||||||
@@ -132,7 +132,7 @@ class WriteOnlyGeometrySerializer : public GeometrySerializer {
|
|||||||
public:
|
public:
|
||||||
WriteOnlyGeometrySerializer(const SerializerSettings& settings) : GeometrySerializer(settings) {}
|
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");
|
throw std::runtime_error("Not supported");
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -41,10 +41,10 @@
|
|||||||
#define read_shape read_text
|
#define read_shape read_text
|
||||||
#endif
|
#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,
|
// For debugging: when using IfcConvert on Windows with wcout,
|
||||||
// it's difficult to get console output of HDF5 stack traces.
|
// it's difficult to get console output of HDF5 stack traces.
|
||||||
|
/*
|
||||||
auto f = fopen("temp.txt", "w");
|
auto f = fopen("temp.txt", "w");
|
||||||
H5Eprint(estack, f);
|
H5Eprint(estack, f);
|
||||||
fclose(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)) {
|
if (!H5Lexists(file.getId(), guid.c_str(), H5P_DEFAULT)) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto representation_id_str = std::to_string(representation_id);
|
|
||||||
|
|
||||||
auto element_group = file.openGroup(guid);
|
auto element_group = file.openGroup(guid);
|
||||||
if (!H5Lexists(element_group.getId(), representation_id_str.c_str(), H5P_DEFAULT)) {
|
if (!H5Lexists(element_group.getId(), representation_id_str.c_str(), H5P_DEFAULT)) {
|
||||||
return nullptr;
|
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]
|
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<std::string>(representation_group, "geom_id");
|
std::string geom_id = read_scalar_attribute<std::string>(representation_group, "geom_id");
|
||||||
|
|
||||||
IfcGeom::ElementSettings element_settings(settings_, f.getUnit("LENGTHUNIT").second, type);
|
IfcGeom::ElementSettings element_settings(settings_, f.getUnit("LENGTHUNIT").second, type);
|
||||||
|
|||||||
@@ -97,7 +97,7 @@ public:
|
|||||||
void write(const IfcGeom::TriangulationElement* o);
|
void write(const IfcGeom::TriangulationElement* o);
|
||||||
void remove(const std::string& guid);
|
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() {}
|
void finalize() {}
|
||||||
bool isTesselated() const { return false; }
|
bool isTesselated() const { return false; }
|
||||||
|
|||||||
Reference in New Issue
Block a user