From e6aa449ef8e7b2550ce955628c7dc85865241587 Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Sun, 6 Jul 2014 14:21:56 +0000 Subject: [PATCH] Accept IfcBooleanResult operands that convert to set of shapes in IfcOpenShell rather than a single shape (i.e IfcShellBasedSurfaceModel, IfcFaceBasedSurfaceModel, IfcFacetedBrep, IfcGeometricSet) --- src/ifcgeom/IfcGeom.h | 1 + src/ifcgeom/IfcGeomFunctions.cpp | 60 +++++++++++++++++++++++++++++++- src/ifcgeom/IfcGeomShapes.cpp | 21 +++++++++-- 3 files changed, 78 insertions(+), 4 deletions(-) diff --git a/src/ifcgeom/IfcGeom.h b/src/ifcgeom/IfcGeom.h index 99cf2bc3ac..610ed7aafc 100644 --- a/src/ifcgeom/IfcGeom.h +++ b/src/ifcgeom/IfcGeom.h @@ -84,6 +84,7 @@ namespace IfcGeom { bool convert_shapes(const IfcUtil::IfcBaseClass* L, IfcRepresentationShapeItems& result); bool is_shape_collection(const IfcUtil::IfcBaseClass* L); bool convert_shape(const IfcUtil::IfcBaseClass* L, TopoDS_Shape& result); + bool flatten_shape_list(const IfcGeom::IfcRepresentationShapeItems& shapes, TopoDS_Shape& result, bool fuse); bool convert_wire(const IfcUtil::IfcBaseClass* L, TopoDS_Wire& result); bool convert_curve(const IfcUtil::IfcBaseClass* L, Handle(Geom_Curve)& result); bool convert_face(const IfcUtil::IfcBaseClass* L, TopoDS_Shape& result); diff --git a/src/ifcgeom/IfcGeomFunctions.cpp b/src/ifcgeom/IfcGeomFunctions.cpp index 6cdfe09a60..094fd60b5c 100644 --- a/src/ifcgeom/IfcGeomFunctions.cpp +++ b/src/ifcgeom/IfcGeomFunctions.cpp @@ -69,6 +69,7 @@ #include #include #include +#include #include #include @@ -691,4 +692,61 @@ bool IfcGeom::fill_nonmanifold_wires_with_planar_faces(TopoDS_Shape& shape) { } catch(...) {} return true; -} \ No newline at end of file +} + +bool IfcGeom::flatten_shape_list(const IfcGeom::IfcRepresentationShapeItems& shapes, TopoDS_Shape& result, bool fuse) { + TopoDS_Compound compound; + BRep_Builder builder; + builder.MakeCompound(compound); + + result = TopoDS_Shape(); + + for ( IfcGeom::IfcRepresentationShapeItems::const_iterator it = shapes.begin(); it != shapes.end(); ++ it ) { + TopoDS_Shape merged; + const TopoDS_Shape& s = it->Shape(); + if (fuse) { + IfcGeom::ensure_fit_for_subtraction(s, merged); + } else { + merged = s; + } + const gp_GTrsf& trsf = it->Placement(); + bool trsf_valid = false; + gp_Trsf _trsf; + try { + _trsf = trsf.Trsf(); + trsf_valid = true; + } catch (...) {} + const TopoDS_Shape moved_shape = trsf_valid ? merged.Moved(_trsf) : + BRepBuilderAPI_GTransform(merged,trsf,true).Shape(); + + if (shapes.size() == 1) { + result = moved_shape; + return true; + } + + if (fuse) { + if (result.IsNull()) { + result = moved_shape; + } else { + BRepAlgoAPI_Fuse brep_fuse(result, moved_shape); + if ( brep_fuse.IsDone() ) { + TopoDS_Shape fused = brep_fuse; + + ShapeFix_Shape fix(result); + fix.Perform(); + result = fix.Shape(); + + bool is_valid = BRepCheck_Analyzer(result).IsValid() != 0; + if ( is_valid ) { + result = fused; + } + } + } + } else { + builder.Add(compound,moved_shape); + } + } + + return !result.IsNull(); +} + \ No newline at end of file diff --git a/src/ifcgeom/IfcGeomShapes.cpp b/src/ifcgeom/IfcGeomShapes.cpp index 432dff57a7..b85d15d659 100644 --- a/src/ifcgeom/IfcGeomShapes.cpp +++ b/src/ifcgeom/IfcGeomShapes.cpp @@ -242,19 +242,34 @@ bool IfcGeom::convert(const IfcSchema::IfcShellBasedSurfaceModel* l, IfcRepresen bool IfcGeom::convert(const IfcSchema::IfcBooleanResult* l, TopoDS_Shape& shape) { TopoDS_Shape s1, s2; + IfcRepresentationShapeItems items1, items2; TopoDS_Wire boundary_wire; IfcSchema::IfcBooleanOperand operand1 = l->FirstOperand(); IfcSchema::IfcBooleanOperand operand2 = l->SecondOperand(); bool is_halfspace = operand2->is(IfcSchema::Type::IfcHalfSpaceSolid); - if ( ! IfcGeom::convert_shape(operand1,s1) ) - return false; + if ( is_shape_collection(operand1) ) { + if (!(convert_shapes(operand1, items1) && flatten_shape_list(items1, s1, true))) { + return false; + } + } else { + if ( ! IfcGeom::convert_shape(operand1,s1) ) { + return false; + } + } const double first_operand_volume = shape_volume(s1); if ( first_operand_volume <= ALMOST_ZERO ) Logger::Message(Logger::LOG_WARNING,"Empty solid for:",l->FirstOperand()->entity); - if ( !IfcGeom::convert_shape(l->SecondOperand(),s2) ) { + bool shape2_processed = false; + if ( is_shape_collection(operand2) ) { + shape2_processed = convert_shapes(operand2, items2) && flatten_shape_list(items2, s2, true); + } else { + shape2_processed = IfcGeom::convert_shape(operand2,s2); + } + + if (!shape2_processed) { shape = s1; Logger::Message(Logger::LOG_ERROR,"Failed to convert SecondOperand of:",l->entity); return true;