diff --git a/src/ifcgeom/IfcGeomFunctions.cpp b/src/ifcgeom/IfcGeomFunctions.cpp index 5b36683ce4..7ae87d9954 100644 --- a/src/ifcgeom/IfcGeomFunctions.cpp +++ b/src/ifcgeom/IfcGeomFunctions.cpp @@ -706,22 +706,31 @@ bool IfcGeom::Kernel::convert_openings_fast(const IfcSchema::IfcProduct* entity, return true; } #else -bool IfcGeom::Kernel::convert_openings_fast(const IfcSchema::IfcProduct* entity, const IfcSchema::IfcRelVoidsElement::list::ptr& openings, - const IfcGeom::IfcRepresentationShapeItems& entity_shapes, const gp_Trsf& entity_trsf, IfcGeom::IfcRepresentationShapeItems& cut_shapes) { - - TopTools_ListOfShape opening_shapelist; - - for ( IfcSchema::IfcRelVoidsElement::list::it it = openings->begin(); it != openings->end(); ++ it ) { + +namespace { + struct opening_sorter { + bool operator()(const std::pair& a, const std::pair& b) const { + return a.first > b.first; + } + }; +} + +bool IfcGeom::Kernel::convert_openings_fast(const IfcSchema::IfcProduct* entity, const IfcSchema::IfcRelVoidsElement::list::ptr& openings, + const IfcGeom::IfcRepresentationShapeItems& entity_shapes, const gp_Trsf& entity_trsf, IfcGeom::IfcRepresentationShapeItems& cut_shapes) { + + std::vector< std::pair > opening_vector; + + for (IfcSchema::IfcRelVoidsElement::list::it it = openings->begin(); it != openings->end(); ++it) { IfcSchema::IfcRelVoidsElement* v = *it; IfcSchema::IfcFeatureElementSubtraction* fes = v->RelatedOpeningElement(); - if ( fes->is(IfcSchema::Type::IfcOpeningElement) ) { + if (fes->is(IfcSchema::Type::IfcOpeningElement)) { if (!fes->hasRepresentation()) continue; // Convert the IfcRepresentation of the IfcOpeningElement gp_Trsf opening_trsf; if (fes->hasObjectPlacement()) { try { - convert(fes->ObjectPlacement(),opening_trsf); + convert(fes->ObjectPlacement(), opening_trsf); } catch (const std::exception& e) { Logger::Error(e); } catch (...) { @@ -736,24 +745,26 @@ bool IfcGeom::Kernel::convert_openings_fast(const IfcSchema::IfcProduct* entity, IfcSchema::IfcRepresentation::list::ptr reps = prodrep->Representations(); IfcGeom::IfcRepresentationShapeItems opening_shapes; - - for ( IfcSchema::IfcRepresentation::list::it it2 = reps->begin(); it2 != reps->end(); ++ it2 ) { - convert_shapes(*it2,opening_shapes); + + for (IfcSchema::IfcRepresentation::list::it it2 = reps->begin(); it2 != reps->end(); ++it2) { + convert_shapes(*it2, opening_shapes); } - for ( unsigned int i = 0; i < opening_shapes.size(); ++ i ) { + for (unsigned int i = 0; i < opening_shapes.size(); ++i) { TopoDS_Shape opening_shape_solid; const TopoDS_Shape& opening_shape_unlocated = ensure_fit_for_subtraction(opening_shapes[i].Shape(), opening_shape_solid); gp_GTrsf gtrsf = opening_shapes[i].Placement(); gtrsf.PreMultiply(opening_trsf); TopoDS_Shape opening_shape = apply_transformation(opening_shape_unlocated, gtrsf); - opening_shapelist.Append(opening_shape); + opening_vector.push_back(std::make_pair(min_edge_length(opening_shape), opening_shape)); } } } + std::sort(opening_vector.begin(), opening_vector.end(), opening_sorter()); + // Iterate over the shapes of the IfcProduct for ( IfcGeom::IfcRepresentationShapeItems::const_iterator it3 = entity_shapes.begin(); it3 != entity_shapes.end(); ++ it3 ) { TopoDS_Shape entity_shape_solid; @@ -764,13 +775,35 @@ bool IfcGeom::Kernel::convert_openings_fast(const IfcSchema::IfcProduct* entity, } TopoDS_Shape entity_shape = apply_transformation(entity_shape_unlocated, entity_shape_gtrsf); - TopoDS_Shape result; - if (boolean_operation(entity_shape, opening_shapelist, BOPAlgo_CUT, result)) { - cut_shapes.push_back(IfcGeom::IfcRepresentationShapeItem(result, &it3->Style())); - } else { - Logger::Message(Logger::LOG_ERROR, "Opening subtraction failed:", entity->entity); - cut_shapes.push_back(IfcGeom::IfcRepresentationShapeItem(entity_shape, &it3->Style())); + TopoDS_Shape result = entity_shape; + + auto it = opening_vector.begin(); + auto jt = it; + + for (;; ++it) { + if (it == opening_vector.end() || jt->first / it->first > 10.) { + + TopTools_ListOfShape opening_list; + for (auto kt = jt; kt < it; ++kt) { + opening_list.Append(kt->second); + } + + TopoDS_Shape intermediate_result; + if (boolean_operation(result, opening_list, BOPAlgo_CUT, intermediate_result)) { + result = intermediate_result; + } else { + Logger::Message(Logger::LOG_ERROR, "Opening subtraction failed for " + boost::lexical_cast(std::distance(jt, it)) + " openings", entity->entity); + } + + jt = it; + } + + if (it == opening_vector.end()) { + break; + } } + + cut_shapes.push_back(IfcGeom::IfcRepresentationShapeItem(result, &it3->Style())); } return true; }