From 700cc772fb8a3876460438170c3976dba8d5bc86 Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Thu, 7 Jun 2012 14:38:21 +0000 Subject: [PATCH] - Add an alternative method to process openings that is potentially faster. Use IfcGeomObjects::FASTER_BOOLEANS to enable. - Begin working on verbosity levels --- src/ifcgeom/IfcGeom.h | 1 + src/ifcgeom/IfcGeomFunctions.cpp | 104 ++++++++++++++++++++++++++++--- src/ifcgeom/IfcGeomObjects.cpp | 18 +++++- src/ifcgeom/IfcGeomObjects.h | 3 + src/ifcparse/IfcParse.cpp | 1 + src/ifcparse/IfcParse.h | 1 + 6 files changed, 117 insertions(+), 11 deletions(-) diff --git a/src/ifcgeom/IfcGeom.h b/src/ifcgeom/IfcGeom.h index 60d432dadc..d5d43a7975 100644 --- a/src/ifcgeom/IfcGeom.h +++ b/src/ifcgeom/IfcGeom.h @@ -65,6 +65,7 @@ namespace IfcGeom { bool convert_curve(const IfcUtil::IfcBaseClass* L, Handle(Geom_Curve)& result); bool convert_face(const IfcUtil::IfcBaseClass* L, TopoDS_Face& result); bool convert_openings(const Ifc2x3::IfcProduct::ptr entity, const Ifc2x3::IfcRelVoidsElement::list& openings, const ShapeList& entity_shapes, const gp_Trsf& entity_trsf, ShapeList& cut_shapes); + bool convert_openings_fast(const Ifc2x3::IfcProduct::ptr entity, const Ifc2x3::IfcRelVoidsElement::list& openings, const ShapeList& entity_shapes, const gp_Trsf& entity_trsf, ShapeList& cut_shapes); bool create_solid_from_compound(const TopoDS_Shape& compound, TopoDS_Shape& solid); bool is_compound(const TopoDS_Shape& shape); bool is_convex(const TopoDS_Wire& wire); diff --git a/src/ifcgeom/IfcGeomFunctions.cpp b/src/ifcgeom/IfcGeomFunctions.cpp index 660c492bfc..c750f42db8 100644 --- a/src/ifcgeom/IfcGeomFunctions.cpp +++ b/src/ifcgeom/IfcGeomFunctions.cpp @@ -179,12 +179,14 @@ bool IfcGeom::convert_openings(const Ifc2x3::IfcProduct::ptr entity, const Ifc2x ? BRepBuilderAPI_GTransform(opening_shape_unlocated,opening_shape_gtrsf,true).Shape() : opening_shape_unlocated.Moved(opening_shape_gtrsf.Trsf()); - const double opening_volume = shape_volume(opening_shape); - if ( opening_volume <= ALMOST_ZERO ) - Ifc::LogMessage("Warning","Empty opening for:",entity->entity); - - const double original_shape_volume = shape_volume(entity_shape); - + double opening_volume, original_shape_volume; + if ( Ifc::Verbosity > 1 ) { + opening_volume = shape_volume(opening_shape); + if ( opening_volume <= ALMOST_ZERO ) + Ifc::LogMessage("Warning","Empty opening for:",entity->entity); + original_shape_volume = shape_volume(entity_shape); + } + BRepAlgoAPI_Cut brep_cut(entity_shape,opening_shape); if ( brep_cut.IsDone() ) { @@ -194,11 +196,12 @@ bool IfcGeom::convert_openings(const Ifc2x3::IfcProduct::ptr entity, const Ifc2x bool is_valid = analyser.IsValid() != 0; if ( is_valid ) { entity_shape = brep_cut; - const double volume_after_subtraction = shape_volume(entity_shape); + if ( Ifc::Verbosity > 1 ) { + const double volume_after_subtraction = shape_volume(entity_shape); - if ( ALMOST_THE_SAME(original_shape_volume,volume_after_subtraction) ) - Ifc::LogMessage("Warning","Subtraction yields unchanged volume:",entity->entity); - + if ( ALMOST_THE_SAME(original_shape_volume,volume_after_subtraction) ) + Ifc::LogMessage("Warning","Subtraction yields unchanged volume:",entity->entity); + } } else { Ifc::LogMessage("Error","Invalid result from subtraction:",entity->entity); } @@ -217,6 +220,87 @@ bool IfcGeom::convert_openings(const Ifc2x3::IfcProduct::ptr entity, const Ifc2x return true; } + +bool IfcGeom::convert_openings_fast(const Ifc2x3::IfcProduct::ptr entity, const Ifc2x3::IfcRelVoidsElement::list& openings, + const ShapeList& entity_shapes, const gp_Trsf& entity_trsf, ShapeList& cut_shapes) { + + // Create a compound of all opening shapes in order to speed up the boolean operations + TopoDS_Compound opening_compound; + BRep_Builder builder; + builder.MakeCompound(opening_compound); + + for ( Ifc2x3::IfcRelVoidsElement::it it = openings->begin(); it != openings->end(); ++ it ) { + Ifc2x3::IfcRelVoidsElement::ptr v = *it; + Ifc2x3::IfcFeatureElementSubtraction::ptr fes = v->RelatedOpeningElement(); + if ( fes->is(Ifc2x3::Type::IfcOpeningElement) ) { + + // Convert the IfcRepresentation of the IfcOpeningElement + gp_Trsf opening_trsf; + IfcGeom::convert(fes->ObjectPlacement(),opening_trsf); + + // Move the opening into the coordinate system of the IfcProduct + opening_trsf.PreMultiply(entity_trsf.Inverted()); + + Ifc2x3::IfcProductRepresentation::ptr prodrep = fes->Representation(); + Ifc2x3::IfcRepresentation::list reps = prodrep->Representations(); + + IfcGeom::ShapeList opening_shapes; + + for ( Ifc2x3::IfcRepresentation::it it2 = reps->begin(); it2 != reps->end(); ++ it2 ) { + IfcGeom::convert_shapes(*it2,opening_shapes); + } + + for ( unsigned int i = 0; i < opening_shapes.size(); ++ i ) { + gp_GTrsf& gtrsf = *opening_shapes[i].first; + gtrsf.PreMultiply(opening_trsf); + const TopoDS_Shape& opening_shape = gtrsf.Form() == gp_Other + ? BRepBuilderAPI_GTransform(*opening_shapes[i].second,gtrsf,true).Shape() + : (*opening_shapes[i].second).Moved(gtrsf.Trsf()); + builder.Add(opening_compound,opening_shape); + } + + for ( IfcGeom::ShapeList::const_iterator it5 = opening_shapes.begin(); it5 != opening_shapes.end(); ++ it5 ) { + delete it5->first; + } + } + } + + // Iterate over the shapes of the IfcProduct + for ( IfcGeom::ShapeList::const_iterator it3 = entity_shapes.begin(); it3 != entity_shapes.end(); ++ it3 ) { + TopoDS_Shape entity_shape_solid; + const TopoDS_Shape& entity_shape_unlocated = IfcGeom::ensure_fit_for_subtraction(*(it3->second),entity_shape_solid); + const gp_GTrsf& entity_shape_gtrsf = *(it3->first); + TopoDS_Shape entity_shape; + if ( entity_shape_gtrsf.Form() == gp_Other ) { + Ifc::LogMessage("Warning","Applying non uniform transformation to:",entity->entity); + entity_shape = BRepBuilderAPI_GTransform(entity_shape_unlocated,entity_shape_gtrsf,true).Shape(); + } else { + entity_shape = entity_shape_unlocated.Moved(entity_shape_gtrsf.Trsf()); + } + + BRepAlgoAPI_Cut brep_cut(entity_shape,opening_compound); + bool is_valid = false; + if ( brep_cut.IsDone() ) { + TopoDS_Shape brep_cut_result = brep_cut; + + BRepCheck_Analyzer analyser(brep_cut_result); + is_valid = analyser.IsValid() != 0; + if ( is_valid ) { + cut_shapes.push_back(IfcGeom::LocationShape(new gp_GTrsf(),new TopoDS_Shape(brep_cut_result))); + } + } + if ( !is_valid ) { + // Apparently processing the boolean operation failed or resulted in an invalid result + // in which case the original shape without the subtractions is returned instead + // we try convert the openings in the original way, one by one. + Ifc::LogMessage("Warning","Subtracting combined openings compound failed:",entity->entity); + return false; + } + + } + return true; +} + bool IfcGeom::convert_wire_to_face(const TopoDS_Wire& wire, TopoDS_Face& face) { BRepBuilderAPI_MakeFace mf(wire, false); BRepBuilderAPI_FaceError er = mf.Error(); diff --git a/src/ifcgeom/IfcGeomObjects.cpp b/src/ifcgeom/IfcGeomObjects.cpp index bce59d1796..4867e97b20 100644 --- a/src/ifcgeom/IfcGeomObjects.cpp +++ b/src/ifcgeom/IfcGeomObjects.cpp @@ -48,6 +48,7 @@ // Welds vertices that belong to different faces bool weld_vertices = true; bool convert_back_units = false; +bool use_faster_booleans = false; int IfcGeomObjects::IfcMesh::addvert(const gp_XYZ& p) { const float X = convert_back_units ? (float) (p.X() / Ifc::LengthUnit) : (float)p.X(); @@ -386,7 +387,19 @@ IfcGeomObjects::IfcGeomObject* _get() { if ( openings && openings->Size() ) { IfcGeom::ShapeList opened_shapes; try { - IfcGeom::convert_openings(ifc_product,openings,shapes,trsf,opened_shapes); + if ( use_faster_booleans ) { + bool succes = IfcGeom::convert_openings_fast(ifc_product,openings,shapes,trsf,opened_shapes); + if ( ! succes ) { + for ( IfcGeom::ShapeList::const_iterator it = opened_shapes.begin(); it != opened_shapes.end(); ++ it ) { + delete it->first; + delete it->second; + } + opened_shapes.clear(); + IfcGeom::convert_openings(ifc_product,openings,shapes,trsf,opened_shapes); + } + } else { + IfcGeom::convert_openings(ifc_product,openings,shapes,trsf,opened_shapes); + } } catch(...) { Ifc::LogMessage("Error","Error processing openings for:",ifc_product->entity); } @@ -521,6 +534,9 @@ void IfcGeomObjects::Settings(int setting, bool value) { case USE_BREP_DATA: use_brep_data = value; break; + case FASTER_BOOLEANS: + use_faster_booleans = value; + break; case SEW_SHELLS: Ifc::SewShells = value; break; diff --git a/src/ifcgeom/IfcGeomObjects.h b/src/ifcgeom/IfcGeomObjects.h index eff49be793..20cb6dd7b2 100644 --- a/src/ifcgeom/IfcGeomObjects.h +++ b/src/ifcgeom/IfcGeomObjects.h @@ -91,6 +91,9 @@ namespace IfcGeomObjects { // Specifies whether to sew IfcConnectedFaceSets (open and closed shells) to // TopoDS_Shells or whether to keep them as a loose collection of faces. const int SEW_SHELLS = 5; + // Specifies whether to compose IfcOpeningElements into a single compound + // in order to speed up the processing of opening subtractions. + const int FASTER_BOOLEANS = 6; // End of settings enumeration. diff --git a/src/ifcparse/IfcParse.cpp b/src/ifcparse/IfcParse.cpp index 74c5b8a5ff..1a6987cf94 100644 --- a/src/ifcparse/IfcParse.cpp +++ b/src/ifcparse/IfcParse.cpp @@ -868,3 +868,4 @@ MapEntityByGuid Ifc::byguid; MapEntitiesByRef Ifc::byref; MapOffsetById Ifc::offsets; std::stringstream Ifc::log_stream; +int Ifc::Verbosity = 2; diff --git a/src/ifcparse/IfcParse.h b/src/ifcparse/IfcParse.h index 9e785cf15f..3214cad18a 100644 --- a/src/ifcparse/IfcParse.h +++ b/src/ifcparse/IfcParse.h @@ -272,6 +272,7 @@ public: static double LengthUnit; static double PlaneAngleUnit; static int CircleSegments; + static int Verbosity; }; double UnitPrefixToValue( Ifc2x3::IfcSIPrefix::IfcSIPrefix v );