diff --git a/src/Mod/Part/App/TopoShape.cpp b/src/Mod/Part/App/TopoShape.cpp index a094dcb3a0..2aea7da5c4 100644 --- a/src/Mod/Part/App/TopoShape.cpp +++ b/src/Mod/Part/App/TopoShape.cpp @@ -1486,7 +1486,7 @@ TopoDS_Shape TopoShape::cut(TopoDS_Shape shape) const if (shape.IsNull()) Standard_Failure::Raise("Tool shape is null"); BRepAlgoAPI_Cut mkCut(this->_Shape, shape); - return mkCut.Shape(); + return makeShell(mkCut.Shape()); } TopoDS_Shape TopoShape::cut(const std::vector& shapes, Standard_Real tolerance) const @@ -1521,7 +1521,7 @@ TopoDS_Shape TopoShape::cut(const std::vector& shapes, Standard_Re throw Base::RuntimeError("Multi cut failed"); TopoDS_Shape resShape = mkCut.Shape(); - return resShape; + return makeShell(resShape); #endif } @@ -1532,7 +1532,7 @@ TopoDS_Shape TopoShape::common(TopoDS_Shape shape) const if (shape.IsNull()) Standard_Failure::Raise("Tool shape is null"); BRepAlgoAPI_Common mkCommon(this->_Shape, shape); - return mkCommon.Shape(); + return makeShell(mkCommon.Shape()); } TopoDS_Shape TopoShape::common(const std::vector& shapes, Standard_Real tolerance) const @@ -1567,7 +1567,7 @@ TopoDS_Shape TopoShape::common(const std::vector& shapes, Standard throw Base::RuntimeError("Multi common failed"); TopoDS_Shape resShape = mkCommon.Shape(); - return resShape; + return makeShell(resShape); #endif } @@ -1578,7 +1578,7 @@ TopoDS_Shape TopoShape::fuse(TopoDS_Shape shape) const if (shape.IsNull()) Standard_Failure::Raise("Tool shape is null"); BRepAlgoAPI_Fuse mkFuse(this->_Shape, shape); - return mkFuse.Shape(); + return makeShell(mkFuse.Shape()); } TopoDS_Shape TopoShape::fuse(const std::vector& shapes, Standard_Real tolerance) const @@ -1627,7 +1627,7 @@ TopoDS_Shape TopoShape::fuse(const std::vector& shapes, Standard_R TopoDS_Shape resShape = mkFuse.Shape(); #endif - return resShape; + return makeShell(resShape); } TopoDS_Shape TopoShape::oldFuse(TopoDS_Shape shape) const @@ -3449,3 +3449,71 @@ TopoDS_Shape TopoShape::defeaturing(const std::vector& s) const return defeat.Shape(); #endif } + +/** + * @brief TopoShape::makeShell + * If the input shape is a compound with faces not being part of a shell + * it tries to make a shell. + * If this operation fails or if the input shape is not a compound or a compound + * with not only faces the input shape is returned. + * @return Shell or passed shape + */ +TopoDS_Shape TopoShape::makeShell(const TopoDS_Shape& input) const +{ + if (input.IsNull()) + return input; + if (input.ShapeType() != TopAbs_COMPOUND) + return input; + + // we need a compound that consists of only faces + TopExp_Explorer it; + // no shells + it.Init(input, TopAbs_SHELL); + if (it.More()) + return input; + + // no wires outside a face + it.Init(input, TopAbs_WIRE, TopAbs_FACE); + if (it.More()) + return input; + + // no edges outside a wire + it.Init(input, TopAbs_EDGE, TopAbs_WIRE); + if (it.More()) + return input; + + // no vertexes outside an edge + it.Init(input, TopAbs_VERTEX, TopAbs_EDGE); + if (it.More()) + return input; + + BRep_Builder builder; + TopoDS_Shape shape; + TopoDS_Shell shell; + builder.MakeShell(shell); + + try { + for (it.Init(input, TopAbs_FACE); it.More(); it.Next()) { + if (!it.Current().IsNull()) + builder.Add(shell, it.Current()); + } + + shape = shell; + BRepCheck_Analyzer check(shell); + if (!check.IsValid()) { + ShapeUpgrade_ShellSewing sewShell; + shape = sewShell.ApplySewing(shell); + } + + if (shape.IsNull()) + return input; + + if (shape.ShapeType() != TopAbs_SHELL) + return input; + + return shape; // success + } + catch (Standard_Failure&) { + return input; + } +} diff --git a/src/Mod/Part/App/TopoShape.h b/src/Mod/Part/App/TopoShape.h index 30d0174ca5..ce9cb6fab9 100644 --- a/src/Mod/Part/App/TopoShape.h +++ b/src/Mod/Part/App/TopoShape.h @@ -238,6 +238,7 @@ public: bool removeInternalWires(double); TopoDS_Shape removeSplitter() const; TopoDS_Shape defeaturing(const std::vector& s) const; + TopoDS_Shape makeShell(const TopoDS_Shape&) const; //@} /** @name Getting basic geometric entities */