Salome HOME
Task #3005 : To be able to create a group on a whole result
authormpv <mpv@opencascade.com>
Tue, 17 Sep 2019 09:48:10 +0000 (12:48 +0300)
committermpv <mpv@opencascade.com>
Tue, 17 Sep 2019 09:48:10 +0000 (12:48 +0300)
Implementation of move in the history of the whole objects.

src/CollectionPlugin/CMakeLists.txt
src/CollectionPlugin/Test/TestGroupMove21.py [new file with mode: 0644]
src/CollectionPlugin/Test/TestGroupMove22.py [new file with mode: 0644]
src/CollectionPlugin/Test/TestGroupMove23.py [new file with mode: 0644]
src/CollectionPlugin/Test/TestGroupMove24.py [new file with mode: 0644]
src/CollectionPlugin/Test/TestGroupMove25.py [new file with mode: 0644]
src/ExchangePlugin/ExchangePlugin_ExportFeature.cpp
src/Model/Model_AttributeSelection.cpp
src/Model/Model_AttributeSelection.h
src/Model/Model_AttributeSelectionList.cpp
src/Model/Model_AttributeSelectionList.h

index fa72858f47a8bce9e6e86d7c323990b357d1b329..611fbc3d7b179be65b93977f505e1889aa90419a 100644 (file)
@@ -138,6 +138,11 @@ ADD_UNIT_TESTS(
                TestGroupMove18.py
                TestGroupMove19.py
                TestGroupMove20.py
+               TestGroupMove21.py
+               TestGroupMove22.py
+               TestGroupMove23.py
+               TestGroupMove24.py
+               TestGroupMove25.py
                TestGroupShareTopology.py
                TestGroupAddition.py
                TestGroupAddition_Error.py
diff --git a/src/CollectionPlugin/Test/TestGroupMove21.py b/src/CollectionPlugin/Test/TestGroupMove21.py
new file mode 100644 (file)
index 0000000..4dda28f
--- /dev/null
@@ -0,0 +1,60 @@
+# Copyright (C) 2014-2019  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
+#
+
+# Test move the group in history for selection of a whole result
+
+from salome.shaper import model
+from GeomAPI import *
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchLine_1 = Sketch_1.addLine(35.07635467980296, 23.01108374384237, -25.74753694581282, 23.01108374384237)
+SketchLine_2 = Sketch_1.addLine(-25.74753694581282, 23.01108374384237, -25.74753694581282, -23.13546798029557)
+SketchLine_3 = Sketch_1.addLine(-25.74753694581282, -23.13546798029557, 35.07635467980296, -23.13546798029557)
+SketchLine_4 = Sketch_1.addLine(35.07635467980296, -23.13546798029557, 35.07635467980296, 23.01108374384237)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchLine_4.endPoint(), SketchLine_1.startPoint())
+SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchConstraintCoincidence_3 = Sketch_1.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+SketchConstraintCoincidence_4 = Sketch_1.setCoincident(SketchLine_3.endPoint(), SketchLine_4.startPoint())
+SketchConstraintHorizontal_1 = Sketch_1.setHorizontal(SketchLine_1.result())
+SketchConstraintVertical_1 = Sketch_1.setVertical(SketchLine_2.result())
+SketchConstraintHorizontal_2 = Sketch_1.setHorizontal(SketchLine_3.result())
+SketchConstraintVertical_2 = Sketch_1.setVertical(SketchLine_4.result())
+model.do()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchLine_1r-SketchLine_2f-SketchLine_3f-SketchLine_4f")], model.selection(), 80, 0)
+# selection of a whole result: 6 faces of a box
+Group_1 = model.addGroup(Part_1_doc, "Faces", [model.selection("SOLID", "Extrusion_1_1")])
+model.testNbSubShapes(Group_1, GeomAPI_Shape.FACE, [6])
+ExtrusionCut_1 = model.addExtrusionCut(Part_1_doc, [], model.selection(), 0, 10, [model.selection("SOLID", "Extrusion_1_1")])
+Sketch_2 = model.addSketch(Part_1_doc, model.selection("FACE", "Extrusion_1_1/Generated_Face&Sketch_1/SketchLine_3"))
+SketchCircle_1 = Sketch_2.addCircle(-7.736745115674536, 52.14422040986419, 6.760003867274182)
+ExtrusionCut_1.setNestedSketch(Sketch_2)
+model.do()
+# move group after the extrusion-cut, so, it refers to it
+Part_1_doc.moveFeature(Group_1.feature(), ExtrusionCut_1.feature())
+model.end()
+
+# check that there is a hole appeared in the group-results
+assert(len(Group_1.feature().results())==1)
+model.testNbSubShapes(Group_1, GeomAPI_Shape.FACE, [8])
+
+assert(model.checkPythonDump())
diff --git a/src/CollectionPlugin/Test/TestGroupMove22.py b/src/CollectionPlugin/Test/TestGroupMove22.py
new file mode 100644 (file)
index 0000000..40802c6
--- /dev/null
@@ -0,0 +1,62 @@
+# Copyright (C) 2014-2019  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
+#
+
+# Test move the group in history for selection of a whole result of a compsolid
+
+from salome.shaper import model
+from GeomAPI import *
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchLine_1 = Sketch_1.addLine(-25.00123152709361, 27.48891625615764, 27.86206896551725, 27.48891625615764)
+SketchConstraintHorizontal_1 = Sketch_1.setHorizontal(SketchLine_1.result())
+SketchLine_2 = Sketch_1.addLine(27.86206896551725, 27.48891625615764, -23.88177339901478, -20.02586206896552)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchLine_3 = Sketch_1.addLine(-23.88177339901478, -20.02586206896552, 28.73275862068966, -20.02586206896552)
+SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+SketchConstraintHorizontal_2 = Sketch_1.setHorizontal(SketchLine_3.result())
+SketchLine_4 = Sketch_1.addLine(28.73275862068966, -20.02586206896552, 27.86206896551725, 27.48891625615764)
+SketchConstraintCoincidence_3 = Sketch_1.setCoincident(SketchLine_3.endPoint(), SketchLine_4.startPoint())
+SketchConstraintCoincidence_4 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_4.endPoint())
+SketchLine_5 = Sketch_1.addLine(-25.00123152709361, 27.48891625615764, 28.73275862068966, -20.02586206896552)
+SketchConstraintCoincidence_5 = Sketch_1.setCoincident(SketchLine_1.startPoint(), SketchLine_5.startPoint())
+SketchConstraintCoincidence_6 = Sketch_1.setCoincident(SketchLine_3.endPoint(), SketchLine_5.endPoint())
+model.do()
+Extrusion_1_objects = [model.selection("FACE", "Sketch_1/Face-SketchLine_5f-SketchLine_2r-SketchLine_1r"), model.selection("FACE", "Sketch_1/Face-SketchLine_2f-SketchLine_5f-SketchLine_4f"), model.selection("FACE", "Sketch_1/Face-SketchLine_2f-SketchLine_3f-SketchLine_5r")]
+Extrusion_1 = model.addExtrusion(Part_1_doc, Extrusion_1_objects, model.selection(), 10, 0)
+# selection of a whole result: 5x3-2 faces (2 faces are shared)
+Group_1 = model.addGroup(Part_1_doc, "Faces", [model.selection("COMPSOLID", "Extrusion_1_1")])
+model.testNbSubShapes(Group_1, GeomAPI_Shape.FACE, [13])
+ExtrusionCut_1 = model.addExtrusionCut(Part_1_doc, [], model.selection(), 0, 10, [model.selection("COMPSOLID", "Extrusion_1_1")])
+Sketch_2 = model.addSketch(Part_1_doc, model.selection("FACE", "Extrusion_1_1_1/To_Face"))
+SketchCircle_1 = Sketch_2.addCircle(13.4282260278248, 11.79859034244854, 3.718064241992405)
+ExtrusionCut_1.setNestedSketch(Sketch_2)
+model.do()
+# move group after the extrusion-cut, so, it refers to it
+Part_1_doc.moveFeature(Group_1.feature(), ExtrusionCut_1.feature())
+model.end()
+
+# check that there is a hole appeared in two solids: +4 faces (1 splitted planar, 3 faces of cylinder, divided by seam)
+assert(len(Group_1.feature().results())==1)
+model.testNbSubShapes(Group_1, GeomAPI_Shape.FACE, [17])
+
+assert(model.checkPythonDump())
diff --git a/src/CollectionPlugin/Test/TestGroupMove23.py b/src/CollectionPlugin/Test/TestGroupMove23.py
new file mode 100644 (file)
index 0000000..50d347f
--- /dev/null
@@ -0,0 +1,60 @@
+# Copyright (C) 2014-2019  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
+#
+
+# Test move the group in history for selection of a whole feature
+
+from salome.shaper import model
+from GeomAPI import *
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchLine_1 = Sketch_1.addLine(35.07635467980296, 23.01108374384237, -25.74753694581282, 23.01108374384237)
+SketchLine_2 = Sketch_1.addLine(-25.74753694581282, 23.01108374384237, -25.74753694581282, -23.13546798029557)
+SketchLine_3 = Sketch_1.addLine(-25.74753694581282, -23.13546798029557, 35.07635467980296, -23.13546798029557)
+SketchLine_4 = Sketch_1.addLine(35.07635467980296, -23.13546798029557, 35.07635467980296, 23.01108374384237)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchLine_4.endPoint(), SketchLine_1.startPoint())
+SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchConstraintCoincidence_3 = Sketch_1.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+SketchConstraintCoincidence_4 = Sketch_1.setCoincident(SketchLine_3.endPoint(), SketchLine_4.startPoint())
+SketchConstraintHorizontal_1 = Sketch_1.setHorizontal(SketchLine_1.result())
+SketchConstraintVertical_1 = Sketch_1.setVertical(SketchLine_2.result())
+SketchConstraintHorizontal_2 = Sketch_1.setHorizontal(SketchLine_3.result())
+SketchConstraintVertical_2 = Sketch_1.setVertical(SketchLine_4.result())
+model.do()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchLine_1r-SketchLine_2f-SketchLine_3f-SketchLine_4f")], model.selection(), 80, 0)
+# selection of a whole feature: 6 faces of a box
+Group_1 = model.addGroup(Part_1_doc, "Faces", [model.selection("COMPOUND", "all-in-Extrusion_1")])
+model.testNbSubShapes(Group_1, GeomAPI_Shape.FACE, [6])
+ExtrusionCut_1 = model.addExtrusionCut(Part_1_doc, [], model.selection(), 0, 10, [model.selection("SOLID", "Extrusion_1_1")])
+Sketch_2 = model.addSketch(Part_1_doc, model.selection("FACE", "Extrusion_1_1/Generated_Face&Sketch_1/SketchLine_3"))
+SketchCircle_1 = Sketch_2.addCircle(-7.736745115674536, 52.14422040986419, 6.760003867274182)
+ExtrusionCut_1.setNestedSketch(Sketch_2)
+model.do()
+# move group after the extrusion-cut, so, it refers to it
+Part_1_doc.moveFeature(Group_1.feature(), ExtrusionCut_1.feature())
+model.end()
+
+# check that there is a hole appeared in the group-results
+assert(len(Group_1.feature().results())==1)
+model.testNbSubShapes(Group_1, GeomAPI_Shape.FACE, [8])
+
+assert(model.checkPythonDump())
diff --git a/src/CollectionPlugin/Test/TestGroupMove24.py b/src/CollectionPlugin/Test/TestGroupMove24.py
new file mode 100644 (file)
index 0000000..8b37ce2
--- /dev/null
@@ -0,0 +1,62 @@
+# Copyright (C) 2014-2019  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
+#
+
+# Test move the group in history for selection of a whole feature that produces compsolid
+
+from salome.shaper import model
+from GeomAPI import *
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchLine_1 = Sketch_1.addLine(-25.00123152709361, 27.48891625615764, 27.86206896551725, 27.48891625615764)
+SketchConstraintHorizontal_1 = Sketch_1.setHorizontal(SketchLine_1.result())
+SketchLine_2 = Sketch_1.addLine(27.86206896551725, 27.48891625615764, -23.88177339901478, -20.02586206896552)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchLine_3 = Sketch_1.addLine(-23.88177339901478, -20.02586206896552, 28.73275862068966, -20.02586206896552)
+SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+SketchConstraintHorizontal_2 = Sketch_1.setHorizontal(SketchLine_3.result())
+SketchLine_4 = Sketch_1.addLine(28.73275862068966, -20.02586206896552, 27.86206896551725, 27.48891625615764)
+SketchConstraintCoincidence_3 = Sketch_1.setCoincident(SketchLine_3.endPoint(), SketchLine_4.startPoint())
+SketchConstraintCoincidence_4 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_4.endPoint())
+SketchLine_5 = Sketch_1.addLine(-25.00123152709361, 27.48891625615764, 28.73275862068966, -20.02586206896552)
+SketchConstraintCoincidence_5 = Sketch_1.setCoincident(SketchLine_1.startPoint(), SketchLine_5.startPoint())
+SketchConstraintCoincidence_6 = Sketch_1.setCoincident(SketchLine_3.endPoint(), SketchLine_5.endPoint())
+model.do()
+Extrusion_1_objects = [model.selection("FACE", "Sketch_1/Face-SketchLine_5f-SketchLine_2r-SketchLine_1r"), model.selection("FACE", "Sketch_1/Face-SketchLine_2f-SketchLine_5f-SketchLine_4f"), model.selection("FACE", "Sketch_1/Face-SketchLine_2f-SketchLine_3f-SketchLine_5r")]
+Extrusion_1 = model.addExtrusion(Part_1_doc, Extrusion_1_objects, model.selection(), 10, 0)
+# selection of a whole result: 5x3-2 faces (2 faces are shared)
+Group_1 = model.addGroup(Part_1_doc, "Faces", [model.selection("COMPOUND", "all-in-Extrusion_1")])
+model.testNbSubShapes(Group_1, GeomAPI_Shape.FACE, [13])
+ExtrusionCut_1 = model.addExtrusionCut(Part_1_doc, [], model.selection(), 0, 10, [model.selection("COMPSOLID", "Extrusion_1_1")])
+Sketch_2 = model.addSketch(Part_1_doc, model.selection("FACE", "Extrusion_1_1_1/To_Face"))
+SketchCircle_1 = Sketch_2.addCircle(13.4282260278248, 11.79859034244854, 3.718064241992405)
+ExtrusionCut_1.setNestedSketch(Sketch_2)
+model.do()
+# move group after the extrusion-cut, so, it refers to it
+Part_1_doc.moveFeature(Group_1.feature(), ExtrusionCut_1.feature())
+model.end()
+
+# check that there is a hole appeared in two solids: +4 faces (1 splitted planar, 3 faces of cylinder, divided by seam)
+assert(len(Group_1.feature().results())==1)
+model.testNbSubShapes(Group_1, GeomAPI_Shape.FACE, [17])
+
+assert(model.checkPythonDump())
diff --git a/src/CollectionPlugin/Test/TestGroupMove25.py b/src/CollectionPlugin/Test/TestGroupMove25.py
new file mode 100644 (file)
index 0000000..24255be
--- /dev/null
@@ -0,0 +1,91 @@
+# Copyright (C) 2014-2019  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
+#
+
+# Test move the group in history for selection of a whole features
+# with many modifications of this feature, and joining them in one.
+
+from SketchAPI import *
+
+from salome.shaper import model
+from ModelAPI import *
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchLine_1 = Sketch_1.addLine(-20, 9.999999999999998, -40, 10)
+SketchLine_2 = Sketch_1.addLine(-40, 10, -40, -10)
+SketchLine_3 = Sketch_1.addLine(-40, -10, -20, -9.999999999999998)
+SketchLine_4 = Sketch_1.addLine(-20, -9.999999999999998, -20, 9.999999999999998)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchLine_4.endPoint(), SketchLine_1.startPoint())
+SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchConstraintCoincidence_3 = Sketch_1.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+SketchConstraintCoincidence_4 = Sketch_1.setCoincident(SketchLine_3.endPoint(), SketchLine_4.startPoint())
+SketchConstraintHorizontal_1 = Sketch_1.setHorizontal(SketchLine_1.result())
+SketchConstraintVertical_1 = Sketch_1.setVertical(SketchLine_2.result())
+SketchConstraintHorizontal_2 = Sketch_1.setHorizontal(SketchLine_3.result())
+SketchConstraintVertical_2 = Sketch_1.setVertical(SketchLine_4.result())
+SketchProjection_1 = Sketch_1.addProjection(model.selection("VERTEX", "PartSet/Origin"), False)
+SketchPoint_1 = SketchProjection_1.createdFeature()
+SketchCircle_1 = Sketch_1.addCircle(0, 0, 10)
+SketchConstraintCoincidence_5 = Sketch_1.setCoincident(SketchPoint_1.result(), SketchCircle_1.center())
+SketchConstraintTangent_1 = Sketch_1.setTangent(SketchLine_1.result(), SketchCircle_1.results()[1])
+SketchConstraintTangent_2 = Sketch_1.setTangent(SketchLine_3.result(), SketchCircle_1.results()[1])
+SketchConstraintDistance_1 = Sketch_1.setDistance(SketchAPI_Point(SketchPoint_1).coordinates(), SketchLine_4.result(), 20, True)
+SketchConstraintRadius_1 = Sketch_1.setRadius(SketchCircle_1.results()[1], 10)
+SketchConstraintEqual_1 = Sketch_1.setEqual(SketchLine_1.result(), SketchLine_4.result())
+model.do()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchLine_1r-SketchLine_2f-SketchLine_3f-SketchLine_4f")], model.selection(), 30, 0)
+Extrusion_2 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchCircle_1_2f")], model.selection(), 15, 0)
+Group_1 = model.addGroup(Part_1_doc, "Vertices", [model.selection("COMPOUND", "all-in-Extrusion_1")])
+Group_2 = model.addGroup(Part_1_doc, "Vertices", [model.selection("COMPOUND", "all-in-Extrusion_2")])
+Group_3 = model.addGroup(Part_1_doc, "Faces", [model.selection("COMPOUND", "all-in-Extrusion_1"), model.selection("COMPOUND", "all-in-Extrusion_2")])
+ExtrusionFuse_1 = model.addExtrusionFuse(Part_1_doc, [], model.selection(), 12, 0, [model.selection("SOLID", "Extrusion_1_1")])
+Sketch_2 = model.addSketch(Part_1_doc, model.selection("FACE", "Extrusion_1_1/Generated_Face&Sketch_1/SketchLine_4"))
+SketchCircle_2 = Sketch_2.addCircle(-2.3396523840492e-15, 15, 7)
+SketchConstraintRadius_2 = Sketch_2.setRadius(SketchCircle_2.results()[1], 7)
+SketchProjection_2 = Sketch_2.addProjection(model.selection("EDGE", "[Extrusion_1_1/Generated_Face&Sketch_1/SketchLine_1][Extrusion_1_1/Generated_Face&Sketch_1/SketchLine_4]"), False)
+SketchLine_5 = SketchProjection_2.createdFeature()
+SketchConstraintDistance_2 = Sketch_2.setDistance(SketchCircle_2.center(), SketchLine_5.result(), 10, True)
+SketchProjection_3 = Sketch_2.addProjection(model.selection("EDGE", "[Extrusion_1_1/Generated_Face&Sketch_1/SketchLine_4][Extrusion_1_1/To_Face]"), False)
+SketchLine_6 = SketchProjection_3.createdFeature()
+SketchConstraintDistance_3 = Sketch_2.setDistance(SketchCircle_2.center(), SketchLine_6.result(), 15, True)
+ExtrusionFuse_1.setNestedSketch(Sketch_2)
+ExtrusionCut_1 = model.addExtrusionCut(Part_1_doc, [], model.selection(), 50, 50, [model.selection("SOLID", "ExtrusionFuse_1_1"), model.selection("SOLID", "Extrusion_2_1")])
+Sketch_3 = model.addSketch(Part_1_doc, model.selection("FACE", "ExtrusionFuse_1_1/To_Face"))
+SketchProjection_4 = Sketch_3.addProjection(model.selection("VERTEX", "[ExtrusionFuse_1_1/Generated_Face&Sketch_2/SketchCircle_2_2][ExtrusionFuse_1_1/To_Face]__cc"), False)
+SketchPoint_2 = SketchProjection_4.createdFeature()
+SketchCircle_3 = Sketch_3.addCircle(-2.3396523840492e-15, 15, 5)
+SketchConstraintCoincidence_6 = Sketch_3.setCoincident(SketchPoint_2.result(), SketchCircle_3.center())
+SketchConstraintRadius_3 = Sketch_3.setRadius(SketchCircle_3.results()[1], 5)
+ExtrusionCut_1.setNestedSketch(Sketch_3)
+Fuse_1 = model.addFuse(Part_1_doc, [model.selection("SOLID", "ExtrusionCut_1_1"), model.selection("SOLID", "ExtrusionCut_1_2")], True, 20190506)
+model.do()
+# move groups after the final fuse
+Part_1_doc.moveFeature(Group_1.feature(), Fuse_1.feature())
+Part_1_doc.moveFeature(Group_2.feature(), Group_1.feature())
+Part_1_doc.moveFeature(Group_3.feature(), Group_2.feature())
+model.end()
+
+aFactory = ModelAPI_Session.get().validators()
+for group in [Group_1, Group_2, Group_3]:
+  selectionList = group.feature().selectionList("group_list")
+  assert(selectionList.size() == 1)
+  assert(aFactory.validate(group.feature()))
index f38b1c60532e0bced2f5491a4bf4ea430209f903..bf677c743730ed28aecade2876c3acdfd2e9c675 100644 (file)
@@ -297,21 +297,6 @@ static bool isInResults(AttributeSelectionListPtr theSelection,
   return false;
 }
 
