Linearizing the use of IfcGeomIterator by integrating it into IfcConvert in full, atm it does not build.

This commit is contained in:
Sander Boer
2019-05-01 18:34:01 +02:00
parent 6468329f01
commit 8ea77bdeca
2 changed files with 1799 additions and 1300 deletions
+553 -54
View File
@@ -49,6 +49,10 @@
#include <set> #include <set>
#include <time.h> #include <time.h>
#include <future>
#include <thread>
#include <chrono>
#if USE_VLD #if USE_VLD
#include <vld.h> #include <vld.h>
#endif #endif
@@ -75,6 +79,29 @@ const std::string TEMP_FILE_EXTENSION = ".tmp";
namespace po = boost::program_options; namespace po = boost::program_options;
struct IfcproductRepresentation
{
int index;
IfcSchema::IfcRepresentation *representation;
IfcSchema::IfcProduct *product;
IfcGeom::Element<real_t> *geom_object;
IfcGeom::BRepElement<real_t> *element;
};
struct Bounds
{
gp_XYZ min;
gp_XYZ max;
};
bool reuse_ok_(SerializerSettings settings, const IfcSchema::IfcProduct::list::ptr &products, IfcGeom::Kernel kernel);
void create_element(SerializerSettings &settings,IfcproductRepresentation &rep);
Bounds compute_bounds(IfcParse::IfcFile* ifc_file, IfcGeom::Kernel kernel);
void print_version() void print_version()
{ {
cout_ << "IfcOpenShell " << IfcSchema::Identifier << " IfcConvert " << IFCOPENSHELL_VERSION << " (OCC " << OCC_VERSION_STRING_EXT << ")\n"; cout_ << "IfcOpenShell " << IfcSchema::Identifier << " IfcConvert " << IFCOPENSHELL_VERSION << " (OCC " << OCC_VERSION_STRING_EXT << ")\n";
@@ -115,6 +142,7 @@ void print_options(const po::options_description& options)
cout_ << std::endl; cout_ << std::endl;
} }
template <typename T> template <typename T>
T change_extension(const T& fn, const T& ext) { T change_extension(const T& fn, const T& ext) {
typename T::size_type dot = fn.find_last_of('.'); typename T::size_type dot = fn.find_last_of('.');
@@ -560,12 +588,18 @@ int main(int argc, char** argv) {
return EXIT_FAILURE; return EXIT_FAILURE;
} }
if (!entity_filter.values.empty()) { entity_filter.update_description(); Logger::Notice(entity_filter.description); } if (!entity_filter.values.empty()) {
if (!layer_filter.values.empty()) { layer_filter.update_description(); Logger::Notice(layer_filter.description); } entity_filter.update_description(); Logger::Notice(entity_filter.description); }
if (!guid_filter.values.empty()) { guid_filter.update_description(); Logger::Notice(guid_filter.description); } if (!layer_filter.values.empty()) {
if (!name_filter.values.empty()) { name_filter.update_description(); Logger::Notice(name_filter.description); } layer_filter.update_description(); Logger::Notice(layer_filter.description); }
if (!desc_filter.values.empty()) { desc_filter.update_description(); Logger::Notice(desc_filter.description); } if (!guid_filter.values.empty()) {
if (!tag_filter.values.empty()) { tag_filter.update_description(); Logger::Notice(tag_filter.description); } guid_filter.update_description(); Logger::Notice(guid_filter.description); }
if (!name_filter.values.empty()) {
name_filter.update_description(); Logger::Notice(name_filter.description); }
if (!desc_filter.values.empty()) {
desc_filter.update_description(); Logger::Notice(desc_filter.description); }
if (!tag_filter.values.empty()) {
tag_filter.update_description(); Logger::Notice(tag_filter.description); }
#ifdef _MSC_VER #ifdef _MSC_VER
if (output_extension == DAE || output_extension == STP || output_extension == IGS) { if (output_extension == DAE || output_extension == STP || output_extension == IGS) {
@@ -600,8 +634,6 @@ int main(int argc, char** argv) {
settings.set(IfcGeom::IteratorSettings::SEARCH_FLOOR, use_element_hierarchy); settings.set(IfcGeom::IteratorSettings::SEARCH_FLOOR, use_element_hierarchy);
settings.set(IfcGeom::IteratorSettings::SITE_LOCAL_PLACEMENT, site_local_placement); settings.set(IfcGeom::IteratorSettings::SITE_LOCAL_PLACEMENT, site_local_placement);
settings.set(IfcGeom::IteratorSettings::BUILDING_LOCAL_PLACEMENT, building_local_placement); settings.set(IfcGeom::IteratorSettings::BUILDING_LOCAL_PLACEMENT, building_local_placement);
settings.set(SerializerSettings::USE_ELEMENT_NAMES, use_element_names); settings.set(SerializerSettings::USE_ELEMENT_NAMES, use_element_names);
settings.set(SerializerSettings::USE_ELEMENT_GUIDS, use_element_guids); settings.set(SerializerSettings::USE_ELEMENT_GUIDS, use_element_guids);
settings.set(SerializerSettings::USE_MATERIAL_NAMES, use_material_names); settings.set(SerializerSettings::USE_MATERIAL_NAMES, use_material_names);
@@ -610,17 +642,25 @@ int main(int argc, char** argv) {
settings.set_deflection_tolerance(deflection_tolerance); settings.set_deflection_tolerance(deflection_tolerance);
settings.precision = precision; settings.precision = precision;
////////////////////////////////////////////////////////////
// Set up serializer
////////////////////////////////////////////////////////////
boost::shared_ptr<GeometrySerializer> serializer; /**< @todo use std::unique_ptr when possible */ boost::shared_ptr<GeometrySerializer> serializer; /**< @todo use std::unique_ptr when possible */
if (output_extension == OBJ) {
if (output_extension == OBJ)
{
// Do not use temp file for MTL as it's such a small file. // Do not use temp file for MTL as it's such a small file.
const path_t mtl_filename = change_extension(output_filename, MTL); const path_t mtl_filename = change_extension(output_filename, MTL);
if (!use_world_coords) { if (!use_world_coords)
{
Logger::Notice("Using world coords when writing WaveFront OBJ files"); Logger::Notice("Using world coords when writing WaveFront OBJ files");
settings.set(IfcGeom::IteratorSettings::USE_WORLD_COORDS, true); settings.set(IfcGeom::IteratorSettings::USE_WORLD_COORDS, true);
} }
serializer = boost::make_shared<WaveFrontOBJSerializer>(IfcUtil::path::to_utf8(output_temp_filename), IfcUtil::path::to_utf8(mtl_filename), settings); serializer = boost::make_shared<WaveFrontOBJSerializer>(IfcUtil::path::to_utf8(output_temp_filename), IfcUtil::path::to_utf8(mtl_filename), settings);
#ifdef WITH_OPENCOLLADA #ifdef WITH_OPENCOLLADA
} else if (output_extension == DAE) { } else if (output_extension == DAE)
{
serializer = boost::make_shared<ColladaSerializer>(IfcUtil::path::to_utf8(output_temp_filename), settings); serializer = boost::make_shared<ColladaSerializer>(IfcUtil::path::to_utf8(output_temp_filename), settings);
#endif #endif
} else if (output_extension == STP) { } else if (output_extension == STP) {
@@ -684,20 +724,196 @@ int main(int argc, char** argv) {
return EXIT_FAILURE; return EXIT_FAILURE;
} }
////////////////////////////////////////////////////////////
// initialize geometry
////////////////////////////////////////////////////////////
serializer->setFile(&ifc_file);
IfcGeom::Iterator<real_t> context_iterator(settings, &ifc_file, filter_funcs); IfcGeom::Iterator<real_t> context_iterator(settings, &ifc_file, filter_funcs);
if (!context_iterator.initialize()) { IfcGeom::Kernel kernel;
/// @todo It would be nice to know and print separate error prints for a case where we found no entities std::string unit_name = "METER" ;
/// and for a case we found no entities that satisfy our filtering criteria. double unit_magnitude = 1.f;
IfcSchema::IfcRepresentation::list::ptr ok_mapped_representations;
IfcSchema::IfcRepresentation::list::ptr representations =
IfcSchema::IfcRepresentation::list::ptr(new IfcSchema::IfcRepresentation::list);
IfcSchema::IfcRepresentation::list::it representation_iterator;
try {
// constructor
// TriangulationElement<P>* current_triangulation =0 ;
// BRepElement<P>* current_shape_model = 0;
// SerializedElement<P>* current_serialization = 0;
kernel.setValue(IfcGeom::Kernel::GV_MAX_FACES_TO_SEW, settings.get(IfcGeom::IteratorSettings::SEW_SHELLS) ? 1000 : -1);
kernel.setValue(IfcGeom::Kernel::GV_DIMENSIONALITY, (settings.get(IfcGeom::IteratorSettings::INCLUDE_CURVES)
? (settings.get(IfcGeom::IteratorSettings::EXCLUDE_SOLIDS_AND_SURFACES) ? -1. : 0.) : +1.));
if (settings.get(IfcGeom::IteratorSettings::BUILDING_LOCAL_PLACEMENT)) {
if (settings.get(IfcGeom::IteratorSettings::SITE_LOCAL_PLACEMENT)) {
Logger::Message(Logger::LOG_WARNING, "building-local-placement takes precedence over site-local-placement");
}
kernel.set_conversion_placement_rel_to(IfcSchema::Type::IfcBuilding);
} else if (settings.get(IfcGeom::IteratorSettings::SITE_LOCAL_PLACEMENT)) {
kernel.set_conversion_placement_rel_to(IfcSchema::Type::IfcSite);
}
// initialize()
// initunits()
IfcSchema::IfcProject::list::ptr projects = ifc_file.entitiesByType<IfcSchema::IfcProject>();
std::set<std::string> allowed_context_types;
std::set<std::string> context_types;
double lowest_precision_encountered = std::numeric_limits<double>::infinity();
bool any_precision_encountered = false;
if (projects->size() == 1) {
IfcSchema::IfcProject* project = *projects->begin();
std::pair<std::string, double> length_unit = kernel.initializeUnits(project->UnitsInContext());
unit_name = length_unit.first;
unit_magnitude = length_unit.second;
} else {
Logger::Error("A single IfcProject is expected (encountered " + boost::lexical_cast<std::string>(projects->size()) + "); unable to read unit information.");
}
allowed_context_types.insert("model");
allowed_context_types.insert("plan");
allowed_context_types.insert("notdefined");
if (!settings.get(IfcGeom::IteratorSettings::EXCLUDE_SOLIDS_AND_SURFACES)) {
// Really this should only be 'Model', as per
// the standard 'Design' is deprecated. So,
// just for backwards compatibility:
context_types.insert("model");
context_types.insert("design");
// Some earlier (?) versions DDS-CAD output their own ContextTypes
context_types.insert("model view");
context_types.insert("detail view");
}
if (settings.get(IfcGeom::IteratorSettings::INCLUDE_CURVES)) {
context_types.insert("plan");
}
representations = IfcSchema::IfcRepresentation::list::ptr(new IfcSchema::IfcRepresentation::list);
ok_mapped_representations = IfcSchema::IfcRepresentation::list::ptr(new IfcSchema::IfcRepresentation::list);
IfcSchema::IfcGeometricRepresentationContext::list::it it;
IfcSchema::IfcGeometricRepresentationSubContext::list::it jt;
IfcSchema::IfcGeometricRepresentationContext::list::ptr contexts =
ifc_file.entitiesByType<IfcSchema::IfcGeometricRepresentationContext>();
IfcSchema::IfcGeometricRepresentationContext::list::ptr filtered_contexts (new IfcSchema::IfcGeometricRepresentationContext::list);
for (it = contexts->begin(); it != contexts->end(); ++it) {
IfcSchema::IfcGeometricRepresentationContext* context = *it;
if (context->is(IfcSchema::Type::IfcGeometricRepresentationSubContext)) {
// Continue, as the list of subcontexts will be considered
// by the parent's context inverse attributes.
continue;
}
try {
if (context->hasContextType()) {
std::string context_type = context->ContextType();
boost::to_lower(context_type);
if (allowed_context_types.find(context_type) == allowed_context_types.end()) {
Logger::Message(Logger::LOG_ERROR, std::string("ContextType '") + context->ContextType() + "' not allowed:", context->entity);
} // == allowed_context_types.end()
if (context_types.find(context_type) != context_types.end()) {
filtered_contexts->push(context);
} // != context_types.end()
} // hasContextType()
} catch (const std::exception& e) {
Logger::Error(e);
}
} // end iterating contexts
// In case no contexts are identified based on their ContextType, all contexts are
// considered. Note that sub contexts are excluded as they are considered later on.
if (filtered_contexts->size() == 0) {
for (it = contexts->begin(); it != contexts->end(); ++it) {
IfcSchema::IfcGeometricRepresentationContext* context = *it;
if (!context->is(IfcSchema::Type::IfcGeometricRepresentationSubContext)) {
filtered_contexts->push(context);
}
}
}
for (it = filtered_contexts->begin(); it != filtered_contexts->end(); ++it) {
IfcSchema::IfcGeometricRepresentationContext* context = *it;
representations->push(context->RepresentationsInContext());
try {
if (context->hasPrecision() && context->Precision() < lowest_precision_encountered) {
lowest_precision_encountered = context->Precision();
any_precision_encountered = true;
}
} catch (const std::exception& e) {
Logger::Error(e);
}
IfcSchema::IfcGeometricRepresentationSubContext::list::ptr sub_contexts = context->HasSubContexts();
for (jt = sub_contexts->begin(); jt != sub_contexts->end(); ++jt) {
representations->push((*jt)->RepresentationsInContext());
}
// There is no need for full recursion as the following is governed by the schema:
// WR31: The parent context shall not be another geometric representation sub context.
} // end iterating filtered_contexts
if (any_precision_encountered) {
// Some arbitrary factor that has proven to work better for the models in the set of test files.
lowest_precision_encountered *= 10.;
lowest_precision_encountered *= unit_magnitude;
if (lowest_precision_encountered < 1.e-7) {
Logger::Message(Logger::LOG_WARNING, "Precision lower than 0.0000001 meter not enforced");
kernel.setValue(IfcGeom::Kernel::GV_PRECISION, 1.e-7);
} else {
kernel.setValue(IfcGeom::Kernel::GV_PRECISION, lowest_precision_encountered);
}
} else {
kernel.setValue(IfcGeom::Kernel::GV_PRECISION, 1.e-5);
}
if (representations->size() == 0) {
Logger::Message(Logger::LOG_ERROR, "No representations encountered in relevant contexts, using all");
representations = ifc_file.entitiesByType<IfcSchema::IfcRepresentation>();
}
if (representations->size() == 0) {
Logger::Message(Logger::LOG_ERROR, "No representations encountered, aborting");
return 0;
}
// representation_iterator = representations->begin();
// ifcproducts.reset();
// if (!create()) {
// return false;
// }
// done = 0;
// total = representations->size();
// return true;
} catch (const std::exception& e) {
Logger::Error(e);
Logger::Error("No geometrical entities found"); Logger::Error("No geometrical entities found");
IfcUtil::path::delete_file(IfcUtil::path::to_utf8(output_temp_filename)); IfcUtil::path::delete_file(IfcUtil::path::to_utf8(output_temp_filename));
write_log(!quiet); write_log(!quiet);
return EXIT_FAILURE; return EXIT_FAILURE;
} }
serializer->setFile(context_iterator.getFile()); //replaces:
// if (!context_iterator.initialize()) {
// /// @todo It would be nice to know and print separate error prints for a case where we found no entities
// /// and for a case we found no entities that satisfy our filtering criteria.
// Logger::Error("No geometrical entities found");
// IfcUtil::path::delete_file(IfcUtil::path::to_utf8(output_temp_filename));
// write_log(!quiet);
// return EXIT_FAILURE;
// }
if (convert_back_units) { if (convert_back_units) {
serializer->setUnitNameAndMagnitude(context_iterator.getUnitName(), static_cast<float>(context_iterator.getUnitMagnitude())); // serializer->setUnitNameAndMagnitude(context_iterator.getUnitName(), static_cast<float>(context_iterator.getUnitMagnitude()));
serializer->setUnitNameAndMagnitude(unit_name, static_cast<float>(unit_magnitude));
} else { } else {
serializer->setUnitNameAndMagnitude("METER", 1.0f); serializer->setUnitNameAndMagnitude("METER", 1.0f);
} }
@@ -705,7 +921,7 @@ int main(int argc, char** argv) {
serializer->writeHeader(); serializer->writeHeader();
int old_progress = quiet ? 0 : -1; int old_progress = quiet ? 0 : -1;
Bounds model_bounds;
if (is_tesselated && (center_model || model_offset)) { if (is_tesselated && (center_model || model_offset)) {
double* offset = serializer->settings().offset; double* offset = serializer->settings().offset;
if (center_model) { if (center_model) {
@@ -715,10 +931,10 @@ int main(int argc, char** argv) {
} }
if (!quiet) Logger::Status("Computing bounds..."); if (!quiet) Logger::Status("Computing bounds...");
context_iterator.compute_bounds(); model_bounds = compute_bounds( &ifc_file, kernel );
if (!quiet) Logger::Status("Done!"); if (!quiet) Logger::Status("Done!");
gp_XYZ center = (context_iterator.bounds_min() + context_iterator.bounds_max()) * 0.5; gp_XYZ center = (model_bounds.min + model_bounds.max) * 0.5;
offset[0] = -center.X(); offset[0] = -center.X();
offset[1] = -center.Y(); offset[1] = -center.Y();
offset[2] = -center.Z(); offset[2] = -center.Z();
@@ -752,50 +968,218 @@ int main(int argc, char** argv) {
// available. // available.
size_t num_created = 0; size_t num_created = 0;
do {
IfcGeom::Element<real_t> *geom_object = context_iterator.get();
if (is_tesselated) ////////////////////////////////////////////////////////////
// start initializing elements for threading
////////////////////////////////////////////////////////////
std::vector<IfcproductRepresentation> IfcproductRepresentations;
// do {
// IfcGeom::Element<real_t> *geom_object = context_iterator.get();
// if (is_tesselated)
// {
// serializer->write(static_cast<const IfcGeom::TriangulationElement<real_t>*>(geom_object));
// }
// else
// {
// serializer->write(static_cast<const IfcGeom::BRepElement<real_t>*>(geom_object));
// }
// if (!no_progress) {
// if (quiet) {
// const int progress = context_iterator.progress();
// for (; old_progress < progress; ++old_progress) {
// std::cout << ".";
// if (stderr_progress)
// std::cerr << ".";
// }
// std::cout << std::flush;
// if (stderr_progress)
// std::cerr << std::flush;
// } else {
// const int progress = context_iterator.progress() / 2;
// if (old_progress != progress) Logger::ProgressBar(progress);
// old_progress = progress;
// }
// }
// } while (++num_created, context_iterator.next());
// if (!no_progress && quiet) {
// for (; old_progress < 100; ++old_progress) {
// std::cout << ".";
// if (stderr_progress)
// std::cerr << ".";
// }
// std::cout << std::flush;
// if (stderr_progress)
// std::cerr << std::flush;
// } else {
// Logger::Status("\rDone creating geometry (" + boost::lexical_cast<std::string>(num_created) +
// " objects) ");
// }
////////////////////////////////////////////////////////////
// Copy/Paste from IfcInfo, fine-tooth comb over vars
////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////
/////// find products associated with representations (... ?)
////////////////////////////////////////////////////////////
IfcSchema::IfcProduct::list::ptr ifcproducts;
IfcSchema::IfcProduct::list::it ifcproduct_iterator;
std::vector<IfcGeom::filter_t> filters_;
IfcGeom::layer_filter layer_filter;
IfcGeom::entity_filter entity_filter;
IfcGeom::string_arg_filter guid_filter(IfcSchema::Type::IfcRoot, 0);
IfcGeom::string_arg_filter name_filter(IfcSchema::Type::IfcRoot, 2);
IfcGeom::string_arg_filter desc_filter(IfcSchema::Type::IfcRoot, 3);
IfcGeom::string_arg_filter tag_filter(IfcSchema::Type::IfcProxy, 8,
IfcSchema::Type::IfcElement,
7);
filters_.emplace_back(boost::ref(layer_filter));
filters_.emplace_back(boost::ref(entity_filter));
filters_.emplace_back(boost::ref(guid_filter));
filters_.emplace_back(boost::ref(name_filter));
filters_.emplace_back(boost::ref(desc_filter));
filters_.emplace_back(boost::ref(tag_filter));
bool geometry_reuse_ok_for_current_representation_;
// functor
struct filter_match
{ {
serializer->write(static_cast<const IfcGeom::TriangulationElement<real_t>*>(geom_object)); filter_match(IfcSchema::IfcProduct *prod) : product(prod) {}
bool operator()(const IfcGeom::filter_t &filter) const { return filter(product); }
IfcSchema::IfcProduct *product;
};
Logger::Status("starting to iterate over representations ");
start = std::chrono::system_clock::now();
int index_count = 0;
for (representation_iterator = representations->begin();
representation_iterator != representations->end(); representation_iterator++)
{
IfcSchema::IfcRepresentation *representation = *representation_iterator;
ifcproducts.reset();
ifcproducts = IfcSchema::IfcProduct::list::ptr(new IfcSchema::IfcProduct::list);
IfcSchema::IfcProduct::list::ptr unfiltered_products =
kernel.products_represented_by(representation);
geometry_reuse_ok_for_current_representation_ = reuse_ok_(settings, unfiltered_products);
IfcSchema::IfcRepresentationMap::list::ptr maps = representation->RepresentationMap();
if (!geometry_reuse_ok_for_current_representation_ && maps->size() == 1)
{
// unfiltered_products contains products represented by this representation by means of
// mapped items. For example because of openings applied to products, reuse might not be
// acceptable and then the products will be processed by means of their immediate
// representation and not the mapped representation.
// IfcRepresentationMaps are also used for IfcTypeProducts, so an additional check is
// performed whether the map is indeed used by IfcMappedItems.
IfcSchema::IfcRepresentationMap *map = *maps->begin();
if (map->MapUsage()->size() > 0)
{
// _nextShape();
// continue;
// NOTE(sander): is this equivalent to _nextShape() ?
continue;
}
}
bool representation_processed_as_mapped_item = false;
IfcSchema::IfcRepresentation *representation_mapped_to =
kernel.representation_mapped_to(representation);
if (representation_mapped_to)
{
// Check if this representation has (or will be) processed as part its mapped
// representation
bool contains = ok_mapped_representations->contains(representation_mapped_to);
bool reuse = reuse_ok_(settings, kernel.products_represented_by(representation_mapped_to));
representation_processed_as_mapped_item = contains || reuse;
}
if (representation_processed_as_mapped_item)
{
ok_mapped_representations->push(representation_mapped_to);
// _nextShape();
// continue;
continue;
}
// Filter the products based on the set of entities and/or names being included or excluded
// for processing.
for (IfcSchema::IfcProduct::list::it jt = unfiltered_products->begin();
jt != unfiltered_products->end(); ++jt)
{
IfcSchema::IfcProduct *prod = *jt;
if (boost::all(filters_, filter_match(prod)))
{
ifcproducts->push(prod);
}
} // end for unfiltered_products
for (ifcproduct_iterator = ifcproducts->begin(); ifcproduct_iterator != ifcproducts->end();
ifcproduct_iterator++)
{
IfcproductRepresentation ir;
ir.index = index_count;
ir.product = *ifcproduct_iterator;
ir.representation = representation;
IfcproductRepresentations.push_back(ir);
index_count++;
} // end for ifcproducts
} // for representation in representations
end = std::chrono::system_clock::now();
elapsed_seconds = end - start;
Logger::Status("iterated over representations: " + std::to_string(elapsed_seconds.count()));
Logger::Status("count: " + std::to_string(index_count));
const unsigned int conc_threads = std::thread::hardware_concurrency();
std::cout << "amount of threads available for use on this machine: " << conc_threads << std::endl;
std::vector<std::future<void>> threadpool;
count = 0;
for (int j = 0; j < (int)IfcproductRepresentations.size();)
{
IfcproductRepresentation &r = IfcproductRepresentations[j];
if (threadpool.size() < conc_threads)
{
std::future<void> fu = std::async(std::launch::async, create_element, std::ref(settings), std::ref(r));
threadpool.emplace_back(std::move(fu));
j++;
} }
else else
{ {
serializer->write(static_cast<const IfcGeom::BRepElement<real_t>*>(geom_object)); bool waiting = true;
while (waiting)
{
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();
threadpool.erase(threadpool.begin() + i);
waiting = false;
} // if
} // for
} // while
} // else
} }
if (!no_progress) { for (std::future<void> &fu : threadpool)
if (quiet) { {
const int progress = context_iterator.progress(); fu.get();
for (; old_progress < progress; ++old_progress) {
std::cout << ".";
if (stderr_progress)
std::cerr << ".";
} }
std::cout << std::flush;
if (stderr_progress)
std::cerr << std::flush;
} else {
const int progress = context_iterator.progress() / 2;
if (old_progress != progress) Logger::ProgressBar(progress);
old_progress = progress;
}
}
} while (++num_created, context_iterator.next());
if (!no_progress && quiet) {
for (; old_progress < 100; ++old_progress) {
std::cout << "."; ////////////////////////////////////////////////////////////
if (stderr_progress) //
std::cerr << "."; ////////////////////////////////////////////////////////////
}
std::cout << std::flush;
if (stderr_progress)
std::cerr << std::flush;
} else {
Logger::Status("\rDone creating geometry (" + boost::lexical_cast<std::string>(num_created) +
" objects) ");
}
serializer->finalize(); serializer->finalize();
// Make sure the dtor is explicitly run here (e.g. output files are closed before renaming them). // Make sure the dtor is explicitly run here (e.g. output files are closed before renaming them).
@@ -1068,3 +1452,118 @@ std::vector<IfcGeom::filter_t> setup_filters(const std::vector<geom_filter>& fil
return filter_funcs; return filter_funcs;
} }
bool reuse_ok_(SerializerSettings settings, const IfcSchema::IfcProduct::list::ptr &products, IfcGeom::Kernel kernel)
{
// IfcGeom::Kernel kernel;
// With world coords enabled, object transformations are directly applied to
// the BRep. There is no way to re-use the geometry for multiple products.
if (settings.get(IfcGeom::IteratorSettings::USE_WORLD_COORDS))
{
return false;
}
std::set<const IfcSchema::IfcMaterial *> associated_single_materials;
for (IfcSchema::IfcProduct::list::it it = products->begin(); it != products->end(); ++it)
{
IfcSchema::IfcProduct *product = *it;
if (!settings.get(IfcGeom::IteratorSettings::DISABLE_OPENING_SUBTRACTIONS) &&
kernel.find_openings(product)->size())
{
return false;
}
if (settings.get(IfcGeom::IteratorSettings::APPLY_LAYERSETS))
{
IfcSchema::IfcRelAssociates::list::ptr associations = product->HasAssociations();
for (IfcSchema::IfcRelAssociates::list::it jt = associations->begin();
jt != associations->end(); ++jt)
{
IfcSchema::IfcRelAssociatesMaterial *assoc =
(*jt)->as<IfcSchema::IfcRelAssociatesMaterial>();
if (assoc)
{
if (assoc->RelatingMaterial()->is(IfcSchema::Type::IfcMaterialLayerSetUsage))
{
// TODO: Check whether single layer?
return false;
}
}
}
}
// Note that this can be a nullptr (!), but the fact that set size should be one still holds
associated_single_materials.insert(kernel.get_single_material_association(product));
if (associated_single_materials.size() > 1)
return false;
}
return associated_single_materials.size() == 1;
}
void create_element(SerializerSettings &settings, IfcproductRepresentation &rep)
{
Logger::Status("processing item #: " + std::to_string(rep.index));
IfcGeom::Kernel kernel;
IfcSchema::IfcRepresentation *representation= rep.representation;
IfcSchema::IfcProduct *product = rep.product;
// IfcGeom::BRepElement<real_t> *element;
rep.element =
kernel.create_brep_for_representation_and_product<real_t>(settings, representation, product);
//if(geometry_reuse_ok_for_current_representation_)
// {
// // element = kernel.create_brep_for_processed_representation(settings, representation,
// // product,
// // current_shape_model);
// }
return;
}
//@todo MOVE this include
#include <gp_GTrsf.hxx>
Bounds compute_bounds(IfcParse::IfcFile* ifc_file, IfcGeom::Kernel kernel)
{
gp_XYZ bounds_min_;
gp_XYZ bounds_max_;
Bounds bounds;
for (int i = 1; i < 4; ++i) {
bounds_min_.SetCoord(i, std::numeric_limits<double>::infinity());
bounds_max_.SetCoord(i, -std::numeric_limits<double>::infinity());
}
IfcSchema::IfcProduct::list::ptr products = ifc_file->entitiesByType<IfcSchema::IfcProduct>();
for (IfcSchema::IfcProduct::list::it iter = products->begin(); iter != products->end(); ++iter) {
IfcSchema::IfcProduct* product = *iter;
if (product->hasObjectPlacement()) {
// Use a fresh trsf every time in order to prevent the result to be concatenated
gp_Trsf trsf;
bool success = false;
try {
success = kernel.convert(product->ObjectPlacement(), trsf);
} catch (const std::exception& e) {
Logger::Error(e);
} catch (...) {
Logger::Error("Failed to construct placement");
}
if (!success) {
continue;
}
const gp_XYZ& pos = trsf.TranslationPart();
bounds_min_.SetX(std::min(bounds_min_.X(), pos.X()));
bounds_min_.SetY(std::min(bounds_min_.Y(), pos.Y()));
bounds_min_.SetZ(std::min(bounds_min_.Z(), pos.Z()));
bounds_max_.SetX(std::max(bounds_max_.X(), pos.X()));
bounds_max_.SetY(std::max(bounds_max_.Y(), pos.Y()));
bounds_max_.SetZ(std::max(bounds_max_.Z(), pos.Z()));
}
}
bounds.min = bounds_min_;
bounds.max = bounds_max_;
return bounds;
}