Salome HOME
Task 3.2. Concealment into multi-level Compounds
authorazv <azv@opencascade.com>
Tue, 7 May 2019 08:13:23 +0000 (11:13 +0300)
committerazv <azv@opencascade.com>
Tue, 7 May 2019 08:13:23 +0000 (11:13 +0300)
Update behavior of FUSE operation to keep hierarchy of compounds.

13 files changed:
src/FeaturesAPI/FeaturesAPI_BooleanFuse.cpp
src/FeaturesAPI/FeaturesAPI_BooleanFuse.h
src/FeaturesPlugin/CMakeLists.txt
src/FeaturesPlugin/FeaturesPlugin_Boolean.cpp
src/FeaturesPlugin/FeaturesPlugin_Boolean.h
src/FeaturesPlugin/FeaturesPlugin_BooleanFuse.cpp
src/FeaturesPlugin/FeaturesPlugin_BooleanFuse.h
src/FeaturesPlugin/Test/TestBooleanFuse_MultiLevelCompound_v0_3.py
src/FeaturesPlugin/Test/TestBooleanFuse_MultiLevelCompound_v0_4.py [new file with mode: 0644]
src/FeaturesPlugin/Test/TestBooleanFuse_MultiLevelCompound_v20190506_1.py [new file with mode: 0644]
src/FeaturesPlugin/Test/TestBooleanFuse_MultiLevelCompound_v20190506_2.py [new file with mode: 0644]
src/FeaturesPlugin/Test/TestBooleanFuse_MultiLevelCompound_v20190506_3.py [new file with mode: 0644]
src/FeaturesPlugin/Test/TestBooleanFuse_MultiLevelCompound_v20190506_4.py [new file with mode: 0644]

index c6cab27359d8ea39e5430f0ef364b05f3144c494..cd7e08afda985fc848f6df262841dcdeba8e7fcf 100644 (file)
@@ -35,11 +35,13 @@ FeaturesAPI_BooleanFuse::FeaturesAPI_BooleanFuse(
 FeaturesAPI_BooleanFuse::FeaturesAPI_BooleanFuse(
   const std::shared_ptr<ModelAPI_Feature>& theFeature,
   const std::list<ModelHighAPI_Selection>& theMainObjects,
-  const bool theRemoveEdges)
+  const bool theRemoveEdges,
+  const int theVersion)
   : ModelHighAPI_Interface(theFeature)
 {
   if (initialize()) {
     fillAttribute(FeaturesPlugin_BooleanFuse::CREATION_METHOD_SIMPLE(), mycreationMethod);
+    fillAttribute(theVersion, theFeature->integer(FeaturesPlugin_Boolean::VERSION_ID()));
     fillAttribute(theMainObjects, mymainObjects);
     fillAttribute(theRemoveEdges, myremoveEdges);
 
@@ -52,11 +54,13 @@ FeaturesAPI_BooleanFuse::FeaturesAPI_BooleanFuse(
   const std::shared_ptr<ModelAPI_Feature>& theFeature,
   const std::list<ModelHighAPI_Selection>& theMainObjects,
   const std::list<ModelHighAPI_Selection>& theToolObjects,
-  const bool theRemoveEdges)
+  const bool theRemoveEdges,
+  const int theVersion)
 : ModelHighAPI_Interface(theFeature)
 {
   if(initialize()) {
     fillAttribute(FeaturesPlugin_BooleanFuse::CREATION_METHOD_ADVANCED(), mycreationMethod);
+    fillAttribute(theVersion, theFeature->integer(FeaturesPlugin_Boolean::VERSION_ID()));
     fillAttribute(theMainObjects, mymainObjects);
     fillAttribute(theToolObjects, mytoolObjects);
     fillAttribute(theRemoveEdges, myremoveEdges);
@@ -125,6 +129,8 @@ void FeaturesAPI_BooleanFuse::dump(ModelHighAPI_Dumper& theDumper) const
     aBase->selectionList(FeaturesPlugin_BooleanFuse::TOOL_LIST_ID());
   AttributeBooleanPtr aRemoveEdges =
     aBase->boolean(FeaturesPlugin_BooleanFuse::REMOVE_INTERSECTION_EDGES_ID());
+  AttributeIntegerPtr aVersion =
+    aBase->integer(FeaturesPlugin_BooleanFuse::VERSION_ID());
 
   theDumper << "(" << aDocName << ", " << anObjects;
 
@@ -132,8 +138,13 @@ void FeaturesAPI_BooleanFuse::dump(ModelHighAPI_Dumper& theDumper) const
     theDumper << ", " << aTools;
   }
 
-  if (aRemoveEdges->value()) {
-    theDumper << ", " << true;
+  bool hasVersion = aVersion && aVersion->isInitialized();
+  if (aRemoveEdges->value() || hasVersion) {
+    theDumper << ", " << aRemoveEdges->value();
+  }
+
+  if (hasVersion) {
+    theDumper << ", " << aVersion->value();
   }
 
   theDumper << ")" << std::endl;
@@ -142,23 +153,27 @@ void FeaturesAPI_BooleanFuse::dump(ModelHighAPI_Dumper& theDumper) const
 //==================================================================================================
 BooleanFusePtr addFuse(const std::shared_ptr<ModelAPI_Document>& thePart,
                        const std::list<ModelHighAPI_Selection>& theObjects,
-                       const bool theRemoveEdges)
+                       const bool theRemoveEdges,
+                       const int theVersion)
 {
   std::shared_ptr<ModelAPI_Feature> aFeature = thePart->addFeature(FeaturesAPI_BooleanFuse::ID());
   return BooleanFusePtr(new FeaturesAPI_BooleanFuse(aFeature,
                                                     theObjects,
-                                                    theRemoveEdges));
+                                                    theRemoveEdges,
+                                                    theVersion));
 }
 
 //==================================================================================================
 BooleanFusePtr addFuse(const std::shared_ptr<ModelAPI_Document>& thePart,
                    const std::list<ModelHighAPI_Selection>& theMainObjects,
                    const std::list<ModelHighAPI_Selection>& theToolObjects,
-                   const bool theRemoveEdges)
+                   const bool theRemoveEdges,
+                   const int theVersion)
 {
   std::shared_ptr<ModelAPI_Feature> aFeature = thePart->addFeature(FeaturesAPI_BooleanFuse::ID());
   return BooleanFusePtr(new FeaturesAPI_BooleanFuse(aFeature,
                                                     theMainObjects,
                                                     theToolObjects,
-                                                    theRemoveEdges));
+                                                    theRemoveEdges,
+                                                    theVersion));
 }
index db80f967743843855c763f94371436b2dbb44be0..5f44f8aa9fec4bbd9f4f15d068583d965f6b072c 100644 (file)
@@ -42,16 +42,18 @@ public:
 
   /// Constructor with values.
   FEATURESAPI_EXPORT