-/// Returns all sub-shapes of the given shape in theResult
-static void allSubShapes(const GeomShapePtr theShape, GeomAPI_Shape::ShapeType theType,
-  std::list<GeomShapePtr>& theResult)
-{
-  if (theShape->shapeType() == theType) {
-    theResult.push_back(theShape);
-  } else {
-    GeomAPI_DataMapOfShapeShape aUnique; // to keep only unique shapes
-    for(GeomAPI_ShapeExplorer anExp(theShape, theType); anExp.more(); anExp.next()) {
-      if (aUnique.bind(anExp.current(), anExp.current()))
-        theResult.push_back(anExp.current());
-    }
-  }
-}
-
 void ExchangePlugin_ExportFeature::exportXAO(const std::string& theFileName)
 {
   try {
index bd6a4fb7d3a772ef930f9308057d871d4ebf52a5..496f1e2afffb3f1dd3953076fbe0c2c7c0f74dff 100644 (file)
@@ -1281,6 +1281,56 @@ void Model_AttributeSelection::computeValues(
   }
 }
 
+
+void Model_AttributeSelection::concealedFeature(
+  const FeaturePtr theFeature, const FeaturePtr theStop, std::list<FeaturePtr>& theConcealers)
+{
+  std::set<FeaturePtr> alreadyProcessed;
+  alreadyProcessed.insert(theFeature);
+  if (theStop.get())
+    alreadyProcessed.insert(theStop);
+  /// iterate all results to find the concealment-attribute
+  const std::list<ResultPtr>& aRootRes = theFeature->results();
+  std::list<ResultPtr>::const_iterator aRootIter = aRootRes.cbegin();
+  for(; aRootIter != aRootRes.cend(); aRootIter++) {
+    std::list<ResultPtr> allRes;
+    allRes.push_back(*aRootIter);
+    ResultBodyPtr aRootBody = ModelAPI_Tools::bodyOwner(*aRootIter, true);
+    if (aRootBody.get()) {
+      ModelAPI_Tools::allSubs(aRootBody, allRes);
+    }
+    for(std::list<ResultPtr>::iterator aRIter = allRes.begin(); aRIter != allRes.end(); aRIter++) {
+      const std::set<AttributePtr>& aRefs = (*aRIter)->data()->refsToMe();
+      std::set<AttributePtr>::const_iterator aRef = aRefs.cbegin();
+      for (; aRef != aRefs.cend(); aRef++) {
+        if (!aRef->get() || !(*aRef)->owner().get())
+          continue;
+        // concealed attribute only
+        FeaturePtr aRefFeat = std::dynamic_pointer_cast<ModelAPI_Feature>((*aRef)->owner());
+        if (alreadyProcessed.find(aRefFeat) != alreadyProcessed.end()) // optimization
+          continue;
+        alreadyProcessed.insert(aRefFeat);
+        if (ModelAPI_Session::get()->validators()->isConcealed(aRefFeat->getKind(), (*aRef)->id()))
+        {
+          // for extrusion cut in python script the nested sketch reference may be concealed before
+          // it is nested, so, check this composite feature is valid
+          static ModelAPI_ValidatorsFactory* aFactory = ModelAPI_Session::get()->validators();
+          // need to be validated to update the "Apply" state if not previewed
+          if (aFactory->validate(aRefFeat)) {
+            if (theStop.get()) {
+              std::shared_ptr<Model_Document> aDoc =
+                std::dynamic_pointer_cast<Model_Document>(theStop->document());
+              if (!aDoc->isLaterByDep(theStop, aRefFeat)) // skip feature later than stop
+                continue;
+            }
+            theConcealers.push_back(aRefFeat);
+          }
+        }
+      }
+    }
+  }
+}
+
 bool Model_AttributeSelection::searchNewContext(std::shared_ptr<Model_Document> theDoc,
   const TopoDS_Shape theContShape, ResultPtr theContext, TopoDS_Shape theValShape,
   TDF_Label theAccessLabel,
@@ -1344,59 +1394,29 @@ bool Model_AttributeSelection::searchNewContext(std::shared_ptr<Model_Document>
 
   if (aResults.empty()) {
     // check the context become concealed by operation which is earlier than this selection
-    std::list<ResultPtr> allRes;
-    ResultPtr aRoot = ModelAPI_Tools::bodyOwner(theContext, true);
-    if (!aRoot.get())
-      aRoot = theContext;
-    ResultBodyPtr aRootBody = std::dynamic_pointer_cast<ModelAPI_ResultBody>(aRoot);
-    if (aRootBody.get()) {
-      ModelAPI_Tools::allSubs(aRootBody, allRes);
-      allRes.push_back(aRootBody);
-    } else
-      allRes.push_back(aRoot);
-
     FeaturePtr aThisFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(owner());
-    for (std::list<ResultPtr>::iterator aSub = allRes.begin(); aSub != allRes.end(); aSub++) {
-      ResultPtr aResCont = *aSub;
-      const std::set<AttributePtr>& aRefs = aResCont->data()->refsToMe();
-      std::set<AttributePtr>::const_iterator aRef = aRefs.begin();
-      for (; aRef != aRefs.end(); aRef++) {
-        if (!aRef->get() || !(*aRef)->owner().get())
-          continue;
-        // concealed attribute only
-        FeaturePtr aRefFeat = std::dynamic_pointer_cast<ModelAPI_Feature>((*aRef)->owner());
-        if (aRefFeat == aThisFeature)
+    FeaturePtr aContextOwner = theDoc->feature(theContext);
+    std::list<FeaturePtr> aConcealers;
+    concealedFeature(aContextOwner, aThisFeature, aConcealers);
+    std::list<FeaturePtr>::iterator aConcealer = aConcealers.begin();
+    for(; aConcealer != aConcealers.end(); aConcealer++) {
+      std::list<ResultPtr> aRefResults;
+      ModelAPI_Tools::allResults(*aConcealer, aRefResults);
+      std::list<ResultPtr>::iterator aRefIter = aRefResults.begin();
+      for(; aRefIter != aRefResults.end(); aRefIter++) {
+        ResultBodyPtr aRefBody = std::dynamic_pointer_cast<ModelAPI_ResultBody>(*aRefIter);
+        if (!aRefBody.get() || aRefBody->numberOfSubs() != 0) // iterate only leafs
           continue;
-        if (!ModelAPI_Session::get()->validators()->isConcealed(
-          aRefFeat->getKind(), (*aRef)->id()))
+        GeomShapePtr aRefShape = aRefBody->shape();
+        if (!aRefShape.get() || aRefShape->isNull())
           continue;
-        if (theDoc->isLaterByDep(aThisFeature, aRefFeat)) {
-          // for extrusion cut in python script the nested sketch reference may be concealed before
-          // it is nested, so, check this composite feature is valid
-          static ModelAPI_ValidatorsFactory* aFactory = ModelAPI_Session::get()->validators();
-          // need to be validated to update the "Apply" state if not previewed
-          if (aFactory->validate(aRefFeat)) {
-            // there could be a reference to unmodified object, check result contain same shape
-            std::list<ResultPtr> aRefResults;
-            ModelAPI_Tools::allResults(aRefFeat, aRefResults);
-            std::list<ResultPtr>::iterator aRefIter = aRefResults.begin();
-            for(; aRefIter != aRefResults.end(); aRefIter++) {
-              ResultBodyPtr aRefBody = std::dynamic_pointer_cast<ModelAPI_ResultBody>(*aRefIter);
-              if (!aRefBody.get() || aRefBody->numberOfSubs() != 0) // iterate only leafs
-                continue;
-              GeomShapePtr aRefShape = aRefBody->shape();
-              if (!aRefShape.get() || aRefShape->isNull())
-                continue;
-              if (aRefShape->impl<TopoDS_Shape>().IsSame(theContShape)) {
-                // add the new context result with the same shape
-                aResults.insert(aRefBody);
-              }
-            }
-            if (aResults.empty())
-              return true; // feature conceals result, return true, so the context will be removed
-          }
+        if (aRefShape->impl<TopoDS_Shape>().IsSame(theContShape)) {
+          // add the new context result with the same shape
+          aResults.insert(aRefBody);
         }
       }
+      if (aResults.empty())
+        return true; // feature conceals result, return true, so the context will be removed
     }
     if (aResults.empty())
       return false; // no modifications found, must stay the same
@@ -1439,11 +1459,42 @@ bool Model_AttributeSelection::searchNewContext(std::shared_ptr<Model_Document>
 
 void Model_AttributeSelection::updateInHistory(bool& theRemove)
 {
+  static std::shared_ptr<GeomAPI_Shape> anEmptyShape;
+
   ResultPtr aContext = std::dynamic_pointer_cast<ModelAPI_Result>(myRef.value());
-  // only bodies and parts may be modified later in the history, don't do anything otherwise
   if (!aContext.get() || (aContext->groupName() != ModelAPI_ResultBody::group() &&
-      aContext->groupName() != ModelAPI_ResultPart::group()))
-    return;
+      aContext->groupName() != ModelAPI_ResultPart::group())) {
+    // but check the case the whole results are allowed: whole features may be selected
+    if (myParent && myParent->isWholeResultAllowed()) {
+      FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(myRef.value());
+      if (aFeature.get()) {
+        FeaturePtr aThisFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(owner());
+        std::list<FeaturePtr> aConcealers;
+        concealedFeature(aFeature, aThisFeature, aConcealers);
+        if (aConcealers.empty())
+          return;
+        bool aChanged = false;
+        std::list<FeaturePtr>::iterator aConcealer = aConcealers.begin();
+        for(; aConcealer != aConcealers.end(); aConcealer++)
+          if (!myParent->isInList(*aConcealer, anEmptyShape)) {// avoid addition of duplicates
+            setValue(*aConcealer, anEmptyShape);
+            aChanged = true;
+          }
+        if (aConcealer == aConcealers.end()) {
+          if (!aChanged) // remove this
+            theRemove = true;
+        } else { // append new
+          for(aConcealer++; aConcealer != aConcealers.end(); aConcealer++)
+            if (!myParent->isInList(*aConcealer, anEmptyShape)) // avoid addition of duplicates
+              myParent->append(*aConcealer, anEmptyShape);
+        }
+        if (aChanged) // searching for the further modifications
+          updateInHistory(theRemove);
+      }
+    }
+    return;// only bodies and parts may be modified later in the history, skip otherwise
+  }
+
   std::shared_ptr<Model_Document> aDoc =
     std::dynamic_pointer_cast<Model_Document>(aContext->document());
   std::shared_ptr<Model_Data> aContData = std::dynamic_pointer_cast<Model_Data>(aContext->data());
@@ -1566,7 +1617,10 @@ void Model_AttributeSelection::updateInHistory(bool& theRemove)
         aShapeShapeType = (*aNewCont)->shape()->shapeType();
       }
       if (aListShapeType != GeomAPI_Shape::SHAPE && aListShapeType != aShapeShapeType) {
-        continue;
+        // exception is for whole results selected
+        if (!myParent || !myParent->isWholeResultAllowed() || aSubShape.get()) {
+          continue;
+        }
       }
 
       ResultPtr aNewContext = *aNewCont;
@@ -1601,8 +1655,7 @@ void Model_AttributeSelection::updateInHistory(bool& theRemove)
       if (myParent) {
         theRemove = true;
       } else {
-        ResultPtr anEmptyContext;
-        std::shared_ptr<GeomAPI_Shape> anEmptyShape;
+        static ResultPtr anEmptyContext;
         setValue(anEmptyContext, anEmptyShape); // nullify the selection
         return;
       }
index c3721e9940e28c9c32e7539881b27809a9b19eb3..ce9872768a5a8df63d1ca5da4127303584514414 100644 (file)
@@ -202,6 +202,10 @@ protected:
   /// Returns null label otherwise.
   TDF_Label baseDocumentLab();
 
+  /// Returns features that conceals theFeature and located in history before theStop
+  void Model_AttributeSelection::concealedFeature(
+    const FeaturePtr theFeature, const FeaturePtr theStop, std::list<FeaturePtr>& theConcealers);
+
   friend class Model_Data;
   friend class Model_AttributeSelectionList;
 };
index 56ce94f9db49b46460f7c23248770696f04cd80a..170190ef66879e1e44f82e71e4be35340ea4f2ca 100644 (file)
@@ -293,17 +293,19 @@ bool Model_AttributeSelectionList::isInList(const ObjectPtr& theContext,
                                             const std::shared_ptr<GeomAPI_Shape>& theSubShape,
                                             const bool theTemporarily)
 {
-  ResultPtr aResCont = std::dynamic_pointer_cast<ModelAPI_Result>(theContext);
   if (myIsCashed) { // the cashing is active
-    if (aResCont.get()) {
-      std::map<ResultPtr, std::list<std::shared_ptr<GeomAPI_Shape> > >::iterator aContext =
-        myCash.find(aResCont);
+    if (theContext.get()) {
+      std::map<ObjectPtr, std::list<std::shared_ptr<GeomAPI_Shape> > >::iterator aContext =
+        myCash.find(theContext);
       if (aContext != myCash.end()) {
         // iterate shapes because "isSame" method must be called for each shape
         std::list<std::shared_ptr<GeomAPI_Shape> >::iterator aShapes = aContext->second.begin();
         for(; aShapes != aContext->second.end(); aShapes++) {
           if (!theSubShape.get()) {
-            if (!aShapes->get() || (*aShapes)->isSame(aContext->first->shape()))
+            if (!aShapes->get())
+              return true;
+            ResultPtr aRes = std::dynamic_pointer_cast<ModelAPI_Result>(aContext->first);
+            if (aRes.get() && (*aShapes)->isSame(aRes->shape()))
               return true;
           } else {
             // we need to call here isSame instead of isEqual to do not check shapes orientation
@@ -316,15 +318,21 @@ bool Model_AttributeSelectionList::isInList(const ObjectPtr& theContext,
     }
   }
   // no-cash method
+  bool isFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theContext).get() != NULL;
+  ResultPtr aRes;
+  if (!isFeature)
+    aRes = std::dynamic_pointer_cast<ModelAPI_Result>(theContext);
   for(int anIndex = size() - 1; anIndex >= 0; anIndex--) {
     AttributeSelectionPtr anAttr = value(anIndex);
     if (anAttr.get()) {
-      if (anAttr->context() == theContext) { // contexts are equal, so, check that values are also
+      if (isFeature && anAttr->contextFeature() == theContext)
+        return true; // for the feature value should not be compared
+      if (!isFeature && anAttr->context() == theContext) {
+        // contexts are equal, so, check that values are also
         std::shared_ptr<GeomAPI_Shape> aValue = anAttr->value();
         if (!theSubShape.get()) {
-          if (!aValue.get() || (aResCont.get() && aValue->isSame(aResCont->shape()))) {// both null
+          if (!aValue.get() || (aRes.get() && aValue->isSame(aRes->shape())))
             return true;
-          }
         } else {
           // we need to call here isSame instead of isEqual to do not check shapes orientation
           if (isIn(aValue, theSubShape)) // shapes are equal
index ca797e623d75716d1efc9e0ffcfad5c8a5f41cb1..3ed3e2804aca7e396befd8f711a858dd1829a9d2 100644 (file)
@@ -42,7 +42,7 @@ class Model_AttributeSelectionList : public ModelAPI_AttributeSelectionList
   Handle(TDataStd_Comment) mySelectionType;
   std::shared_ptr<Model_AttributeSelection> myTmpAttr; ///< temporary attribute (the last one)
   /// the cashed shapes to optimize isInList method: from context to set of shapes in this context
-  std::map<ResultPtr, std::list<std::shared_ptr<GeomAPI_Shape> > > myCash;
+  std::map<ObjectPtr, std::list<std::shared_ptr<GeomAPI_Shape> > > myCash;
   bool myIsCashed; ///< true if cashing is performed
 public:
   /// Adds the new reference to the end of the list