Fixes for transform and mapped item reuse in taxonomy

This commit is contained in:
Thomas Krijnen
2020-07-09 22:09:54 +02:00
parent 0e2bac5e3b
commit 6d59e6ea90
7 changed files with 162 additions and 109 deletions
-5
View File
@@ -15,15 +15,10 @@ namespace ifcopenshell {
namespace geometry {
class Element;
class NativeElement;
struct geometry_conversion_task {
int index;
IfcUtil::IfcBaseEntity* representation;
IfcEntityList::ptr products;
std::vector<ifcopenshell::geometry::NativeElement*> breps;
std::vector<ifcopenshell::geometry::Element*> elements;
};
typedef boost::function<bool(IfcUtil::IfcBaseEntity*)> filter_t;
+12 -36
View File
@@ -513,12 +513,14 @@ taxonomy::item* mapping::map_impl(const IfcSchema::IfcCartesianTransformationOpe
scale3 = nu->hasScale3() ? nu->Scale3() : scale1;
}
*m->components <<
Eigen::Matrix4d tmp;
tmp <<
axis1 * scale1,
axis2 * scale2,
axis3 * scale3,
origin;
*m->components = tmp.inverse();
m->components->transposeInPlace();
// @todo tag identity?
@@ -560,7 +562,7 @@ taxonomy::item* mapping::map_impl(const IfcSchema::IfcLocalPlacement* inst) {
return m4;
}
IfcSchema::IfcProduct::list::ptr mapping::products_represented_by(const IfcSchema::IfcRepresentation* representation) {
IfcSchema::IfcProduct::list::ptr mapping::products_represented_by(const IfcSchema::IfcRepresentation* representation, bool only_direct) {
IfcSchema::IfcProduct::list::ptr products(new IfcSchema::IfcProduct::list);
IfcSchema::IfcProductRepresentation::list::ptr prodreps = representation->OfProductRepresentation();
@@ -575,6 +577,10 @@ IfcSchema::IfcProduct::list::ptr mapping::products_represented_by(const IfcSchem
products->push((*it)->data().getInverse((&IfcSchema::IfcProduct::Class()), -1)->as<IfcSchema::IfcProduct>());
}
if (only_direct) {
return products;
}
IfcSchema::IfcRepresentationMap::list::ptr maps = representation->RepresentationMap();
if (maps->size() == 1) {
IfcSchema::IfcRepresentationMap* rmap = *maps->begin();
@@ -777,46 +783,16 @@ void mapping::get_representations(std::vector<geometry_conversion_task>& tasks,
int task_index = 0;
for (auto representation : *representations) {
// There used to be a whole lot of magic in here to pair multiple products with,
// representations but this is now handled at a later stage where equivalent
// taxonomy::items (sorted based on std::less) are grouped.
// Init. the list of filtered IfcProducts for this representation
// Include only the desired products for processing.
IfcSchema::IfcProduct::list::ptr ifcproducts = filter_products(products_represented_by(representation), filters);
IfcSchema::IfcProduct::list::ptr ifcproducts = filter_products(products_represented_by(representation, true), filters);
if (ifcproducts->size() == 0) {
continue;
}
auto geometry_reuse_ok_for_current_representation_ = reuse_ok_(s, ifcproducts);
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) {
continue;
}
}
// Check if this represenation has (or will be) processed as part its mapped representation
bool representation_processed_as_mapped_item = false;
IfcSchema::IfcRepresentation* rep_mapped_to = representation_mapped_to(representation);
if (rep_mapped_to) {
representation_processed_as_mapped_item = geometry_reuse_ok_for_current_representation_ && (
ok_mapped_representations->contains(rep_mapped_to) || reuse_ok_(s, filter_products(products_represented_by(rep_mapped_to), filters)));
}
if (representation_processed_as_mapped_item) {
ok_mapped_representations->push(rep_mapped_to);
continue;
}
// @todo, fix this properly by considering the mapped geometry types in the representation.
if (representation->hasRepresentationIdentifier() && representation->RepresentationIdentifier() == "Body") {
geometry_conversion_task task;
+1 -1
View File
@@ -31,7 +31,7 @@ namespace geometry {
const IfcSchema::IfcMaterial* get_single_material_association(const IfcSchema::IfcProduct* product);
IfcSchema::IfcRepresentation* representation_mapped_to(const IfcSchema::IfcRepresentation* representation);
IfcSchema::IfcProduct::list::ptr products_represented_by(const IfcSchema::IfcRepresentation* representation);
IfcSchema::IfcProduct::list::ptr products_represented_by(const IfcSchema::IfcRepresentation* representation, bool only_direct=false);
bool reuse_ok_(settings& s, const IfcSchema::IfcProduct::list::ptr& products);
IfcEntityList::ptr find_openings(const IfcSchema::IfcProduct* product);
IfcUtil::IfcBaseEntity* get_decomposing_entity(IfcUtil::IfcBaseEntity* product, bool include_openings);
+83 -48
View File
@@ -9,15 +9,14 @@ ifcopenshell::geometry::Converter::Converter(const std::string& geometry_library
mapping_ = impl::mapping_implementations().construct(file, settings_);
}
ifcopenshell::geometry::NativeElement* ifcopenshell::geometry::Converter::create_brep_for_representation_and_product(
IfcUtil::IfcBaseEntity* representation, IfcUtil::IfcBaseEntity* product) {
std::stringstream representation_id_builder;
ifcopenshell::geometry::NativeElement* ifcopenshell::geometry::Converter::create_brep_for_representation_and_product(taxonomy::item* product_node, const taxonomy::matrix4& place) {
auto product = (IfcUtil::IfcBaseEntity*) product_node->instance;
const std::string product_type = product->declaration().name();
// @todo
element_settings s(settings_, 1.0 /*getValue(GV_LENGTH_UNIT) */, product_type);
std::stringstream representation_id_builder;
int parent_id = -1;
try {
IfcUtil::IfcBaseEntity* parent_object = mapping_->get_decomposing_entity(product);
@@ -30,62 +29,34 @@ ifcopenshell::geometry::NativeElement* ifcopenshell::geometry::Converter::create
const std::string guid = product->get_value<std::string>("GlobalId");
const std::string name = product->get_value_or<std::string>("Name", "");
representation_id_builder << representation->data().id();
ifcopenshell::geometry::Representation::BRep* shape;
ifcopenshell::geometry::ConversionResults shapes;
// @todo should be rep id.
representation_id_builder << product->data().id();
/*
auto rep_item = mapping_->map(representation);
// @todo should map() throw an exception instead?
if (rep_item == nullptr) {
return nullptr;
}
*/
brep_ptr shape;
std::clock_t map_start = std::clock();
// @todo how to combine product_node and rep_item?
auto product_node = (taxonomy::geom_item*) mapping_->map(product);
if (product_node == nullptr) {
return nullptr;
}
std::clock_t geom_start = std::clock();
if (false) {
std::ostringstream oss;
product_node->print(oss);
std::string s = oss.str();
std::wcout << s.c_str() << std::endl;
}
auto place = taxonomy::matrix4();
std::swap(place, product_node->matrix);
auto it = cache_.find(product_node);
auto it = cache_.end(); // cache_.find(product_node);
if (it == cache_.end()) {
try {
ifcopenshell::geometry::ConversionResults shapes;
std::clock_t geom_start = std::clock();
kernel_->convert(product_node, shapes);
std::clock_t geom_end = std::clock();
total_geom_time += (geom_end - geom_start) / (double)CLOCKS_PER_SEC;
shape = brep_ptr(new ifcopenshell::geometry::Representation::BRep(s, representation_id_builder.str(), shapes));
} catch (...) {
return nullptr;
}
cache_.insert(it, { product_node, shapes });
cache_.insert(it, { product_node, shape });
} else {
Logger::Notice("Reusing geometry for", product);
Logger::Notice("Found", it->first->instance);
shapes = it->second;
shape = it->second;
}
shape = new ifcopenshell::geometry::Representation::BRep(s, representation_id_builder.str(), shapes);
std::clock_t geom_end = std::clock();
total_map_time += (geom_start - map_start) / (double) CLOCKS_PER_SEC;
total_geom_time += (geom_end - geom_start) / (double) CLOCKS_PER_SEC;
return new NativeElement(
product->data().id(),
parent_id,
@@ -96,9 +67,32 @@ ifcopenshell::geometry::NativeElement* ifcopenshell::geometry::Converter::create
"",
place,
// product_node->matrix,
boost::shared_ptr<ifcopenshell::geometry::Representation::BRep>(shape),
shape,
product
);
}
ifcopenshell::geometry::NativeElement* ifcopenshell::geometry::Converter::create_brep_for_representation_and_product(
// @todo representation is not used yet.
IfcUtil::IfcBaseEntity*, IfcUtil::IfcBaseEntity* product) {
std::clock_t map_start = std::clock();
// @todo how to combine product_node and rep_item?
auto product_node = (taxonomy::geom_item*) mapping_->map(product);
if (product_node == nullptr) {
return nullptr;
}
std::clock_t map_end = std::clock();
auto place = taxonomy::matrix4();
std::swap(place, product_node->matrix);
total_map_time += (map_end - map_start) / (double)CLOCKS_PER_SEC;
return create_brep_for_representation_and_product(product_node, place);
/*
std::stringstream representation_id_builder;
@@ -240,6 +234,47 @@ ifcopenshell::geometry::NativeElement* ifcopenshell::geometry::Converter::create
*/
}
ifcopenshell::geometry::NativeElement* ifcopenshell::geometry::Converter::create_brep_for_processed_representation(
IfcUtil::IfcBaseEntity* product, const taxonomy::matrix4& place, ifcopenshell::geometry::NativeElement* brep) {
int parent_id = -1;
try {
IfcUtil::IfcBaseEntity* parent_object = mapping_->get_decomposing_entity(product);
if (parent_object) {
parent_id = parent_object->data().id();
}
} catch (const std::exception& e) {
Logger::Error(e);
}
const std::string guid = product->get_value<std::string>("GlobalId");
const std::string name = product->get_value_or<std::string>("Name", "");
/*
std::string context_string = "";
if (representation->hasRepresentationIdentifier()) {
context_string = representation->RepresentationIdentifier();
} else if (representation->ContextOfItems()->hasContextType()) {
context_string = representation->ContextOfItems()->ContextType();
}
*/
const std::string product_type = product->declaration().name();
return new NativeElement(
product->data().id(),
parent_id,
name,
product_type,
guid,
// @todo
"",
place,
brep->geometry_pointer(),
product
);
}
ifcopenshell::geometry::NativeElement* ifcopenshell::geometry::Converter::create_brep_for_processed_representation(
IfcUtil::IfcBaseEntity* /* representation */, IfcUtil::IfcBaseEntity* product,
ifcopenshell::geometry::NativeElement* brep)
+6 -1
View File
@@ -14,11 +14,13 @@ namespace ifcopenshell { namespace geometry {
class NativeElement;
class Converter {
public:
typedef boost::shared_ptr<ifcopenshell::geometry::Representation::BRep> brep_ptr;
private:
abstract_mapping* mapping_;
kernels::AbstractKernel* kernel_;
ifcopenshell::geometry::settings settings_;
std::map<ifcopenshell::geometry::taxonomy::item*, ifcopenshell::geometry::ConversionResults, ifcopenshell::geometry::taxonomy::less_functor> cache_;
std::map<ifcopenshell::geometry::taxonomy::item*, brep_ptr, ifcopenshell::geometry::taxonomy::less_functor> cache_;
public:
kernels::AbstractKernel* kernel() { return kernel_; }
@@ -96,6 +98,9 @@ namespace ifcopenshell { namespace geometry {
ifcopenshell::geometry::NativeElement* create_brep_for_representation_and_product(IfcUtil::IfcBaseEntity* representation, IfcUtil::IfcBaseEntity* product);
ifcopenshell::geometry::NativeElement* create_brep_for_processed_representation(IfcUtil::IfcBaseEntity* representation, IfcUtil::IfcBaseEntity* product, ifcopenshell::geometry::NativeElement* brep);
ifcopenshell::geometry::NativeElement* create_brep_for_representation_and_product(taxonomy::item*, const taxonomy::matrix4&);
ifcopenshell::geometry::NativeElement* create_brep_for_processed_representation(IfcUtil::IfcBaseEntity*, const taxonomy::matrix4&, ifcopenshell::geometry::NativeElement*);
/*
static int count(const ifcopenshell::geometry::ConversionResultShape*, int, bool unique=false);
static int surface_genus(const ifcopenshell::geometry::ConversionResultShape*);
+56 -16
View File
@@ -105,6 +105,17 @@
#undef max
#endif
namespace ifcopenshell { namespace geometry {
struct geometry_conversion_result {
taxonomy::item* item;
std::vector<std::pair<IfcUtil::IfcBaseEntity*, taxonomy::matrix4>> products;
std::vector<ifcopenshell::geometry::NativeElement*> breps;
std::vector<ifcopenshell::geometry::Element*> elements;
};
} }
namespace {
ifcopenshell::geometry::Element* process_based_on_settings(
const ifcopenshell::geometry::settings& settings,
@@ -137,11 +148,12 @@ namespace {
void create_element(
ifcopenshell::geometry::Converter* converter,
const ifcopenshell::geometry::settings& settings,
ifcopenshell::geometry::geometry_conversion_task* rep)
ifcopenshell::geometry::geometry_conversion_result* rep)
{
IfcUtil::IfcBaseEntity* representation = rep->representation;
IfcUtil::IfcBaseEntity* product = (IfcUtil::IfcBaseEntity*) *rep->products->begin();
auto brep = converter->create_brep_for_representation_and_product(representation, product);
ifcopenshell::geometry::taxonomy::item* representation = rep->item;
auto place = rep->products.front().second;
auto brep = converter->create_brep_for_representation_and_product(representation, place);
if (!brep) {
return;
}
@@ -154,10 +166,11 @@ namespace {
rep->breps = { brep };
rep->elements = { elem };
for (auto it = rep->products->begin() + 1; it != rep->products->end(); ++it) {
auto brep2 = converter->create_brep_for_processed_representation(representation, (IfcUtil::IfcBaseEntity*) *it, brep);
for (auto it = rep->products.begin() + 1; it != rep->products.end(); ++it) {
const auto& p = *it;
auto brep2 = converter->create_brep_for_processed_representation(p.first, p.second, brep);
if (brep2) {
auto elem2 = process_based_on_settings(settings, brep, dynamic_cast<ifcopenshell::geometry::TriangulationElement*>(elem));
auto elem2 = process_based_on_settings(settings, brep2, dynamic_cast<ifcopenshell::geometry::TriangulationElement*>(elem));
if (elem2) {
rep->breps.push_back(brep2);
rep->elements.push_back(elem2);
@@ -174,8 +187,8 @@ namespace ifcopenshell { namespace geometry {
int num_threads_;
std::atomic<int> progress_;
std::vector<geometry_conversion_task> tasks_;
std::vector<geometry_conversion_task>::iterator task_iterator_;
std::vector<geometry_conversion_result> tasks_;
std::vector<geometry_conversion_result>::iterator task_iterator_;
std::vector<ifcopenshell::geometry::Element*> all_processed_elements_;
std::vector<ifcopenshell::geometry::NativeElement*> all_processed_native_elements_;
@@ -210,7 +223,34 @@ namespace ifcopenshell { namespace geometry {
bool initialize() {
converter_ = new Converter(geometry_library_, ifc_file, settings_);
converter_->mapping()->get_representations(tasks_, filters_, settings_);
std::vector<geometry_conversion_task> reps;
converter_->mapping()->get_representations(reps, filters_, settings_);
std::vector<IfcUtil::IfcBaseClass*> products;
for (auto& r : reps) {
std::copy(r.products->begin(), r.products->end(), std::back_inserter(products));
}
std::vector<taxonomy::item*> items;
std::map<taxonomy::item*, taxonomy::matrix4> placements;
std::transform(products.begin(), products.end(), std::back_inserter(items), [this, &placements](IfcUtil::IfcBaseClass* p) {
auto item = converter_->mapping()->map(p);
// Product placements do not affect item reuse and should temporarily be swapped to identity
std::swap(placements[item], ((taxonomy::geom_item*)item)->matrix);
return item;
});
std::sort(items.begin(), items.end(), taxonomy::less);
auto it = items.begin();
while (it < items.end()) {
auto jt = std::upper_bound(it, items.end(), *it, taxonomy::less);
geometry_conversion_result r;
r.item = *it;
std::transform(it, jt, std::back_inserter(r.products), [&r, &placements](taxonomy::item* product_node) {
return std::make_pair((IfcUtil::IfcBaseEntity*) product_node->instance, placements[product_node]);
});
tasks_.push_back(r);
it = jt;
}
Logger::Notice("Created " + boost::lexical_cast<std::string>(tasks_.size()) + " tasks for " + boost::lexical_cast<std::string>(products.size()) + " products");
if (tasks_.size() == 0) {
Logger::Warning("No representations encountered, aborting");
@@ -386,8 +426,8 @@ namespace ifcopenshell { namespace geometry {
++done;
}
IfcUtil::IfcBaseClass* create_shape_model_for_next_entity() {
geometry_conversion_task* task = nullptr;
const IfcUtil::IfcBaseClass* create_shape_model_for_next_entity() {
geometry_conversion_result* task = nullptr;
while (task_iterator_ != tasks_.end()) {
task = &*task_iterator_++;
create_element(converter_, settings_, task);
@@ -400,7 +440,7 @@ namespace ifcopenshell { namespace geometry {
if (task) {
all_processed_elements_.insert(all_processed_elements_.end(), task->elements.begin(), task->elements.end());
all_processed_native_elements_.insert(all_processed_native_elements_.end(), task->breps.begin(), task->breps.end());
return (*task->products)[0];
return task->item->instance;
} else {
return nullptr;
}
@@ -410,7 +450,7 @@ namespace ifcopenshell { namespace geometry {
/// Moves to the next shape representation, create its geometry, and returns the associated product.
/// Use get() to retrieve the created geometry.
IfcUtil::IfcBaseClass* next() {
const IfcUtil::IfcBaseClass* next() {
if (num_threads_ != 1) {
task_result_index_++;
if (task_result_index_ == all_processed_elements_.size()) {
@@ -555,8 +595,8 @@ namespace ifcopenshell { namespace geometry {
*/
}
IfcUtil::IfcBaseClass* create() {
IfcUtil::IfcBaseClass* product = nullptr;
const IfcUtil::IfcBaseClass* create() {
const IfcUtil::IfcBaseClass* product = nullptr;
try {
product = create_shape_model_for_next_entity();
} catch (const std::exception& e) {
+4 -2
View File
@@ -89,6 +89,8 @@ namespace {
bool compare(const collection& a, const collection& b);
bool compare(const extrusion& a, const extrusion& b) {
// @todo extrusions can also have non-identity matrices right? perhaps it's time
// for a dedicated transform node and not on the abstract geom_item.
const int order[3] = {
less_to_order(a.basis, b.basis),
less_to_order(a.direction, b.direction),
@@ -211,8 +213,8 @@ namespace {
}
return a_lt_b;
}
// Vectors equal.
return false;
// Vectors equal, compare matrix (in case of mapped items).
return compare(a.matrix, b.matrix);
} else {
return a.children.size() < b.children.size();
}