-    FeaturesAPI_BooleanFuse(const std::shared_ptr<ModelAPI_Feature>& theFeature,
-                            const std::list<ModelHighAPI_Selection>& theMainObjects,
-                            const bool theRemoveEdges = false);
+  FeaturesAPI_BooleanFuse(const std::shared_ptr<ModelAPI_Feature>& theFeature,
+                          const std::list<ModelHighAPI_Selection>& theMainObjects,
+                          const bool theRemoveEdges = false,
+                          const int theVersion = 0);
 
   /// Constructor with values.
   FEATURESAPI_EXPORT
   FeaturesAPI_BooleanFuse(const std::shared_ptr<ModelAPI_Feature>& theFeature,
                           const std::list<ModelHighAPI_Selection>& theMainObjects,
                           const std::list<ModelHighAPI_Selection>& theToolObjects,
-                          const bool theRemoveEdges = false);
+                          const bool theRemoveEdges = false,
+                          const int theVersion = 0);
 
   /// Destructor.
   FEATURESAPI_EXPORT
@@ -96,7 +98,8 @@ typedef std::shared_ptr<FeaturesAPI_BooleanFuse> BooleanFusePtr;
 FEATURESAPI_EXPORT
 BooleanFusePtr addFuse(const std::shared_ptr<ModelAPI_Document>& thePart,
                        const std::list<ModelHighAPI_Selection>& theObjects,
-                       const bool theRemoveEdges = false);
+                       const bool theRemoveEdges = false,
+                       const int theVersion = 0);
 
 /// \ingroup CPPHighAPI
 /// \brief Create Boolean Fuse feature.
@@ -104,6 +107,7 @@ FEATURESAPI_EXPORT
 BooleanFusePtr addFuse(const std::shared_ptr<ModelAPI_Document>& thePart,
                        const std::list<ModelHighAPI_Selection>& theMainObjects,
                        const std::list<ModelHighAPI_Selection>& theToolObjects,
-                       const bool theRemoveEdges = false);
+                       const bool theRemoveEdges = false,
+                       const int theVersion = 0);
 
 #endif // FeaturesAPI_BooleanFuse_H_
