Merge branch 'v0.6.0' into v0.7.0

This commit is contained in:
Thomas Krijnen
2019-08-02 17:56:45 +02:00
16 changed files with 643 additions and 222 deletions
@@ -13,8 +13,8 @@ namespace IfcGeom {
namespace {
template <typename P, typename PP>
struct MAKE_TYPE_NAME(factory_t) {
IfcGeom::IteratorImplementation<P, PP>* operator()(const std::string& geometry_engine, const IfcGeom::IteratorSettings& settings, IfcParse::IfcFile* file, const std::vector<IfcGeom::filter_t>& filters) const {
return new IfcGeom::MAKE_TYPE_NAME(IteratorImplementation_)<P, PP>(geometry_engine, settings, file, filters);
IfcGeom::IteratorImplementation<P, PP>* operator()(const std::string& geometry_engine, const IfcGeom::IteratorSettings& settings, IfcParse::IfcFile* file, const std::vector<IfcGeom::filter_t>& filters, int num_threads) const {
return new IfcGeom::MAKE_TYPE_NAME(IteratorImplementation_)<P, PP>(geometry_engine, settings, file, filters, num_threads);
}
};
}
@@ -63,6 +63,11 @@
#include <vector>
#include <limits>
#include <algorithm>
#include <atomic>
#include <future>
#include <thread>
#include <chrono>
#include <boost/algorithm/string.hpp>
@@ -90,6 +95,8 @@
#include INCLUDE_SCHEMA(IfcSchema)
#undef INCLUDE_SCHEMA
#include <atomic>
// The infamous min & max Win32 #defines can leak here from OCE depending on the build configuration
#ifdef min
#undef min
@@ -98,12 +105,95 @@
#undef max
#endif
namespace {
template <typename P, typename PP=P>
struct geometry_conversion_task {
int index;
IfcSchema::IfcRepresentation *representation;
IfcSchema::IfcProduct::list::ptr products;
std::vector<IfcGeom::NativeElement<P, PP>*> breps;
std::vector<IfcGeom::Element<P, PP>*> elements;
};
template <typename P, typename PP=P>
IfcGeom::Element<P, PP>* process_based_on_settings(
const IfcGeom::IteratorSettings& settings,
IfcGeom::NativeElement<P, PP>* elem,
IfcGeom::TriangulationElement<P, PP>* previous=nullptr)
{
if (settings.get(IfcGeom::IteratorSettings::USE_BREP_DATA)) {
try {
return new IfcGeom::SerializedElement<P, PP>(*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<P, PP>(*elem);
} else {
return new IfcGeom::TriangulationElement<P, PP>(*elem, previous->geometry_pointer());
}
} catch (...) {
Logger::Message(Logger::LOG_ERROR, "Getting a triangulation element from model failed.");
return nullptr;
}
} else {
return elem;
}
}
template <typename P, typename PP = P>
void create_element(
IfcGeom::MAKE_TYPE_NAME(AbstractKernel)* kernel,
const IfcGeom::IteratorSettings& settings,
geometry_conversion_task<P, PP>* rep)
{
IfcSchema::IfcRepresentation *representation = rep->representation;
IfcSchema::IfcProduct *product = *rep->products->begin();
auto brep = kernel->create_brep_for_representation_and_product<P, PP>(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<P, PP>(settings, representation, *it, brep);
if (brep2) {
auto elem2 = process_based_on_settings(settings, brep, dynamic_cast<IfcGeom::TriangulationElement<P, PP>*>(elem));
if (elem2) {
rep->breps.push_back(brep2);
rep->elements.push_back(elem2);
}
}
}
}
}
namespace IfcGeom {
template <typename P, typename PP>
class MAKE_TYPE_NAME(IteratorImplementation_) : public IteratorImplementation<P, PP> {
private:
int num_threads_;
std::atomic<int> progress_;
std::vector<geometry_conversion_task<P, PP>> tasks_;
std::vector<IfcGeom::Element<P, PP>*> all_processed_elements_;
std::vector<IfcGeom::NativeElement<P, PP>*> all_processed_native_elements_;
typename std::vector<IfcGeom::Element<P, PP>*>::const_iterator task_result_iterator_;
typename std::vector<IfcGeom::NativeElement<P, PP>*>::const_iterator native_task_result_iterator_;
std::string geometry_library_;
MAKE_TYPE_NAME(IteratorImplementation_)(const MAKE_TYPE_NAME(IteratorImplementation_)&); // N/I
MAKE_TYPE_NAME(IteratorImplementation_)& operator=(const MAKE_TYPE_NAME(IteratorImplementation_)&); // N/I
@@ -245,16 +335,118 @@ namespace IfcGeom {
representation_iterator = representations->begin();
ifcproducts.reset();
if (!create()) {
return false;
}
done = 0;
total = representations->size();
if (num_threads_ != 1) {
collect();
process_concurrently();
} else {
if (!create()) {
return false;
}
}
return true;
}
void collect() {
int i = 0;
IfcSchema::IfcProduct::list* previous = nullptr;
while (auto rp = get_next_task()) {
// Note that get_next_task() mutates the state of the iterator
// we use that capture all products that can be processed as
// part of this representation and then keep iterating until
// the underlying list of products changes.
if (ifcproducts.get() != previous) {
previous = ifcproducts.get();
geometry_conversion_task<P, PP> t;
t.index = i++;
t.representation = *representation_iterator;
t.products = ifcproducts;
tasks_.emplace_back(t);
}
_nextShape();
}
}
void process_concurrently() {
size_t conc_threads = num_threads_;
if (conc_threads > tasks_.size()) {
conc_threads = tasks_.size();
}
std::vector<MAKE_TYPE_NAME(AbstractKernel)*> kernel_pool;
kernel_pool.reserve(conc_threads);
for (unsigned i = 0; i < conc_threads; ++i) {
kernel_pool.push_back((MAKE_TYPE_NAME(AbstractKernel)*) impl::kernel_implementations().construct(ifc_file->schema()->name(), geometry_library_, ifc_file));
}
std::vector<std::future<void>> threadpool;
int old_progress = -1;
int processed = 0;
Logger::ProgressBar(0);
for (auto& rep : tasks_) {
MAKE_TYPE_NAME(AbstractKernel)* K = nullptr;
if (threadpool.size() < kernel_pool.size()) {
K = kernel_pool[threadpool.size()];
}
while (threadpool.size() == conc_threads) {
for (int i = 0; i < (int)threadpool.size(); i++) {
std::future<void> &fu = threadpool[i];
std::future_status status;
status = fu.wait_for(std::chrono::seconds(0));
if (status == std::future_status::ready) {
fu.get();
processed += 1;
progress_ = processed * 50 / tasks_.size();
if (progress_ != old_progress) {
Logger::ProgressBar(progress_);
old_progress = progress_;
}
std::swap(threadpool[i], threadpool.back());
threadpool.pop_back();
std::swap(kernel_pool[i], kernel_pool.back());
K = kernel_pool.back();
break;
} // if
} // for
} // while
std::future<void> fu = std::async(std::launch::async, create_element<P, PP>, K, std::ref(settings), &rep);
threadpool.emplace_back(std::move(fu));
}
for (std::future<void> &fu : threadpool) {
fu.get();
processed += 1;
progress_ = processed * 50 / tasks_.size();
if (progress_ != old_progress) {
Logger::ProgressBar(progress_);
old_progress = progress_;
}
}
for (auto& rep : tasks_) {
all_processed_elements_.insert(all_processed_elements_.end(), rep.elements.begin(), rep.elements.end());
all_processed_native_elements_.insert(all_processed_native_elements_.end(), rep.breps.begin(), rep.breps.end());
}
task_result_iterator_ = all_processed_elements_.begin();
native_task_result_iterator_ = all_processed_native_elements_.begin();
Logger::Status("\rDone creating geometry (" + boost::lexical_cast<std::string>(all_processed_elements_.size()) +
" objects) ");
}
/// Computes model's bounding box (bounds_min and bounds_max).
/// @note Can take several minutes for large files.
void compute_bounds()
@@ -296,7 +488,13 @@ namespace IfcGeom {
}
}
int progress() const { return 100 * done / total; }
int progress() const {
if (num_threads_ == 1) {
return 100 * done / total;
} else {
return progress_;
}
}
const std::string& getUnitName() const { return unit_name; }
@@ -360,13 +558,13 @@ namespace IfcGeom {
return associated_single_materials.size() == 1;
}
NativeElement<P, PP>* create_shape_model_for_next_entity() {
boost::optional<std::pair<IfcSchema::IfcRepresentation*, IfcSchema::IfcProduct*>> get_next_task() {
for (;;) {
IfcSchema::IfcRepresentation* representation;
if ( representation_iterator == representations->end() ) {
if (representation_iterator == representations->end()) {
representations.reset();
return 0; // reached the end of our list of representations
return boost::none; // reached the end of our list of representations
}
representation = *representation_iterator;
@@ -382,12 +580,12 @@ namespace IfcGeom {
}
}
if (ifcproducts->size() == 0) {
_nextShape();
continue;
}
if (ifcproducts->size() == 0) {
_nextShape();
continue;
}
geometry_reuse_ok_for_current_representation_ = reuse_ok_(ifcproducts);
geometry_reuse_ok_for_current_representation_ = reuse_ok_(ifcproducts);
IfcSchema::IfcRepresentationMap::list::ptr maps = representation->RepresentationMap();
@@ -414,7 +612,7 @@ namespace IfcGeom {
}
if (representation_processed_as_mapped_item) {
ok_mapped_representations->push(representation_mapped_to);
ok_mapped_representations->push(representation_mapped_to);
_nextShape();
continue;
}
@@ -423,13 +621,28 @@ namespace IfcGeom {
}
// Have we reached the end of our list of IfcProducts?
if ( ifcproduct_iterator == ifcproducts->end() ) {
if (ifcproduct_iterator == ifcproducts->end()) {
_nextShape();
continue;
}
IfcSchema::IfcProduct* product = *ifcproduct_iterator;
Logger::SetProduct(product);
return std::make_pair(representation, product);
}
}
NativeElement<P, PP>* create_shape_model_for_next_entity() {
for (;;) {
auto rp = get_next_task();
if (!rp) {
return nullptr;
}
auto representation = rp->first;
auto product = rp->second;
Logger::SetProduct(product);
NativeElement<P, PP>* element;
if (ifcproduct_iterator == ifcproducts->begin() || !geometry_reuse_ok_for_current_representation_) {
@@ -477,13 +690,23 @@ namespace IfcGeom {
/// Moves to the next shape representation, create its geometry, and returns the associated product.
/// Use get() to retrieve the created geometry.
IfcUtil::IfcBaseClass* next() {
// Increment the iterator over the list of products using the current
// shape representation
if (ifcproducts) {
++ifcproduct_iterator;
}
if (num_threads_ != 1) {
task_result_iterator_++;
native_task_result_iterator_++;
if (task_result_iterator_ == all_processed_elements_.end()) {
return nullptr;
} else {
return (*task_result_iterator_)->product();
}
} else {
// Increment the iterator over the list of products using the current
// shape representation
if (ifcproducts) {
++ifcproduct_iterator;
}
return create();
return create();
}
}
/// Gets the representation of the current geometrical entity.
@@ -491,9 +714,18 @@ namespace IfcGeom {
{
// TODO: Test settings and throw
Element<P, PP>* ret = 0;
if (current_triangulation) { ret = current_triangulation; }
else if (current_serialization) { ret = current_serialization; }
else if (current_shape_model) { ret = current_shape_model; }
if (num_threads_ != 1) {
ret = *task_result_iterator_;
} else {
if (current_triangulation) {
ret = current_triangulation;
} else if (current_serialization) {
ret = current_serialization;
} else if (current_shape_model) {
ret = current_shape_model;
}
}
// If we want to organize the element considering their hierarchy
if (settings.get(IteratorSettings::SEARCH_FLOOR))
@@ -548,7 +780,11 @@ namespace IfcGeom {
NativeElement<P, PP>* get_native()
{
// TODO: Test settings and throw
return current_shape_model;
if (num_threads_ != 1) {
return *native_task_result_iterator_;
} else {
return current_shape_model;
}
}
const Element<P, PP>* get_object(int id) {
@@ -678,11 +914,13 @@ namespace IfcGeom {
bool owns_ifc_file;
public:
MAKE_TYPE_NAME(IteratorImplementation_)(const std::string& geometry_library, const IteratorSettings& settings, IfcParse::IfcFile* file, const std::vector<IfcGeom::filter_t>& filters)
MAKE_TYPE_NAME(IteratorImplementation_)(const std::string& geometry_library, const IteratorSettings& settings, IfcParse::IfcFile* file, const std::vector<IfcGeom::filter_t>& filters, int num_threads)
: settings(settings)
, ifc_file(file)
, filters_(filters)
, owns_ifc_file(false)
, num_threads_(num_threads)
, geometry_library_(geometry_library)
{
kernel = (MAKE_TYPE_NAME(AbstractKernel)*) impl::kernel_implementations().construct(file->schema()->name(), geometry_library, file);
// kernel = new Kernel(geometry_library, file);
@@ -694,6 +932,16 @@ namespace IfcGeom {
delete ifc_file;
}
if (settings.get(IfcGeom::IteratorSettings::DISABLE_TRIANGULATION)) {
for (auto& p : all_processed_native_elements_) {
delete p;
}
}
for (auto& p : all_processed_elements_) {
delete p;
}
free_shapes();
}
};
@@ -83,19 +83,19 @@ namespace IfcGeom {
IteratorImplementation<P, PP>* implementation_;
public:
Iterator(const IfcGeom::IteratorSettings& settings, IfcParse::IfcFile* file, const std::string& geometry_library="opencascade")
Iterator(const IfcGeom::IteratorSettings& settings, IfcParse::IfcFile* file, const std::string& geometry_library="opencascade", int num_threads = 1)
: file_(file)
, settings_(settings)
{
implementation_ = iterator_implementations<P, PP>().construct(file_->schema()->name(), geometry_library, settings, file, filters_);
implementation_ = iterator_implementations<P, PP>().construct(file_->schema()->name(), geometry_library, settings, file, filters_, num_threads);
}
Iterator(const IfcGeom::IteratorSettings& settings, IfcParse::IfcFile* file, const std::vector<IfcGeom::filter_t>& filters, const std::string& geometry_library = "opencascade")
Iterator(const IfcGeom::IteratorSettings& settings, IfcParse::IfcFile* file, const std::vector<IfcGeom::filter_t>& filters, const std::string& geometry_library = "opencascade", int num_threads = 1)
: file_(file)
, settings_(settings)
, filters_(filters)
{
implementation_ = iterator_implementations<P, PP>().construct(file_->schema()->name(), geometry_library, settings, file, filters_);
implementation_ = iterator_implementations<P, PP>().construct(file_->schema()->name(), geometry_library, settings, file, filters_, num_threads);
}
bool initialize() {
@@ -31,14 +31,14 @@ void IteratorFactoryImplementation<P, PP>::bind(const std::string& schema_name,
}
template <typename P, typename PP>
IfcGeom::IteratorImplementation<P, PP>* IteratorFactoryImplementation<P, PP>::construct(const std::string& schema_name, const std::string& geometry_library, const IfcGeom::IteratorSettings& settings, IfcParse::IfcFile* file, const std::vector<IfcGeom::filter_t>& filters) {
IfcGeom::IteratorImplementation<P, PP>* IteratorFactoryImplementation<P, PP>::construct(const std::string& schema_name, const std::string& geometry_library, const IfcGeom::IteratorSettings& settings, IfcParse::IfcFile* file, const std::vector<IfcGeom::filter_t>& filters, int num_threads) {
const std::string schema_name_lower = boost::to_lower_copy(schema_name);
typename std::map<std::string, typename get_factory_type<P, PP>::type>::const_iterator it;
it = this->find(schema_name_lower);
if (it == this->end()) {
throw IfcParse::IfcException("No geometry iterator registered for " + schema_name);
}
return it->second(geometry_library, settings, file, filters);
return it->second(geometry_library, settings, file, filters, num_threads);
}
@@ -23,9 +23,9 @@ namespace IfcGeom {
class NativeElement;
}
typedef boost::function4<IfcGeom::IteratorImplementation<float, float>*, const std::string&, const IfcGeom::IteratorSettings&, IfcParse::IfcFile*, const std::vector<IfcGeom::filter_t>&> iterator_float_float_fn;
typedef boost::function4<IfcGeom::IteratorImplementation<float, double>*, const std::string&, const IfcGeom::IteratorSettings&, IfcParse::IfcFile*, const std::vector<IfcGeom::filter_t>&> iterator_float_double_fn;
typedef boost::function4<IfcGeom::IteratorImplementation<double, double>*, const std::string&, const IfcGeom::IteratorSettings&, IfcParse::IfcFile*, const std::vector<IfcGeom::filter_t>&> iterator_double_double_fn;
typedef boost::function5<IfcGeom::IteratorImplementation<float, float>*, const std::string&, const IfcGeom::IteratorSettings&, IfcParse::IfcFile*, const std::vector<IfcGeom::filter_t>&, int> iterator_float_float_fn;
typedef boost::function5<IfcGeom::IteratorImplementation<float, double>*, const std::string&, const IfcGeom::IteratorSettings&, IfcParse::IfcFile*, const std::vector<IfcGeom::filter_t>&, int> iterator_float_double_fn;
typedef boost::function5<IfcGeom::IteratorImplementation<double, double>*, const std::string&, const IfcGeom::IteratorSettings&, IfcParse::IfcFile*, const std::vector<IfcGeom::filter_t>&, int> iterator_double_double_fn;
template <typename P, typename PP>
struct get_factory_type {};
@@ -50,7 +50,7 @@ class IteratorFactoryImplementation : public std::map<std::string, typename get_
public:
IteratorFactoryImplementation();
void bind(const std::string& schema_name, typename get_factory_type<P, PP>::type fn);
IfcGeom::IteratorImplementation<P, PP>* construct(const std::string& schema_name, const std::string& geometry_library, const IfcGeom::IteratorSettings&, IfcParse::IfcFile*, const std::vector<IfcGeom::filter_t>&);
IfcGeom::IteratorImplementation<P, PP>* construct(const std::string& schema_name, const std::string& geometry_library, const IfcGeom::IteratorSettings&, IfcParse::IfcFile*, const std::vector<IfcGeom::filter_t>&, int);
};
template <typename P, typename PP>