diff --git a/src/ifcgeom/IfcGeomFunctions.cpp b/src/ifcgeom/IfcGeomFunctions.cpp index 8c3f0a3eb9..d0aba46590 100644 --- a/src/ifcgeom/IfcGeomFunctions.cpp +++ b/src/ifcgeom/IfcGeomFunctions.cpp @@ -208,27 +208,65 @@ bool IfcGeom::convert_openings(const IfcSchema::IfcProduct* entity, const IfcSch Logger::Message(Logger::LOG_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() ) { - TopoDS_Shape brep_cut_result = brep_cut; + if (entity_shape.ShapeType() == TopAbs_COMPSOLID) { + + // For compound solids process the subtraction for the constituent + // solids individually and write the result back as a compound solid. + + TopoDS_CompSolid compound; + BRep_Builder builder; + builder.MakeCompSolid(compound); + + TopExp_Explorer exp(entity_shape, TopAbs_SOLID); + + for (; exp.More(); exp.Next()) { + BRepAlgoAPI_Cut brep_cut(exp.Current(), opening_shape); + bool added = false; + if ( brep_cut.IsDone() ) { + TopoDS_Shape brep_cut_result = brep_cut; + BRepCheck_Analyzer analyser(brep_cut_result); + bool is_valid = analyser.IsValid() != 0; + if (is_valid) { + TopExp_Explorer exp(brep_cut_result, TopAbs_SOLID); + for (; exp.More(); exp.Next()) { + builder.Add(compound, exp.Current()); + added = true; + } + } + } + if (!added) { + // Add the original in case subtraction fails + builder.Add(compound, exp.Current()); + } else { + Logger::Message(Logger::LOG_ERROR,"Failed to process subtraction:",entity->entity); + } + } + + entity_shape = compound; + + } else { + BRepAlgoAPI_Cut brep_cut(entity_shape,opening_shape); + + if ( brep_cut.IsDone() ) { + TopoDS_Shape brep_cut_result = brep_cut; - BRepCheck_Analyzer analyser(brep_cut_result); - bool is_valid = analyser.IsValid() != 0; - if ( is_valid ) { - entity_shape = brep_cut; - if ( Logger::Verbosity() >= Logger::LOG_WARNING ) { - const double volume_after_subtraction = shape_volume(entity_shape); + BRepCheck_Analyzer analyser(brep_cut_result); + bool is_valid = analyser.IsValid() != 0; + if ( is_valid ) { + entity_shape = brep_cut; + if ( Logger::Verbosity() >= Logger::LOG_WARNING ) { + const double volume_after_subtraction = shape_volume(entity_shape); - if ( ALMOST_THE_SAME(original_shape_volume,volume_after_subtraction) ) - Logger::Message(Logger::LOG_WARNING,"Subtraction yields unchanged volume:",entity->entity); + if ( ALMOST_THE_SAME(original_shape_volume,volume_after_subtraction) ) + Logger::Message(Logger::LOG_WARNING,"Subtraction yields unchanged volume:",entity->entity); + } + } else { + Logger::Message(Logger::LOG_ERROR,"Invalid result from subtraction:",entity->entity); } } else { - Logger::Message(Logger::LOG_ERROR,"Invalid result from subtraction:",entity->entity); + Logger::Message(Logger::LOG_ERROR,"Failed to process subtraction:",entity->entity); } - } else { - Logger::Message(Logger::LOG_ERROR,"Failed to process subtraction:",entity->entity); } } diff --git a/src/ifcgeom/IfcGeomShapes.cpp b/src/ifcgeom/IfcGeomShapes.cpp index b85d15d659..f56b7ac45f 100644 --- a/src/ifcgeom/IfcGeomShapes.cpp +++ b/src/ifcgeom/IfcGeomShapes.cpp @@ -96,8 +96,9 @@ #include "../ifcgeom/IfcGeom.h" bool IfcGeom::convert(const IfcSchema::IfcExtrudedAreaSolid* l, TopoDS_Shape& shape) { - TopoDS_Face face; + TopoDS_Shape face; if ( ! IfcGeom::convert_face(l->SweptArea(),face) ) return false; + const double height = l->Depth() * IfcGeom::GetValue(GV_LENGTH_UNIT); gp_Trsf trsf; IfcGeom::convert(l->Position(),trsf); @@ -105,7 +106,34 @@ bool IfcGeom::convert(const IfcSchema::IfcExtrudedAreaSolid* l, TopoDS_Shape& sh gp_Dir dir; convert(l->ExtrudedDirection(),dir); - shape = BRepPrimAPI_MakePrism(face,height*dir); + shape.Nullify(); + + if (face.ShapeType() == TopAbs_COMPOUND) { + + // For compounds (most likely the result of a IfcCompositeProfileDef) + // create a compound solid shape. + + TopExp_Explorer exp(face, TopAbs_FACE); + + TopoDS_CompSolid compound; + BRep_Builder builder; + builder.MakeCompSolid(compound); + + int num_faces_extruded = 0; + for (; exp.More(); exp.Next(), ++num_faces_extruded) { + builder.Add(compound, BRepPrimAPI_MakePrism(exp.Current(), height*dir)); + } + + if (num_faces_extruded) { + shape = compound; + } + + } + + if (shape.IsNull()) { + shape = BRepPrimAPI_MakePrism(face, height*dir); + } + shape.Move(trsf); return ! shape.IsNull(); }