index 5555d4743ec04d5af87673ca00c5cb6b40c2bb0e..82fd74586c1a27a89a5b4d6f7f08c955a306f923 100644 (file)
@@ -465,6 +465,11 @@ ADD_UNIT_TESTS(TestExtrusion.py
                TestBooleanFuse_MultiLevelCompound_v0_1.py
                TestBooleanFuse_MultiLevelCompound_v0_2.py
                TestBooleanFuse_MultiLevelCompound_v0_3.py
+               TestBooleanFuse_MultiLevelCompound_v0_4.py
+               TestBooleanFuse_MultiLevelCompound_v20190506_1.py
+               TestBooleanFuse_MultiLevelCompound_v20190506_2.py
+               TestBooleanFuse_MultiLevelCompound_v20190506_3.py
+               TestBooleanFuse_MultiLevelCompound_v20190506_4.py
                TestBooleanSmash_MultiLevelCompound0.py
                TestBooleanSplit_MultiLevelCompound0.py
                TestPartition_MultiLevelCompound0.py
index 7f9ce37ac77b4a27d79d5d42dd71133c9edc666f..856d8d4679fdc586284e21de592f2f006e08e6eb 100644 (file)
@@ -35,6 +35,7 @@
 #include <GeomAlgoAPI_MakeShapeList.h>
 #include <GeomAlgoAPI_Partition.h>
 #include <GeomAlgoAPI_PaveFiller.h>
+#include <GeomAlgoAPI_ShapeBuilder.h>
 #include <GeomAlgoAPI_ShapeTools.h>
 #include <GeomAlgoAPI_Tools.h>
 #include <GeomAPI_Face.h>
@@ -420,7 +421,16 @@ void FeaturesPlugin_Boolean::ObjectHierarchy::AddParent(const GeomShapePtr& theS
                                                         const GeomShapePtr& theParent)
 {
   myParent[theShape] = theParent;
-  mySubshapes[theParent].push_back(theShape);
+
+  MapShapeToIndex::iterator aFound = myParentIndices.find(theParent);
+  size_t anIndex = myParentIndices.size();
+  if (aFound == myParentIndices.end()) {
+    myParentIndices[theParent] = anIndex;
+    mySubshapes.push_back(ShapeAndSubshapes(theParent, ListOfShape()));
+  } else
+    anIndex = aFound->second;
+
+  mySubshapes[anIndex].second.push_back(theShape);
 }
 
 GeomShapePtr FeaturesPlugin_Boolean::ObjectHierarchy::Parent(const GeomShapePtr& theShape,
@@ -433,7 +443,7 @@ GeomShapePtr FeaturesPlugin_Boolean::ObjectHierarchy::Parent(const GeomShapePtr&
     if (theMarkProcessed) {
       // mark the parent and all its subs as processed by Boolean algorithm
       myProcessedObjects.insert(aParent);
-      const ListOfShape& aSubs = mySubshapes[aParent];
+      const ListOfShape& aSubs = mySubshapes[myParentIndices[aParent]].second;
       for (ListOfShape::const_iterator anIt = aSubs.begin(); anIt != aSubs.end(); ++anIt)
         myProcessedObjects.insert(*anIt);
     }
@@ -473,12 +483,15 @@ void FeaturesPlugin_Boolean::ObjectHierarchy::SplitCompound(const GeomShapePtr&
   theUsed.clear();
   theNotUsed.clear();
 
-  const ListOfShape& aSubs = mySubshapes.find(theCompShape)->second;
+  MapShapeToIndex::const_iterator aFoundIndex = myParentIndices.find(theCompShape);
+  if (aFoundIndex == myParentIndices.end())
+    return; // no such shape
+
+  const ListOfShape& aSubs = mySubshapes[aFoundIndex->second].second;
   SetOfShape aSubsSet;
   aSubsSet.insert(aSubs.begin(), aSubs.end());
 
-  for (GeomAPI_ShapeExplorer anExp(theCompShape, GeomAPI_Shape::SOLID);
-       anExp.more(); anExp.next()) {
+  for (GeomAPI_ShapeIterator anExp(theCompShape); anExp.more(); anExp.next()) {
     GeomShapePtr aCurrent = anExp.current();
     if (aSubsSet.find(aCurrent) == aSubsSet.end())
       theNotUsed.push_back(aCurrent);
@@ -492,6 +505,64 @@ bool FeaturesPlugin_Boolean::ObjectHierarchy::IsEmpty() const
   return myObjects.empty();
 }
 
+void FeaturesPlugin_Boolean::ObjectHierarchy::CompoundsOfUnusedObjects(
+    ListOfShape& theDestination) const
+{
+  SetOfShape aUsedObjects;
+  aUsedObjects.insert(myObjects.begin(), myObjects.end());
+
+  for (std::vector<ShapeAndSubshapes>::const_iterator anIt = mySubshapes.begin();
+       anIt != mySubshapes.end(); ++anIt) {
+    MapShapeToParent::const_iterator aParent = myParent.find(anIt->first);
+    if ((aParent == myParent.end() || !aParent->second) &&
+         anIt->first->shapeType() ==  GeomAPI_Shape::COMPOUND) {
+      // this is a top-level compound
+      GeomShapePtr aCompound = collectUnusedSubs(anIt->first, aUsedObjects);
+      // add to destination non-empty compounds only
+      if (aCompound)
+        theDestination.push_back(aCompound);
+    }
+  }
+}
+
+GeomShapePtr FeaturesPlugin_Boolean::ObjectHierarchy::collectUnusedSubs(
+    GeomShapePtr theTopLevelCompound,
+    const SetOfShape& theUsed) const
+{
+  GeomShapePtr aResult = theTopLevelCompound->emptyCopied();
+  bool isResultEmpty = true;
+
+  for (GeomAPI_ShapeIterator aSub(theTopLevelCompound); aSub.more(); aSub.next()) {
+    GeomShapePtr aCurrent = aSub.current();
+    if (theUsed.find(aCurrent) != theUsed.end())
+      continue; // already used
+
+    MapShapeToIndex::const_iterator aFoundIndex = myParentIndices.find(aCurrent);
+    if (aCurrent->shapeType() > GeomAPI_Shape::COMPOUND ||
+        aFoundIndex == myParentIndices.end()) {
+      bool isAddShape = true;
+      // check compsolid is fully unused in the Boolean operation
+      if (aCurrent->shapeType() == GeomAPI_Shape::COMPSOLID) {
+        for (GeomAPI_ShapeIterator anIt(aCurrent); isAddShape && anIt.more(); anIt.next())
+          isAddShape = theUsed.find(anIt.current()) == theUsed.end();
+      }
+
+      if (isAddShape) { // low-level shape, add it
+        GeomAlgoAPI_ShapeBuilder::add(aResult, aCurrent);
+        isResultEmpty = false;
+      }
+    } else {
+      GeomShapePtr aCompound = collectUnusedSubs(aCurrent, theUsed);
+      if (aCompound) {
+        GeomAlgoAPI_ShapeBuilder::add(theTopLevelCompound, aCompound);
+        isResultEmpty = false;
+      }
+    }
+  }
+  return isResultEmpty ? GeomShapePtr() : aResult;
+}
+
+
 FeaturesPlugin_Boolean::ObjectHierarchy::Iterator FeaturesPlugin_Boolean::ObjectHierarchy::Begin()
 {
   return Iterator(this);
index a72c3efe9e483319ed4ff29457625a4ae83b0a47..9f6f216285ea624660bd9a67bc21555f709b2f52 100644 (file)
@@ -59,6 +59,13 @@ public:
     return MY_TOOL_LIST_ID;
   }
 
+  /// Attribute name of the version of Boolean feature
+  inline static const std::string& VERSION_ID()
+  {
+    static const std::string MY_VERSION_ID("version");
+    return MY_VERSION_ID;
+  }
+
   /// \return boolean operation type.
   FEATURESPLUGIN_EXPORT OperationType operationType();
 
@@ -81,13 +88,18 @@ protected:
   /// Auxiliary class to store hierarchy of Boolean operation objects/tools
   /// and their parent shapes (compounds or compsolids)
   class ObjectHierarchy {
-    typedef std::map<GeomShapePtr, ListOfShape, GeomAPI_Shape::Comparator>  MapShapeToSubshapes;
+    typedef std::pair<GeomShapePtr, ListOfShape> ShapeAndSubshapes;
     typedef std::map<GeomShapePtr, GeomShapePtr, GeomAPI_Shape::Comparator> MapShapeToParent;
+    typedef std::map<GeomShapePtr, size_t, GeomAPI_Shape::Comparator> MapShapeToIndex;
     typedef std::set<GeomShapePtr, GeomAPI_Shape::Comparator> SetOfShape;
 
-    ListOfShape myObjects;
-    MapShapeToParent myParent;
-    MapShapeToSubshapes mySubshapes;
+    ListOfShape myObjects; ///< list of objects/tools of Boolean operation
+    MapShapeToParent myParent; ///< refer a shape to compound/compsolid containing it
+    /// indices of compounds/compsolids to keep the order of parent shapes
+    /// corresponding to the order of objects
+    MapShapeToIndex  myParentIndices;
+    /// list of shape and its subshapes stored according to the index of parent shape
+    std::vector<ShapeAndSubshapes> mySubshapes;
 
     SetOfShape myProcessedObjects;
 
@@ -107,6 +119,10 @@ protected:
                        ListOfShape& theUsed,
                        ListOfShape& theNotUsed) const;
 
+    /// Generates the list of top-level compounds, which contain the objects of Boolean operation.
+    /// The generated list will contain only shapes unused during the Boolean operation.
+    void CompoundsOfUnusedObjects(ListOfShape& theDestination) const;
+
     /// Return \c true if there is no object in hierarchy
     bool IsEmpty() const;
 
@@ -117,6 +133,10 @@ protected:
         const GeomAPI_Shape::ShapeType theMinType = GeomAPI_Shape::COMPOUND,
         const GeomAPI_Shape::ShapeType theMaxType = GeomAPI_Shape::SHAPE) const;
 
+  private:
+    GeomShapePtr collectUnusedSubs(const GeomShapePtr theTopLevelCompound,
+                                   const SetOfShape& theUsed) const;
+
   public:
     class Iterator {
       friend class ObjectHierarchy;
index 497d529e43ad221c3941eac83a2529ac3fce4750..65e5c0f4cb6e7a95578489b57de9c6cb48a30d9f 100644 (file)
@@ -23,6 +23,7 @@
 
 #include <ModelAPI_ResultBody.h>
 #include <ModelAPI_AttributeBoolean.h>
+#include <ModelAPI_AttributeInteger.h>
 #include <ModelAPI_AttributeSelectionList.h>
 #include <ModelAPI_AttributeString.h>
 #include <ModelAPI_Session.h>
 #include <GeomAlgoAPI_Boolean.h>
 #include <GeomAlgoAPI_MakeShapeList.h>
 #include <GeomAlgoAPI_PaveFiller.h>
+#include <GeomAlgoAPI_ShapeBuilder.h>
 #include <GeomAlgoAPI_ShapeTools.h>
 #include <GeomAlgoAPI_Tools.h>
 #include <GeomAlgoAPI_UnifySameDomain.h>
+
 #include <GeomAPI_ShapeExplorer.h>
+#include <GeomAPI_ShapeIterator.h>
+
+static const int THE_FUSE_VERSION_1 = 20190506;
 
 //==================================================================================================
 FeaturesPlugin_BooleanFuse::FeaturesPlugin_BooleanFuse()
@@ -55,6 +61,17 @@ void FeaturesPlugin_BooleanFuse::initAttributes()
 
   ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), OBJECT_LIST_ID());
   ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), TOOL_LIST_ID());
+
+  AttributePtr aVerAttr = data()->addAttribute(VERSION_ID(), ModelAPI_AttributeInteger::typeId());
+  aVerAttr->setIsArgument(false);
+  ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), VERSION_ID());
+  if (!integer(VERSION_ID())->isInitialized() &&
+      !selectionList(OBJECT_LIST_ID())->isInitialized() &&
+      !selectionList(TOOL_LIST_ID())->isInitialized()) {
+    // this is a newly created feature (not read from file),
+    // so, initialize the latest version
+    integer(VERSION_ID())->setValue(THE_FUSE_VERSION_1);
+  }
 }
 
 //==================================================================================================
@@ -95,6 +112,14 @@ void FeaturesPlugin_BooleanFuse::execute()
     return;
   }
 
