From 6c4fee1028cc0160de5f39152646def5641a92b0 Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Fri, 6 Oct 2017 15:36:51 +0200 Subject: [PATCH] Color elements by material association. Reimplement reuse detection. Fix #265 --- src/ifcgeom/IfcGeom.h | 3 + src/ifcgeom/IfcGeomFunctions.cpp | 102 ++++++++++++++++++ src/ifcgeom/IfcGeomIterator.h | 171 +++++++++---------------------- 3 files changed, 152 insertions(+), 124 deletions(-) diff --git a/src/ifcgeom/IfcGeom.h b/src/ifcgeom/IfcGeom.h index dff6c93820..3ddad87902 100644 --- a/src/ifcgeom/IfcGeom.h +++ b/src/ifcgeom/IfcGeom.h @@ -257,6 +257,9 @@ public: IfcGeom::BRepElement

* create_brep_for_processed_representation( const IteratorSettings&, IfcSchema::IfcRepresentation*, IfcSchema::IfcProduct*, IfcGeom::BRepElement

*); + const IfcSchema::IfcMaterial* get_single_material_association(const IfcSchema::IfcProduct*); + IfcSchema::IfcRepresentation* representation_mapped_to(const IfcSchema::IfcRepresentation* representation); + IfcSchema::IfcProduct::list::ptr products_represented_by(const IfcSchema::IfcRepresentation*); const SurfaceStyle* get_style(const IfcSchema::IfcRepresentationItem*); const SurfaceStyle* get_style(const IfcSchema::IfcMaterial*); diff --git a/src/ifcgeom/IfcGeomFunctions.cpp b/src/ifcgeom/IfcGeomFunctions.cpp index ccc7939c7e..2cb2ebadc0 100644 --- a/src/ifcgeom/IfcGeomFunctions.cpp +++ b/src/ifcgeom/IfcGeomFunctions.cpp @@ -1134,6 +1134,26 @@ IfcSchema::IfcRelVoidsElement::list::ptr IfcGeom::Kernel::find_openings(IfcSchem return openings; } +const IfcSchema::IfcMaterial* IfcGeom::Kernel::get_single_material_association(const IfcSchema::IfcProduct* product) { + IfcSchema::IfcMaterial* single_material = 0; + IfcSchema::IfcRelAssociatesMaterial::list::ptr associated_materials = product->HasAssociations()->as(); + if (associated_materials->size() == 1) { + IfcSchema::IfcMaterialSelect* associated_material = (*associated_materials->begin())->RelatingMaterial(); + single_material = associated_material->as(); + // TODO: Should this check for APPLY_LAYERSETS setting? + if (!single_material && associated_material->as()) { + IfcSchema::IfcMaterialLayerSet* layerset = associated_material->as()->ForLayerSet(); + if (layerset->MaterialLayers()->size() == 1) { + IfcSchema::IfcMaterialLayer* layer = (*layerset->MaterialLayers()->begin()); + if (layer->hasMaterial()) { + single_material = layer->Material(); + } + } + } + } + return single_material; +} + template IfcGeom::BRepElement

* IfcGeom::Kernel::create_brep_for_representation_and_product( const IteratorSettings& settings, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product) @@ -1183,6 +1203,23 @@ IfcGeom::BRepElement

* IfcGeom::Kernel::create_brep_for_representation_and_pro } } + bool material_style_applied = false; + + const IfcSchema::IfcMaterial* single_material = get_single_material_association(product); + if (single_material) { + const IfcGeom::SurfaceStyle* s = get_style(single_material); + for (auto it = shapes.begin(); it != shapes.end(); ++it) { + if (!it->hasStyle() && s) { + it->setStyle(s); + material_style_applied = true; + } + } + } + + if (material_style_applied) { + representation_id_builder << "-material-" << single_material->entity->id(); + } + int parent_id = -1; try { IfcSchema::IfcObjectDefinition* parent_object = get_decomposing_entity(product); @@ -1276,6 +1313,71 @@ IfcGeom::BRepElement

* IfcGeom::Kernel::create_brep_for_representation_and_pro ); } +IfcSchema::IfcRepresentation* IfcGeom::Kernel::representation_mapped_to(const IfcSchema::IfcRepresentation* representation) { + IfcSchema::IfcRepresentation* representation_mapped_to = 0; + IfcSchema::IfcRepresentationItem::list::ptr items = representation->Items(); + if (items->size() == 1) { + IfcSchema::IfcRepresentationItem* item = *items->begin(); + if (item->is(IfcSchema::Type::IfcMappedItem)) { + if (item->StyledByItem()->size() == 0) { + IfcSchema::IfcMappedItem* mapped_item = item->as(); + if (is_identity_transform(mapped_item->MappingTarget())) { + IfcSchema::IfcRepresentationMap* map = mapped_item->MappingSource(); + if (is_identity_transform(map->MappingOrigin())) { + representation_mapped_to = map->MappedRepresentation(); + } + } + } + } + } + return representation_mapped_to; +} + +IfcSchema::IfcProduct::list::ptr IfcGeom::Kernel::products_represented_by(const IfcSchema::IfcRepresentation* representation) { + IfcSchema::IfcProduct::list::ptr products(new IfcSchema::IfcProduct::list); + + IfcSchema::IfcProductRepresentation::list::ptr prodreps = representation->OfProductRepresentation(); + + for (IfcSchema::IfcProductRepresentation::list::it it = prodreps->begin(); it != prodreps->end(); ++it) { + // http://buildingsmart-tech.org/ifc/IFC2x3/TC1/html/ifcrepresentationresource/lexical/ifcproductrepresentation.htm + // IFC2x Edition 3 NOTE Users should not instantiate the entity IfcProductRepresentation from IFC2x Edition 3 onwards. + // It will be changed into an ABSTRACT supertype in future releases of IFC. + + // IfcProductRepresentation also lacks the INVERSE relation to IfcProduct + // Let's find the IfcProducts that reference the IfcProductRepresentation anyway + products->push((*it)->entity->getInverse(IfcSchema::Type::IfcProduct, -1)->as()); + } + + IfcSchema::IfcRepresentationMap::list::ptr maps = representation->RepresentationMap(); + if (maps->size() == 1) { + IfcSchema::IfcRepresentationMap* map = *maps->begin(); + if (is_identity_transform(map->MappingOrigin())) { + IfcSchema::IfcMappedItem::list::ptr items = map->MapUsage(); + for (IfcSchema::IfcMappedItem::list::it it = items->begin(); it != items->end(); ++it) { + IfcSchema::IfcMappedItem* item = *it; + if (item->StyledByItem()->size() != 0) continue; + + if (!is_identity_transform(item->MappingTarget())) { + continue; + } + + IfcSchema::IfcRepresentation::list::ptr reps = item->entity->getInverse(IfcSchema::Type::IfcRepresentation, -1)->as(); + for (IfcSchema::IfcRepresentation::list::it jt = reps->begin(); jt != reps->end(); ++jt) { + IfcSchema::IfcRepresentation* rep = *jt; + if (rep->Items()->size() != 1) continue; + IfcSchema::IfcProductRepresentation::list::ptr prodreps_mapped = rep->OfProductRepresentation(); + for (IfcSchema::IfcProductRepresentation::list::it kt = prodreps_mapped->begin(); kt != prodreps_mapped->end(); ++kt) { + IfcSchema::IfcProduct::list::ptr ps = (*kt)->entity->getInverse(IfcSchema::Type::IfcProduct, -1)->as(); + products->push(ps); + } + } + } + } + } + + return products; +} + template IfcGeom::BRepElement

* IfcGeom::Kernel::create_brep_for_processed_representation( const IteratorSettings& /*settings*/, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product, diff --git a/src/ifcgeom/IfcGeomIterator.h b/src/ifcgeom/IfcGeomIterator.h index 5cf90fb1cf..cabe628ad6 100644 --- a/src/ifcgeom/IfcGeomIterator.h +++ b/src/ifcgeom/IfcGeomIterator.h @@ -351,10 +351,44 @@ namespace IfcGeom { ++ done; } - std::set mapped_representations_processed; - bool geometry_reuse_ok_for_current_representation_; + bool reuse_ok_(const IfcSchema::IfcProduct::list::ptr& products) { + // 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(IteratorSettings::USE_WORLD_COORDS)) { + return false; + } + + std::set associated_single_materials; + + for (IfcSchema::IfcProduct::list::it it = products->begin(); it != products->end(); ++it) { + IfcSchema::IfcProduct* product = *it; + + if (!settings.get(IteratorSettings::DISABLE_OPENING_SUBTRACTIONS) && kernel.find_openings(product)->size()) { + return false; + } + + if (settings.get(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(); + 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)); + } + + return associated_single_materials.size() == 1; + } + BRepElement

* create_shape_model_for_next_entity() { for (;;) { IfcSchema::IfcRepresentation* representation; @@ -368,101 +402,25 @@ namespace IfcGeom { // Has the list of IfcProducts for this representation been initialized? if (!ifcproducts) { - ifcproducts = IfcSchema::IfcProduct::list::ptr(new IfcSchema::IfcProduct::list); - IfcSchema::IfcProduct::list::ptr unfiltered_products(new IfcSchema::IfcProduct::list); + IfcSchema::IfcProduct::list::ptr unfiltered_products = kernel.products_represented_by(representation); - { - IfcSchema::IfcProductRepresentation::list::ptr prodreps = representation->OfProductRepresentation(); + geometry_reuse_ok_for_current_representation_ = reuse_ok_(unfiltered_products); - for (IfcSchema::IfcProductRepresentation::list::it it = prodreps->begin(); it != prodreps->end(); ++it) { - if ((*it)->is(IfcSchema::Type::IfcProductDefinitionShape)) { - IfcSchema::IfcProductDefinitionShape* pds = (IfcSchema::IfcProductDefinitionShape*)*it; - unfiltered_products->push(pds->ShapeOfProduct()); - } - else { - // http://buildingsmart-tech.org/ifc/IFC2x3/TC1/html/ifcrepresentationresource/lexical/ifcproductrepresentation.htm - // IFC2x Edition 3 NOTE Users should not instantiate the entity IfcProductRepresentation from IFC2x Edition 3 onwards. - // It will be changed into an ABSTRACT supertype in future releases of IFC. - - // IfcProductRepresentation also lacks the INVERSE relation to IfcProduct - // Let's find the IfcProducts that reference the IfcProductRepresentation anyway - unfiltered_products->push((*it)->entity->getInverse(IfcSchema::Type::IfcProduct, -1)->as()); - } - } + if (!geometry_reuse_ok_for_current_representation_ && representation->RepresentationMap()->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. + _nextShape(); + continue; } - bool has_openings = false; - bool has_layers = false; - - for (IfcSchema::IfcProduct::list::it it = unfiltered_products->begin(); it != unfiltered_products->end(); ++it) { - if (kernel.find_openings(*it)->size()) { - has_openings = true; - } - IfcSchema::IfcRelAssociates::list::ptr associations = (*it)->HasAssociations(); - for (IfcSchema::IfcRelAssociates::list::it jt = associations->begin(); jt != associations->end(); ++jt) { - IfcSchema::IfcRelAssociatesMaterial* assoc = (*jt)->as(); - if (assoc) { - if (assoc->RelatingMaterial()->is(IfcSchema::Type::IfcMaterialLayerSetUsage)) { - has_layers = true; - } - } - } - } - - // With world coords enabled, object transformations are directly applied to - // the BRep. There is no way to re-use the geometry for multiple products. - geometry_reuse_ok_for_current_representation_ = !settings.get(IteratorSettings::USE_WORLD_COORDS) && - (!has_openings || settings.get(IteratorSettings::DISABLE_OPENING_SUBTRACTIONS)) && - (!has_layers || !settings.get(IteratorSettings::APPLY_LAYERSETS)); bool representation_processed_as_mapped_item = false; - IfcSchema::IfcRepresentation* representation_mapped_to = 0; - - if (geometry_reuse_ok_for_current_representation_) { - IfcSchema::IfcRepresentationItem::list::ptr items = representation->Items(); - if (items->size() == 1) { - IfcSchema::IfcRepresentationItem* item = *items->begin(); - if (item->is(IfcSchema::Type::IfcMappedItem)) { - if (item->StyledByItem()->size() == 0) { - IfcSchema::IfcMappedItem* mapped_item = item->as(); - if (kernel.is_identity_transform(mapped_item->MappingTarget())) { - IfcSchema::IfcRepresentationMap* map = mapped_item->MappingSource(); - if (kernel.is_identity_transform(map->MappingOrigin())) { - representation_mapped_to = map->MappedRepresentation(); - IfcSchema::IfcProductRepresentation::list::ptr prodreps = representation_mapped_to->OfProductRepresentation(); - - bool all_product_without_openings = true; - IfcSchema::IfcProduct::list::ptr products(new IfcSchema::IfcProduct::list); - - for (IfcSchema::IfcProductRepresentation::list::it it = prodreps->begin(); it != prodreps->end(); ++it) { - IfcSchema::IfcProduct::list::ptr products_of_prodrep = (*it)->entity->getInverse(IfcSchema::Type::IfcProduct, -1)->as(); - products->push(products_of_prodrep); - for (IfcSchema::IfcProduct::list::it jt = products_of_prodrep->begin(); jt != products_of_prodrep->end(); ++jt) { - if (kernel.find_openings(*jt)->size() > 0 && !settings.get(IteratorSettings::DISABLE_OPENING_SUBTRACTIONS)) { - all_product_without_openings = false; - break; - } - } - } - - if (all_product_without_openings) { - representation_processed_as_mapped_item = true; - } - } - } - } - } - } - } - + IfcSchema::IfcRepresentation* representation_mapped_to = kernel.representation_mapped_to(representation); if (representation_mapped_to) { - if (mapped_representations_processed.find(representation_mapped_to) != mapped_representations_processed.end()) { - _nextShape(); - continue; - } - - mapped_representations_processed.insert(representation_mapped_to); + // Check if this represenation has (or will be) processed as part its mapped representation + representation_processed_as_mapped_item = reuse_ok_(kernel.products_represented_by(representation_mapped_to)); } if (representation_processed_as_mapped_item) { @@ -470,40 +428,6 @@ namespace IfcGeom { continue; } - IfcSchema::IfcRepresentationMap::list::ptr maps = representation->RepresentationMap(); - - if (geometry_reuse_ok_for_current_representation_ && maps->size() == 1) { - IfcSchema::IfcRepresentationMap* map = *maps->begin(); - if (kernel.is_identity_transform(map->MappingOrigin())) { - IfcSchema::IfcMappedItem::list::ptr items = map->MapUsage(); - for (IfcSchema::IfcMappedItem::list::it it = items->begin(); it != items->end(); ++it) { - IfcSchema::IfcMappedItem* item = *it; - if (item->StyledByItem()->size() != 0) continue; - - if (!kernel.is_identity_transform(item->MappingTarget())) { - continue; - } - - IfcSchema::IfcRepresentation::list::ptr reps = item->entity->getInverse(IfcSchema::Type::IfcRepresentation, -1)->as(); - for (IfcSchema::IfcRepresentation::list::it jt = reps->begin(); jt != reps->end(); ++jt) { - IfcSchema::IfcRepresentation* rep = *jt; - if (rep->Items()->size() != 1) continue; - IfcSchema::IfcProductRepresentation::list::ptr prodreps = rep->OfProductRepresentation(); - for (IfcSchema::IfcProductRepresentation::list::it kt = prodreps->begin(); kt != prodreps->end(); ++kt) { - IfcSchema::IfcProduct::list::ptr prods = (*kt)->entity->getInverse(IfcSchema::Type::IfcProduct, -1)->as(); - for (IfcSchema::IfcProduct::list::it lt = prods->begin(); lt != prods->end(); ++lt) { - if (kernel.find_openings(*lt)->size() == 0 || settings.get(IteratorSettings::DISABLE_OPENING_SUBTRACTIONS)) { - if (!unfiltered_products->contains(*lt)) { - unfiltered_products->push(*lt); - } - } - } - } - } - } - } - } - // 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; @@ -522,7 +446,6 @@ namespace IfcGeom { } IfcSchema::IfcProduct* product = *ifcproduct_iterator; - Logger::SetProduct(product); BRepElement

* element;