From 95dabcd8d48217b459bf126f0dd8df41e94bbd99 Mon Sep 17 00:00:00 2001 From: mbs Date: Wed, 3 May 2023 11:34:50 +0100 Subject: [PATCH 1/1] Fixed a problem where the boolean cut operation of a self-intersecting compound against a solid shape did not give the expected result. --- .../FeaturesPlugin_BooleanCut.cpp | 32 +++++-- .../Test/TestBooleanCut_Solid_Compound.py | 90 +++++++++++++++++++ src/FeaturesPlugin/tests.set | 1 + 3 files changed, 118 insertions(+), 5 deletions(-) create mode 100644 src/FeaturesPlugin/Test/TestBooleanCut_Solid_Compound.py diff --git a/src/FeaturesPlugin/FeaturesPlugin_BooleanCut.cpp b/src/FeaturesPlugin/FeaturesPlugin_BooleanCut.cpp index 1aaa84a0f..02b5c0738 100644 --- a/src/FeaturesPlugin/FeaturesPlugin_BooleanCut.cpp +++ b/src/FeaturesPlugin/FeaturesPlugin_BooleanCut.cpp @@ -36,6 +36,25 @@ #include +static const ListOfShape ExplodeCompounds(const ListOfShape &aList) +{ + ListOfShape subShapes; + for (auto shp = aList.cbegin(); shp != aList.cend(); ++shp) + { + if ((*shp).get() && (*shp)->isCompound()) { + // Use all sub shapes of the compound + for (GeomAPI_ShapeIterator anExp(*shp); anExp.more(); anExp.next()) { + GeomShapePtr aCurrent = anExp.current(); + subShapes.push_back(aCurrent); + } + } + else + subShapes.push_back(*shp); + } + + return subShapes; +} + //================================================================================================== FeaturesPlugin_BooleanCut::FeaturesPlugin_BooleanCut() : FeaturesPlugin_Boolean(FeaturesPlugin_Boolean::BOOL_CUT) @@ -87,6 +106,9 @@ void FeaturesPlugin_BooleanCut::execute() bool aUseFuzzy = boolean(USE_FUZZY_ID())->value(); double aFuzzy = (aUseFuzzy ? real(FUZZY_PARAM_ID())->value() : -1); + // When selecting a compound tool object, use its exploded subshapes as tool object instead. + const ListOfShape aToolList = ExplodeCompounds(aTools.objects()); + // For solids cut each object with all tools. bool isOk = true; for (GeomAPI_ShapeHierarchy::iterator anObjectsIt = anObjects.begin(); @@ -100,7 +122,7 @@ void FeaturesPlugin_BooleanCut::execute() if (aShapeType == GeomAPI_Shape::COMPOUND) { // Compound handling isOk = processCompound(GeomAlgoAPI_Tools::BOOL_CUT, - anObjects, aParent, aTools.objects(), + anObjects, aParent, aToolList, aFuzzy, aResultIndex, aResultBaseAlgoList, aResultShapesList, aResultCompound); @@ -108,7 +130,7 @@ void FeaturesPlugin_BooleanCut::execute() else if (aShapeType == GeomAPI_Shape::COMPSOLID) { // Compsolid handling isOk = processCompsolid(GeomAlgoAPI_Tools::BOOL_CUT, - anObjects, aParent, aTools.objects(), ListOfShape(), + anObjects, aParent, aToolList, ListOfShape(), aFuzzy, aResultIndex, aResultBaseAlgoList, aResultShapesList, aResultCompound); @@ -116,14 +138,14 @@ void FeaturesPlugin_BooleanCut::execute() } else { // process object as is isOk = processObject(GeomAlgoAPI_Tools::BOOL_CUT, - anObject, aTools.objects(), aPlanes, + anObject, aToolList, aPlanes, aFuzzy, aResultIndex, aResultBaseAlgoList, aResultShapesList, aResultCompound); } } - storeResult(anObjects.objects(), aTools.objects(), aResultCompound, aResultIndex, + storeResult(anObjects.objects(), aToolList, aResultCompound, aResultIndex, aMakeShapeList, aResultBaseAlgoList); // Store deleted shapes after all results has been proceeded. This is to avoid issue when in one @@ -131,7 +153,7 @@ void FeaturesPlugin_BooleanCut::execute() if (!aResultCompound) aResultCompound = GeomAlgoAPI_CompoundBuilder::compound(aResultShapesList); ModelAPI_Tools::loadDeletedShapes(aResultBaseAlgoList, - aTools.objects(), + aToolList, aResultCompound); // remove the rest results if there were produced in the previous pass diff --git a/src/FeaturesPlugin/Test/TestBooleanCut_Solid_Compound.py b/src/FeaturesPlugin/Test/TestBooleanCut_Solid_Compound.py new file mode 100644 index 000000000..2828a187f --- /dev/null +++ b/src/FeaturesPlugin/Test/TestBooleanCut_Solid_Compound.py @@ -0,0 +1,90 @@ +# Copyright (C) 2014-2022 CEA/DEN, EDF R&D +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +### +### SHAPER component +### + +from salome.shaper import model + +model.begin() +partSet = model.moduleDocument() + +### Create Part +Part_1 = model.addPart(partSet) +Part_1_doc = Part_1.document() +model.addParameter(Part_1_doc, "nb", '6') + +### Create Cylinder +Cylinder_1 = model.addCylinder(Part_1_doc, model.selection("VERTEX", "PartSet/Origin"), model.selection("EDGE", "PartSet/OZ"), 5, 10) + +### Create Sketch +Sketch_1 = model.addSketch(Part_1_doc, model.selection("FACE", "Cylinder_1_1/Face_3")) + +### Create SketchLine +SketchLine_1 = Sketch_1.addLine(-3.635759493440736, -2.855949413069177, 3.547995857301719, -2.855949413069177) + +### Create SketchProjection +SketchProjection_1 = Sketch_1.addProjection(model.selection("EDGE", "PartSet/OY"), False) +SketchLine_2 = SketchProjection_1.createdFeature() + +### Create SketchLine +SketchLine_3 = Sketch_1.addLine(3.547995857301719, -2.855949413069177, 3.547995857301719, -5.405023892364889) + +### Create SketchLine +SketchLine_4 = Sketch_1.addLine(3.547995857301719, -5.405023892364889, -3.635759493440736, -5.405023892364889) + +### Create SketchLine +SketchLine_5 = Sketch_1.addLine(-3.635759493440736, -5.405023892364889, -3.635759493440736, -2.855949413069177) +Sketch_1.setCoincident(SketchLine_5.endPoint(), SketchLine_1.startPoint()) +Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_3.startPoint()) +Sketch_1.setCoincident(SketchLine_3.endPoint(), SketchLine_4.startPoint()) +Sketch_1.setCoincident(SketchLine_4.endPoint(), SketchLine_5.startPoint()) + +### Create SketchLine +SketchLine_6 = Sketch_1.addLine(-3.635759493440736, -2.855949413069177, 3.547995857301719, -5.405023892364889) +SketchLine_6.setAuxiliary(True) + +### Create SketchLine +SketchLine_7 = Sketch_1.addLine(3.547995857301719, -2.855949413069177, -3.635759493440736, -5.405023892364889) +SketchLine_7.setAuxiliary(True) +Sketch_1.setCoincident(SketchLine_1.startPoint(), SketchLine_6.startPoint()) +Sketch_1.setCoincident(SketchLine_3.startPoint(), SketchLine_7.startPoint()) +Sketch_1.setCoincident(SketchLine_4.startPoint(), SketchLine_6.endPoint()) +Sketch_1.setCoincident(SketchLine_5.startPoint(), SketchLine_7.endPoint()) +Sketch_1.setHorizontal(SketchLine_1.result()) +Sketch_1.setVertical(SketchLine_3.result()) +Sketch_1.setHorizontal(SketchLine_4.result()) +Sketch_1.setVertical(SketchLine_5.result()) +model.do() + +### Create Extrusion +Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchLine_5r-SketchLine_4r-SketchLine_3r-SketchLine_1r")], model.selection(), 1, 11, "Faces|Wires") + +### Create AngularCopy +AngularCopy_1 = model.addMultiRotation(Part_1_doc, [model.selection("SOLID", "Extrusion_1_1")], model.selection("EDGE", "PartSet/OZ"), "nb", keepSubResults = True) + +### Create Cut +Cut_1 = model.addCut(Part_1_doc, [model.selection("SOLID", "Cylinder_1_1")], [model.selection("COMPOUND", "AngularCopy_1_1")], keepSubResults = True) + +model.do() +model.end() + +model.testResults(Cut_1, 1, [0], [1], [8], [18], [12]) +model.testResultsVolumes(Cut_1, [282.54761399726]) diff --git a/src/FeaturesPlugin/tests.set b/src/FeaturesPlugin/tests.set index 75aabe51e..98f8623c6 100644 --- a/src/FeaturesPlugin/tests.set +++ b/src/FeaturesPlugin/tests.set @@ -228,6 +228,7 @@ SET(TEST_NAMES_PARA TestBooleanCut_Shell_Shell.py TestBooleanCut_ShellCompound_ShellCompound.py TestBooleanCut_Solid_Solid.py + TestBooleanCut_Solid_Compound.py TestBooleanCut_SolidCompound_SolidCompound.py TestBooleanCut_Vertex_Vertex.py TestBooleanCut_VertexCompound_Solid.py -- 2.30.2