+  // version of FUSE feature
+  AttributeIntegerPtr aVersionAttr = integer(VERSION_ID());
+  int aFuseVersion = 0;
+  if (aVersionAttr && aVersionAttr->isInitialized())
+    aFuseVersion = aVersionAttr->value();
+
+////  isSimpleCreation = isSimpleCreation && aFuseVersion < THE_FUSE_VERSION_1;
+
   // Collecting all solids which will be fused.
   ListOfShape aSolidsToFuse;
   aSolidsToFuse.insert(aSolidsToFuse.end(), anObjects.begin(), anObjects.end());
@@ -221,6 +246,12 @@ void FeaturesPlugin_BooleanFuse::execute()
     aMakeShapeList->appendAlgo(aUnifyAlgo);
   }
 
+  if (aFuseVersion == THE_FUSE_VERSION_1) {
+    // merge hierarchies of compounds containing objects and tools
+    // and append the result of the FUSE operation
+    aShape = keepUnusedSubsOfCompound(aShape, anObjectsHierarchy, aToolsHierarchy, aMakeShapeList);
+  }
+
   int aResultIndex = 0;
 
   ResultBodyPtr aResultBody = document()->createBody(data(), aResultIndex);
@@ -243,3 +274,32 @@ void FeaturesPlugin_BooleanFuse::execute()
   // remove the rest results if there were produced in the previous pass
   removeResults(aResultIndex);
 }
+
+//==================================================================================================
+GeomShapePtr FeaturesPlugin_BooleanFuse::keepUnusedSubsOfCompound(
+    const GeomShapePtr& theFuseResult,
+    const ObjectHierarchy& theObjectsHierarchy,
+    const ObjectHierarchy& theToolsHierarchy,
+    std::shared_ptr<GeomAlgoAPI_MakeShapeList> theMakeShapeList)
+{
+  ListOfShape aCompounds;
+  theObjectsHierarchy.CompoundsOfUnusedObjects(aCompounds);
+  theToolsHierarchy.CompoundsOfUnusedObjects(aCompounds);
+
+  GeomShapePtr aResultShape = theFuseResult;
+  if (!aCompounds.empty()) {
+    aResultShape = aCompounds.front();
+    aCompounds.pop_front();
+
+    std::shared_ptr<GeomAlgoAPI_ShapeBuilder> aBuilder(new GeomAlgoAPI_ShapeBuilder);
+    for (ListOfShape::iterator anIt = aCompounds.begin(); anIt != aCompounds.end(); ++anIt) {
+      for (GeomAPI_ShapeIterator aSub(*anIt); aSub.more(); aSub.next())
+        aBuilder->add(aResultShape, aSub.current());
+    }
+
+    aBuilder->add(aResultShape, theFuseResult);
+
+    theMakeShapeList->appendAlgo(aBuilder);
+  }
+  return aResultShape;
+}
index a16c8781ae07eff63d923f11bfb36a3af5422998..f94498406a0326a669de4763ce10164e6e330e00 100644 (file)
@@ -22,6 +22,8 @@
 
 #include "FeaturesPlugin_Boolean.h"
 
+class GeomAlgoAPI_MakeShapeList;
+
 /// \class FeaturesPlugin_BooleanFuse
 /// \ingroup Plugins
 /// \brief Feature for applying of Boolean Fuse operation.
@@ -95,6 +97,16 @@ public:
 
   /// Use plugin manager for features creation.
   FeaturesPlugin_BooleanFuse();
+
+private:
+  /// Process unused sub-shapes of compounds.
+  /// Keep the compound hierarchy, but merge top-level compounds
+  /// into a single compound and add the result of the FUSE operation.
+  GeomShapePtr keepUnusedSubsOfCompound(
+      const GeomShapePtr& theFuseResult,
+      const ObjectHierarchy& theObjectsHierarchy,
+      const ObjectHierarchy& theToolsHierarchy,
+      std::shared_ptr<GeomAlgoAPI_MakeShapeList> theMakeShapeList);
 };
 
 #endif
index 4e209565d622cb93ad04719aa87b07dfbfc922ea..64de0bacc28028fc518661fe1cf6f9c9c7ce3982 100644 (file)
@@ -76,19 +76,6 @@ Edge_1 = model.addEdge(Part_1_doc, [model.selection("EDGE", "Sketch_2/SketchLine
 Extrusion_2 = model.addExtrusion(Part_1_doc, [model.selection("EDGE", "Edge_1_1")], model.selection("EDGE", "PartSet/OZ"), 13, 3)
 Compound_1 = model.addCompound(Part_1_doc, [model.selection("COMPSOLID", "Extrusion_1_1"), model.selection("FACE", "Extrusion_2_1")])
 Fuse_1 = model.addFuse(Part_1_doc, [model.selection("SOLID", "Compound_1_1_1_1")], [model.selection("SOLID", "LinearCopy_2_1_1_1"), model.selection("FACE", "Compound_1_1_2")], True)
-
-model.testHaveNamingSubshapes(Fuse_1, model, Part_1_doc)
-
 model.end()
 
-from GeomAPI import GeomAPI_Shape
-
-model.testNbResults(Fuse_1, 1)
-model.testNbSubResults(Fuse_1, [2])
-model.testNbSubShapes(Fuse_1, GeomAPI_Shape.SOLID, [2])
-model.testNbSubShapes(Fuse_1, GeomAPI_Shape.FACE, [16])
-model.testNbSubShapes(Fuse_1, GeomAPI_Shape.EDGE, [78])
-model.testNbSubShapes(Fuse_1, GeomAPI_Shape.VERTEX, [156])
-model.testResultsVolumes(Fuse_1, [1589.048622670478835])
-
-assert(model.checkPythonDump())
+assert(Fuse_1.feature().error() != "")
diff --git a/src/FeaturesPlugin/Test/TestBooleanFuse_MultiLevelCompound_v0_4.py b/src/FeaturesPlugin/Test/TestBooleanFuse_MultiLevelCompound_v0_4.py
new file mode 100644 (file)
index 0000000..d532942
--- /dev/null
@@ -0,0 +1,94 @@
+# 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
+#
+
+from SketchAPI import *
+
+from salome.shaper import model
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Cylinder_1 = model.addCylinder(Part_1_doc, model.selection("VERTEX", "PartSet/Origin"), model.selection("EDGE", "PartSet/OZ"), 5, 10)
+LinearCopy_1 = model.addMultiTranslation(Part_1_doc, [model.selection("SOLID", "Cylinder_1_1")], model.selection("EDGE", "PartSet/OY"), 15, 3)
+LinearCopy_2 = model.addMultiTranslation(Part_1_doc, [model.selection("COMPOUND", "LinearCopy_1_1")], model.selection("EDGE", "PartSet/OX"), -20, 2)
+Extrusion_1 = model.addExtrusion(Part_1_doc, [], model.selection(), 10, 0)
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchLine_1 = Sketch_1.addLine(10, -5, 0, -5)
+SketchLine_2 = Sketch_1.addLine(0, -5, 0, 0)
+SketchLine_3 = Sketch_1.addLine(0, 0, 10, 0)
+SketchLine_4 = Sketch_1.addLine(10, 0, 10, -5)
+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())
+SketchLine_5 = Sketch_1.addLine(10, -5, 20, -5)
+SketchConstraintCoincidence_5 = Sketch_1.setCoincident(SketchLine_1.startPoint(), SketchLine_5.startPoint())
+SketchLine_6 = Sketch_1.addLine(20, -5, 20, 0)
+SketchConstraintCoincidence_6 = Sketch_1.setCoincident(SketchLine_5.endPoint(), SketchLine_6.startPoint())
+SketchLine_7 = Sketch_1.addLine(20, 0, 10, 0)
+SketchConstraintCoincidence_7 = Sketch_1.setCoincident(SketchLine_6.endPoint(), SketchLine_7.startPoint())
+SketchConstraintCoincidence_8 = Sketch_1.setCoincident(SketchLine_3.endPoint(), SketchLine_7.endPoint())
+SketchConstraintHorizontal_3 = Sketch_1.setHorizontal(SketchLine_5.result())
+SketchConstraintHorizontal_4 = Sketch_1.setHorizontal(SketchLine_7.result())
+SketchConstraintVertical_3 = Sketch_1.setVertical(SketchLine_6.result())
+SketchConstraintEqual_1 = Sketch_1.setEqual(SketchLine_1.result(), SketchLine_5.result())
+SketchProjection_1 = Sketch_1.addProjection(model.selection("EDGE", "PartSet/OX"), False)
+SketchLine_8 = SketchProjection_1.createdFeature()
+SketchConstraintCoincidence_9 = Sketch_1.setCoincident(SketchLine_2.endPoint(), SketchAPI_Line(SketchLine_8).startPoint())
+SketchConstraintCoincidence_9.setName("SketchConstraintCoincidence_10")
+SketchConstraintLength_1 = Sketch_1.setLength(SketchLine_2.result(), 5)
+SketchConstraintLength_2 = Sketch_1.setLength(SketchLine_1.result(), 10)
+Extrusion_1.setNestedSketch(Sketch_1)
+Sketch_2 = model.addSketch(Part_1_doc, model.selection("FACE", "Extrusion_1_1_2/From_Face"))
+SketchLine_9 = Sketch_2.addLine(22, 2.5, 6, 2.5)
+SketchConstraintHorizontal_5 = Sketch_2.setHorizontal(SketchLine_9.result())
+SketchConstraintLength_3 = Sketch_2.setLength(SketchLine_9.result(), 16)
+SketchProjection_2 = Sketch_2.addProjection(model.selection("EDGE", "[Extrusion_1_1_1/Generated_Face&Sketch_1/SketchLine_4][Extrusion_1_1_1/From_Face]"), False)
+SketchLine_10 = SketchProjection_2.createdFeature()
+SketchPoint_1 = Sketch_2.addPoint(10, 2.5)
+SketchConstraintCoincidence_10 = Sketch_2.setCoincident(SketchPoint_1.coordinates(), SketchLine_9.result())
+SketchConstraintCoincidence_10.setName("SketchConstraintCoincidence_11")
+SketchConstraintMiddle_1 = Sketch_2.setMiddlePoint(SketchPoint_1.coordinates(), SketchLine_10.result())
+SketchConstraintDistance_1 = Sketch_2.setDistance(SketchLine_9.startPoint(), SketchLine_10.result(), 12, True)
+model.do()
+Edge_1 = model.addEdge(Part_1_doc, [model.selection("EDGE", "Sketch_2/SketchLine_9")])
+Extrusion_2 = model.addExtrusion(Part_1_doc, [model.selection("EDGE", "Edge_1_1")], model.selection("EDGE", "PartSet/OZ"), 13, 3)
+Compound_1 = model.addCompound(Part_1_doc, [model.selection("COMPSOLID", "Extrusion_1_1"), model.selection("FACE", "Extrusion_2_1")])
+Fuse_1 = model.addFuse(Part_1_doc, [model.selection("SOLID", "Compound_1_1_1_1")], [model.selection("SOLID", "LinearCopy_2_1_1_1")])
+
+model.testHaveNamingSubshapes(Fuse_1, model, Part_1_doc)
+
+model.end()
+
+from GeomAPI import GeomAPI_Shape
+
+model.testNbResults(Fuse_1, 1)
+model.testNbSubResults(Fuse_1, [2])
+model.testNbSubShapes(Fuse_1, GeomAPI_Shape.SOLID, [2])
+model.testNbSubShapes(Fuse_1, GeomAPI_Shape.FACE, [16])
+model.testNbSubShapes(Fuse_1, GeomAPI_Shape.EDGE, [60])
+model.testNbSubShapes(Fuse_1, GeomAPI_Shape.VERTEX, [120])
+model.testResultsVolumes(Fuse_1, [1589.04862264177882])
+
+assert(model.checkPythonDump())
diff --git a/src/FeaturesPlugin/Test/TestBooleanFuse_MultiLevelCompound_v20190506_1.py b/src/FeaturesPlugin/Test/TestBooleanFuse_MultiLevelCompound_v20190506_1.py
new file mode 100644 (file)
index 0000000..42b7fa9
--- /dev/null
@@ -0,0 +1,97 @@
+# 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
+#
+
+from SketchAPI import *
+
+from salome.shaper import model
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Cylinder_1 = model.addCylinder(Part_1_doc, model.selection("VERTEX", "PartSet/Origin"), model.selection("EDGE", "PartSet/OZ"), 10, 20)
+LinearCopy_1 = model.addMultiTranslation(Part_1_doc, [model.selection("SOLID", "Cylinder_1_1")], model.selection("EDGE", "PartSet/OX"), 40, 2)
+LinearCopy_2 = model.addMultiTranslation(Part_1_doc, [model.selection("COMPOUND", "LinearCopy_1_1")], model.selection("EDGE", "PartSet/OY"), 40, 2)
+LinearCopy_2.result().subResult(0).subResult(0).setColor(255, 170, 0)
+LinearCopy_2.result().subResult(0).subResult(1).setColor(255, 170, 0)
+LinearCopy_2.result().subResult(1).subResult(0).setColor(0, 0, 255)
+LinearCopy_2.result().subResult(1).subResult(1).setColor(0, 0, 255)
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("YOZ"))
+SketchLine_1 = Sketch_1.addLine(7, 0, -7, 0)
+SketchLine_2 = Sketch_1.addLine(-7, 0, -7, 5)
+SketchLine_3 = Sketch_1.addLine(-7, 5, 7, 5)
+SketchLine_4 = Sketch_1.addLine(7, 5, 7, 0)
+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("EDGE", "PartSet/OZ"), False)
+SketchLine_5 = SketchProjection_1.createdFeature()
+SketchConstraintDistance_1 = Sketch_1.setDistance(SketchLine_3.endPoint(), SketchLine_5.result(), 7, True)
+SketchConstraintCoincidence_5 = Sketch_1.setCoincident(SketchAPI_Line(SketchLine_5).startPoint(), SketchLine_1.result())
+SketchConstraintLength_1 = Sketch_1.setLength(SketchLine_1.result(), 14)
+SketchConstraintLength_2 = Sketch_1.setLength(SketchLine_2.result(), 5)
+SketchLine_6 = Sketch_1.addLine(5, 12, -5, 12)
+SketchLine_7 = Sketch_1.addLine(-5, 12, -5, 15)
+SketchLine_8 = Sketch_1.addLine(-5, 15, 5, 15)
+SketchLine_9 = Sketch_1.addLine(5, 15, 5, 12)
+SketchConstraintCoincidence_6 = Sketch_1.setCoincident(SketchLine_9.endPoint(), SketchLine_6.startPoint())
+SketchConstraintCoincidence_7 = Sketch_1.setCoincident(SketchLine_6.endPoint(), SketchLine_7.startPoint())
+SketchConstraintCoincidence_8 = Sketch_1.setCoincident(SketchLine_7.endPoint(), SketchLine_8.startPoint())
+SketchConstraintCoincidence_9 = Sketch_1.setCoincident(SketchLine_8.endPoint(), SketchLine_9.startPoint())
+SketchConstraintHorizontal_3 = Sketch_1.setHorizontal(SketchLine_6.result())
+SketchConstraintVertical_3 = Sketch_1.setVertical(SketchLine_7.result())
+SketchConstraintHorizontal_4 = Sketch_1.setHorizontal(SketchLine_8.result())
+SketchConstraintVertical_4 = Sketch_1.setVertical(SketchLine_9.result())
+SketchConstraintLength_3 = Sketch_1.setLength(SketchLine_7.result(), 3)
+SketchConstraintLength_4 = Sketch_1.setLength(SketchLine_8.result(), 10)
+SketchConstraintDistance_2 = Sketch_1.setDistance(SketchLine_8.endPoint(), SketchLine_5.result(), 5, True)
+SketchConstraintDistance_3 = Sketch_1.setDistance(SketchLine_6.startPoint(), SketchLine_3.result(), 7, True)
+model.do()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchLine_4r-SketchLine_3r-SketchLine_2r-SketchLine_1r")], model.selection(), 60, 20)
+Extrusion_2 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchLine_9r-SketchLine_8r-SketchLine_7r-SketchLine_6r")], model.selection(), 55, 15)
+LinearCopy_3 = model.addMultiTranslation(Part_1_doc, [model.selection("SOLID", "Extrusion_1_1")], model.selection("EDGE", "PartSet/OY"), 40, 2)
+AngularCopy_1 = model.addMultiRotation(Part_1_doc, [model.selection("SOLID", "Extrusion_2_1")], model.selection("EDGE", "PartSet/OZ"), 90, 2)
+Compound_1 = model.addCompound(Part_1_doc, [model.selection("COMPOUND", "LinearCopy_3_1"), model.selection("COMPOUND", "AngularCopy_1_1")])
+Compound_1.result().subResult(0).subResult(0).setColor(0, 170, 0)
+Compound_1.result().subResult(0).subResult(1).setColor(0, 170, 0)
+Compound_1.result().subResult(1).subResult(0).setColor(0, 255, 0)
+Compound_1.result().subResult(1).subResult(1).setColor(0, 255, 0)
+Fuse_1_objects_1 = [model.selection("SOLID", "LinearCopy_2_1_1_1"), model.selection("SOLID", "Compound_1_1_1_1"), model.selection("COMPOUND", "Compound_1_1_2")]
+Fuse_1 = model.addFuse(Part_1_doc, Fuse_1_objects_1, False, 20190506)
+
+model.testHaveNamingSubshapes(Fuse_1, model, Part_1_doc)
+
+model.end()
+
+from GeomAPI import GeomAPI_Shape
+
+model.testNbResults(Fuse_1, 1)
+model.testNbSubResults(Fuse_1, [4])
+model.testNbSubShapes(Fuse_1, GeomAPI_Shape.SOLID, [5])
+model.testNbSubShapes(Fuse_1, GeomAPI_Shape.FACE, [50])
+model.testNbSubShapes(Fuse_1, GeomAPI_Shape.EDGE, [208])
+model.testNbSubShapes(Fuse_1, GeomAPI_Shape.VERTEX, [416])
+model.testResultsVolumes(Fuse_1, [38109.5099691938])
+
+assert(model.checkPythonDump())
diff --git a/src/FeaturesPlugin/Test/TestBooleanFuse_MultiLevelCompound_v20190506_2.py b/src/FeaturesPlugin/Test/TestBooleanFuse_MultiLevelCompound_v20190506_2.py
new file mode 100644 (file)
index 0000000..7cb0da0
--- /dev/null
@@ -0,0 +1,95 @@
+# 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
+#
+
+from SketchAPI import *
+
+from salome.shaper import model
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Cylinder_1 = model.addCylinder(Part_1_doc, model.selection("VERTEX", "PartSet/Origin"), model.selection("EDGE", "PartSet/OZ"), 5, 10)
+LinearCopy_1 = model.addMultiTranslation(Part_1_doc, [model.selection("SOLID", "Cylinder_1_1")], model.selection("EDGE", "PartSet/OY"), 15, 3)
+LinearCopy_2 = model.addMultiTranslation(Part_1_doc, [model.selection("COMPOUND", "LinearCopy_1_1")], model.selection("EDGE", "PartSet/OX"), -20, 2)
+Extrusion_1 = model.addExtrusion(Part_1_doc, [], model.selection(), 10, 0)
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchLine_1 = Sketch_1.addLine(10, -5, 0, -5)
+SketchLine_2 = Sketch_1.addLine(0, -5, 0, 0)
+SketchLine_3 = Sketch_1.addLine(0, 0, 10, 0)
+SketchLine_4 = Sketch_1.addLine(10, 0, 10, -5)
+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())
+SketchLine_5 = Sketch_1.addLine(10, -5, 20, -5)
+SketchConstraintCoincidence_5 = Sketch_1.setCoincident(SketchLine_1.startPoint(), SketchLine_5.startPoint())
+SketchLine_6 = Sketch_1.addLine(20, -5, 20, 0)
+SketchConstraintCoincidence_6 = Sketch_1.setCoincident(SketchLine_5.endPoint(), SketchLine_6.startPoint())
+SketchLine_7 = Sketch_1.addLine(20, 0, 10, 0)
+SketchConstraintCoincidence_7 = Sketch_1.setCoincident(SketchLine_6.endPoint(), SketchLine_7.startPoint())
+SketchConstraintCoincidence_8 = Sketch_1.setCoincident(SketchLine_3.endPoint(), SketchLine_7.endPoint())
+SketchConstraintHorizontal_3 = Sketch_1.setHorizontal(SketchLine_5.result())
+SketchConstraintHorizontal_4 = Sketch_1.setHorizontal(SketchLine_7.result())
+SketchConstraintVertical_3 = Sketch_1.setVertical(SketchLine_6.result())
+SketchConstraintEqual_1 = Sketch_1.setEqual(SketchLine_1.result(), SketchLine_5.result())
+SketchProjection_1 = Sketch_1.addProjection(model.selection("EDGE", "PartSet/OX"), False)
+SketchLine_8 = SketchProjection_1.createdFeature()
+SketchConstraintCoincidence_9 = Sketch_1.setCoincident(SketchLine_2.endPoint(), SketchAPI_Line(SketchLine_8).startPoint())
+SketchConstraintCoincidence_9.setName("SketchConstraintCoincidence_10")
+SketchConstraintLength_1 = Sketch_1.setLength(SketchLine_2.result(), 5)
+SketchConstraintLength_2 = Sketch_1.setLength(SketchLine_1.result(), 10)
+Extrusion_1.setNestedSketch(Sketch_1)
+Sketch_2 = model.addSketch(Part_1_doc, model.selection("FACE", "Extrusion_1_1_2/From_Face"))
+SketchLine_9 = Sketch_2.addLine(22, 2.5, 5.999999999999998, 2.5)
+SketchConstraintHorizontal_5 = Sketch_2.setHorizontal(SketchLine_9.result())
+SketchConstraintLength_3 = Sketch_2.setLength(SketchLine_9.result(), 16)
+SketchProjection_2 = Sketch_2.addProjection(model.selection("EDGE", "[Extrusion_1_1_1/Generated_Face&Sketch_1/SketchLine_4][Extrusion_1_1_1/From_Face]"), False)
+SketchLine_10 = SketchProjection_2.createdFeature()
+SketchPoint_1 = Sketch_2.addPoint(10, 2.5)
+SketchConstraintCoincidence_10 = Sketch_2.setCoincident(SketchPoint_1.coordinates(), SketchLine_9.result())
+SketchConstraintCoincidence_10.setName("SketchConstraintCoincidence_11")
+SketchConstraintMiddle_1 = Sketch_2.setMiddlePoint(SketchPoint_1.coordinates(), SketchLine_10.result())
+SketchConstraintDistance_1 = Sketch_2.setDistance(SketchLine_9.startPoint(), SketchLine_10.result(), 12, True)
+model.do()
+Edge_1 = model.addEdge(Part_1_doc, [model.selection("EDGE", "Sketch_2/SketchLine_9")])
+Extrusion_2 = model.addExtrusion(Part_1_doc, [model.selection("EDGE", "Edge_1_1")], model.selection("EDGE", "PartSet/OZ"), 13, 3)
+Compound_1 = model.addCompound(Part_1_doc, [model.selection("COMPSOLID", "Extrusion_1_1"), model.selection("FACE", "Extrusion_2_1")])
+Fuse_1_objects_1 = [model.selection("SOLID", "Compound_1_1_1_1"), model.selection("SOLID", "LinearCopy_2_1_1_1"), model.selection("FACE", "Compound_1_1_2")]
+Fuse_1 = model.addFuse(Part_1_doc, Fuse_1_objects_1, True, 20190506)
+
+model.testHaveNamingSubshapes(Fuse_1, model, Part_1_doc)
+
+model.end()
+
+from GeomAPI import GeomAPI_Shape
+
+model.testNbResults(Fuse_1, 1)
+model.testNbSubResults(Fuse_1, [3])
+model.testNbSubShapes(Fuse_1, GeomAPI_Shape.SOLID, [6])
+model.testNbSubShapes(Fuse_1, GeomAPI_Shape.FACE, [23])
+model.testNbSubShapes(Fuse_1, GeomAPI_Shape.EDGE, [70])
+model.testNbSubShapes(Fuse_1, GeomAPI_Shape.VERTEX, [140])
+model.testResultsVolumes(Fuse_1, [5016.039439659862])
+
+assert(model.checkPythonDump())
diff --git a/src/FeaturesPlugin/Test/TestBooleanFuse_MultiLevelCompound_v20190506_3.py b/src/FeaturesPlugin/Test/TestBooleanFuse_MultiLevelCompound_v20190506_3.py
new file mode 100644 (file)
index 0000000..23e7c75
--- /dev/null
@@ -0,0 +1,81 @@
+# 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
+#
+
+from SketchAPI import *
+
+from salome.shaper import model
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Cylinder_1 = model.addCylinder(Part_1_doc, model.selection("VERTEX", "PartSet/Origin"), model.selection("EDGE", "PartSet/OZ"), 5, 10)
+LinearCopy_1 = model.addMultiTranslation(Part_1_doc, [model.selection("SOLID", "Cylinder_1_1")], model.selection("EDGE", "PartSet/OY"), 15, 3)
+LinearCopy_2 = model.addMultiTranslation(Part_1_doc, [model.selection("COMPOUND", "LinearCopy_1_1")], model.selection("EDGE", "PartSet/OX"), -20, 2)
+Extrusion_1 = model.addExtrusion(Part_1_doc, [], model.selection(), 10, 0)
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchLine_1 = Sketch_1.addLine(10, -5, 0, -5)
+SketchLine_2 = Sketch_1.addLine(0, -5, 0, 0)
+SketchLine_3 = Sketch_1.addLine(0, 0, 10, 0)
+SketchLine_4 = Sketch_1.addLine(10, 0, 10, -5)
+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())
+SketchLine_5 = Sketch_1.addLine(10, -5, 20, -5)
+SketchConstraintCoincidence_5 = Sketch_1.setCoincident(SketchLine_1.startPoint(), SketchLine_5.startPoint())
+SketchLine_6 = Sketch_1.addLine(20, -5, 20, 0)
+SketchConstraintCoincidence_6 = Sketch_1.setCoincident(SketchLine_5.endPoint(), SketchLine_6.startPoint())
+SketchLine_7 = Sketch_1.addLine(20, 0, 10, 0)
+SketchConstraintCoincidence_7 = Sketch_1.setCoincident(SketchLine_6.endPoint(), SketchLine_7.startPoint())
+SketchConstraintCoincidence_8 = Sketch_1.setCoincident(SketchLine_3.endPoint(), SketchLine_7.endPoint())
+SketchConstraintHorizontal_3 = Sketch_1.setHorizontal(SketchLine_5.result())
+SketchConstraintHorizontal_4 = Sketch_1.setHorizontal(SketchLine_7.result())
+SketchConstraintVertical_3 = Sketch_1.setVertical(SketchLine_6.result())
+SketchConstraintEqual_1 = Sketch_1.setEqual(SketchLine_1.result(), SketchLine_5.result())
+SketchProjection_1 = Sketch_1.addProjection(model.selection("EDGE", "PartSet/OX"), False)
+SketchLine_8 = SketchProjection_1.createdFeature()
+SketchConstraintCoincidence_9 = Sketch_1.setCoincident(SketchLine_2.endPoint(), SketchAPI_Line(SketchLine_8).startPoint())
+SketchConstraintCoincidence_9.setName("SketchConstraintCoincidence_10")
+SketchConstraintLength_1 = Sketch_1.setLength(SketchLine_2.result(), 5)
+SketchConstraintLength_2 = Sketch_1.setLength(SketchLine_1.result(), 10)
+Extrusion_1.setNestedSketch(Sketch_1)
+Sketch_2 = model.addSketch(Part_1_doc, model.selection("FACE", "Extrusion_1_1_2/From_Face"))
+SketchLine_9 = Sketch_2.addLine(22, 2.5, 5.999999999999998, 2.5)
+SketchConstraintHorizontal_5 = Sketch_2.setHorizontal(SketchLine_9.result())
+SketchConstraintLength_3 = Sketch_2.setLength(SketchLine_9.result(), 16)
+SketchProjection_2 = Sketch_2.addProjection(model.selection("EDGE", "[Extrusion_1_1_1/Generated_Face&Sketch_1/SketchLine_4][Extrusion_1_1_1/From_Face]"), False)
+SketchLine_10 = SketchProjection_2.createdFeature()
+SketchPoint_1 = Sketch_2.addPoint(10, 2.5)
+SketchConstraintCoincidence_10 = Sketch_2.setCoincident(SketchPoint_1.coordinates(), SketchLine_9.result())
+SketchConstraintCoincidence_10.setName("SketchConstraintCoincidence_11")
+SketchConstraintMiddle_1 = Sketch_2.setMiddlePoint(SketchPoint_1.coordinates(), SketchLine_10.result())
+SketchConstraintDistance_1 = Sketch_2.setDistance(SketchLine_9.startPoint(), SketchLine_10.result(), 12, True)
+model.do()
+Edge_1 = model.addEdge(Part_1_doc, [model.selection("EDGE", "Sketch_2/SketchLine_9")])
+Extrusion_2 = model.addExtrusion(Part_1_doc, [model.selection("EDGE", "Edge_1_1")], model.selection("EDGE", "PartSet/OZ"), 13, 3)
+Compound_1 = model.addCompound(Part_1_doc, [model.selection("COMPSOLID", "Extrusion_1_1"), model.selection("FACE", "Extrusion_2_1")])
+Fuse_1 = model.addFuse(Part_1_doc, [model.selection("SOLID", "Compound_1_1_1_1")], [model.selection("SOLID", "LinearCopy_2_1_1_1"), model.selection("FACE", "Compound_1_1_2")], True, 20190506)
+model.end()
+
+assert(Fuse_1.feature().error() != "")
diff --git a/src/FeaturesPlugin/Test/TestBooleanFuse_MultiLevelCompound_v20190506_4.py b/src/FeaturesPlugin/Test/TestBooleanFuse_MultiLevelCompound_v20190506_4.py
new file mode 100644 (file)
index 0000000..6452a7c
--- /dev/null
@@ -0,0 +1,94 @@
+# 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
+#
+
+from SketchAPI import *
+
+from salome.shaper import model
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Cylinder_1 = model.addCylinder(Part_1_doc, model.selection("VERTEX", "PartSet/Origin"), model.selection("EDGE", "PartSet/OZ"), 5, 10)
+LinearCopy_1 = model.addMultiTranslation(Part_1_doc, [model.selection("SOLID", "Cylinder_1_1")], model.selection("EDGE", "PartSet/OY"), 15, 3)
+LinearCopy_2 = model.addMultiTranslation(Part_1_doc, [model.selection("COMPOUND", "LinearCopy_1_1")], model.selection("EDGE", "PartSet/OX"), -20, 2)
+Extrusion_1 = model.addExtrusion(Part_1_doc, [], model.selection(), 10, 0)
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchLine_1 = Sketch_1.addLine(10, -5, 0, -5)
+SketchLine_2 = Sketch_1.addLine(0, -5, 0, 0)
+SketchLine_3 = Sketch_1.addLine(0, 0, 10, 0)
+SketchLine_4 = Sketch_1.addLine(10, 0, 10, -5)
+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())
+SketchLine_5 = Sketch_1.addLine(10, -5, 20, -5)
+SketchConstraintCoincidence_5 = Sketch_1.setCoincident(SketchLine_1.startPoint(), SketchLine_5.startPoint())
+SketchLine_6 = Sketch_1.addLine(20, -5, 20, 0)
+SketchConstraintCoincidence_6 = Sketch_1.setCoincident(SketchLine_5.endPoint(), SketchLine_6.startPoint())
+SketchLine_7 = Sketch_1.addLine(20, 0, 10, 0)
+SketchConstraintCoincidence_7 = Sketch_1.setCoincident(SketchLine_6.endPoint(), SketchLine_7.startPoint())
+SketchConstraintCoincidence_8 = Sketch_1.setCoincident(SketchLine_3.endPoint(), SketchLine_7.endPoint())
+SketchConstraintHorizontal_3 = Sketch_1.setHorizontal(SketchLine_5.result())
+SketchConstraintHorizontal_4 = Sketch_1.setHorizontal(SketchLine_7.result())
+SketchConstraintVertical_3 = Sketch_1.setVertical(SketchLine_6.result())
+SketchConstraintEqual_1 = Sketch_1.setEqual(SketchLine_1.result(), SketchLine_5.result())
+SketchProjection_1 = Sketch_1.addProjection(model.selection("EDGE", "PartSet/OX"), False)
+SketchLine_8 = SketchProjection_1.createdFeature()
+SketchConstraintCoincidence_9 = Sketch_1.setCoincident(SketchLine_2.endPoint(), SketchAPI_Line(SketchLine_8).startPoint())
+SketchConstraintCoincidence_9.setName("SketchConstraintCoincidence_10")
+SketchConstraintLength_1 = Sketch_1.setLength(SketchLine_2.result(), 5)
+SketchConstraintLength_2 = Sketch_1.setLength(SketchLine_1.result(), 10)
+Extrusion_1.setNestedSketch(Sketch_1)
+Sketch_2 = model.addSketch(Part_1_doc, model.selection("FACE", "Extrusion_1_1_2/From_Face"))
+SketchLine_9 = Sketch_2.addLine(22, 2.5, 5.999999999999998, 2.5)
+SketchConstraintHorizontal_5 = Sketch_2.setHorizontal(SketchLine_9.result())
+SketchConstraintLength_3 = Sketch_2.setLength(SketchLine_9.result(), 16)
+SketchProjection_2 = Sketch_2.addProjection(model.selection("EDGE", "[Extrusion_1_1_1/Generated_Face&Sketch_1/SketchLine_4][Extrusion_1_1_1/From_Face]"), False)
+SketchLine_10 = SketchProjection_2.createdFeature()
+SketchPoint_1 = Sketch_2.addPoint(10, 2.5)
+SketchConstraintCoincidence_10 = Sketch_2.setCoincident(SketchPoint_1.coordinates(), SketchLine_9.result())
+SketchConstraintCoincidence_10.setName("SketchConstraintCoincidence_11")
+SketchConstraintMiddle_1 = Sketch_2.setMiddlePoint(SketchPoint_1.coordinates(), SketchLine_10.result())
+SketchConstraintDistance_1 = Sketch_2.setDistance(SketchLine_9.startPoint(), SketchLine_10.result(), 12, True)
+model.do()
+Edge_1 = model.addEdge(Part_1_doc, [model.selection("EDGE", "Sketch_2/SketchLine_9")])
+Extrusion_2 = model.addExtrusion(Part_1_doc, [model.selection("EDGE", "Edge_1_1")], model.selection("EDGE", "PartSet/OZ"), 13, 3)
+Compound_1 = model.addCompound(Part_1_doc, [model.selection("COMPSOLID", "Extrusion_1_1"), model.selection("FACE", "Extrusion_2_1")])
+Fuse_1 = model.addFuse(Part_1_doc, [model.selection("SOLID", "Compound_1_1_1_1")], [model.selection("SOLID", "LinearCopy_2_1_1_1")], False, 20190506)
+
+model.testHaveNamingSubshapes(Fuse_1, model, Part_1_doc)
+
+model.end()
+
+from GeomAPI import GeomAPI_Shape
+
+model.testNbResults(Fuse_1, 1)
+model.testNbSubResults(Fuse_1, [4])
+model.testNbSubShapes(Fuse_1, GeomAPI_Shape.SOLID, [7])
+model.testNbSubShapes(Fuse_1, GeomAPI_Shape.FACE, [32])
+model.testNbSubShapes(Fuse_1, GeomAPI_Shape.EDGE, [94])
+model.testNbSubShapes(Fuse_1, GeomAPI_Shape.VERTEX, [188])
+model.testResultsVolumes(Fuse_1, [5516.039439629021])
+
+assert(model.checkPythonDump())